From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <f.ebner@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 636BD77ECE
 for <pve-devel@lists.proxmox.com>; Mon, 25 Oct 2021 15:48:42 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 6632023893
 for <pve-devel@lists.proxmox.com>; Mon, 25 Oct 2021 15:48:11 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [94.136.29.106])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS id F3B232364F
 for <pve-devel@lists.proxmox.com>; Mon, 25 Oct 2021 15:48:00 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id C8A9045F73
 for <pve-devel@lists.proxmox.com>; Mon, 25 Oct 2021 15:48:00 +0200 (CEST)
From: Fabian Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Date: Mon, 25 Oct 2021 15:47:53 +0200
Message-Id: <20211025134755.169491-11-f.ebner@proxmox.com>
X-Mailer: git-send-email 2.30.2
In-Reply-To: <20211025134755.169491-1-f.ebner@proxmox.com>
References: <20211025134755.169491-1-f.ebner@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.260 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
Subject: [pve-devel] [PATCH manager 4/6] ui: node: add destroy menu for
 directory, lvm, lvmthin, zfs
X-BeenThere: pve-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
List-Post: <mailto:pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Mon, 25 Oct 2021 13:48:42 -0000

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

Dependency bump for pve-storage needed.

 www/manager6/node/Directory.js | 82 ++++++++++++++++++++++++++++++
 www/manager6/node/LVM.js       | 83 ++++++++++++++++++++++++++++++
 www/manager6/node/LVMThin.js   | 93 ++++++++++++++++++++++++++++++++++
 www/manager6/node/ZFS.js       | 81 ++++++++++++++++++++++++++++-
 4 files changed, 337 insertions(+), 2 deletions(-)

diff --git a/www/manager6/node/Directory.js b/www/manager6/node/Directory.js
index 67f56870..c3dba2ef 100644
--- a/www/manager6/node/Directory.js
+++ b/www/manager6/node/Directory.js
@@ -63,6 +63,43 @@ Ext.define('PVE.node.Directorylist', {
     extend: 'Ext.grid.Panel',
     xtype: 'pveDirectoryList',
 
+    viewModel: {
+	data: {
+	    path: '',
+	},
+	formulas: {
+	    dirName: (get) => get('path')?.replace('/mnt/pve/', '') || undefined,
+	},
+    },
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	destroyDirectory: function() {
+	    let me = this;
+	    let vm = me.getViewModel();
+	    let view = me.getView();
+
+	    const dirName = vm.get('dirName');
+
+	    if (!view.nodename) {
+		throw "no node name specified";
+	    }
+
+	    if (!dirName) {
+		throw "no directory name specified";
+	    }
+
+	    Ext.create('Proxmox.window.SafeDestroy', {
+		url: `/nodes/${view.nodename}/disks/directory/${dirName}`,
+		item: { id: dirName },
+		showProgress: true,
+		taskName: 'dirremove',
+		taskDone: () => { view.reload(); },
+	    }).show();
+	},
+    },
+
     stateful: true,
     stateId: 'grid-node-directory',
     columns: [
@@ -117,6 +154,45 @@ Ext.define('PVE.node.Directorylist', {
 		});
 	    },
 	},
+	'->',
+	{
+	    xtype: 'tbtext',
+	    data: {
+		dirName: undefined,
+	    },
+	    bind: {
+		data: {
+		    dirName: "{dirName}",
+		},
+	    },
+	    tpl: [
+		'<tpl if="dirName">',
+		gettext('Directory') + ' {dirName}:',
+		'<tpl else>',
+		Ext.String.format(gettext('No {0} selected'), gettext('directory')),
+		'</tpl>',
+	    ],
+	},
+	{
+	    text: gettext('More'),
+	    iconCls: 'fa fa-bars',
+	    disabled: true,
+	    bind: {
+		disabled: '{!dirName}',
+	    },
+	    menu: [
+		{
+		    text: gettext('Destroy'),
+		    itemId: 'remove',
+		    iconCls: 'fa fa-fw fa-trash-o',
+		    handler: 'destroyDirectory',
+		    disabled: true,
+		    bind: {
+			disabled: '{!dirName}',
+		    },
+		},
+	    ],
+	},
     ],
 
     reload: function() {
@@ -129,6 +205,12 @@ Ext.define('PVE.node.Directorylist', {
 	activate: function() {
 	    this.reload();
 	},
+	selectionchange: function(model, selected) {
+	    let me = this;
+	    let vm = me.getViewModel();
+
+	    vm.set('path', selected[0]?.data.path || '');
+	},
     },
 
     initComponent: function() {
diff --git a/www/manager6/node/LVM.js b/www/manager6/node/LVM.js
index 4b5225d8..70ddf451 100644
--- a/www/manager6/node/LVM.js
+++ b/www/manager6/node/LVM.js
@@ -52,6 +52,40 @@ Ext.define('PVE.node.LVMList', {
     extend: 'Ext.tree.Panel',
     xtype: 'pveLVMList',
 
+    viewModel: {
+	data: {
+	    volumeGroup: '',
+	},
+    },
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	destroyVolumeGroup: function() {
+	    let me = this;
+	    let vm = me.getViewModel();
+	    let view = me.getView();
+
+	    const volumeGroup = vm.get('volumeGroup');
+
+	    if (!view.nodename) {
+		throw "no node name specified";
+	    }
+
+	    if (!volumeGroup) {
+		throw "no volume group specified";
+	    }
+
+	    Ext.create('Proxmox.window.SafeDestroy', {
+		url: `/nodes/${view.nodename}/disks/lvm/${volumeGroup}`,
+		item: { id: volumeGroup },
+		showProgress: true,
+		taskName: 'lvmremove',
+		taskDone: () => { view.reload(); },
+	    }).show();
+	},
+    },
+
     emptyText: gettext('No Volume Groups found'),
 
     stateful: true,
@@ -120,6 +154,45 @@ Ext.define('PVE.node.LVMList', {
 		});
 	    },
 	},
+	'->',
+	{
+	    xtype: 'tbtext',
+	    data: {
+		volumeGroup: undefined,
+	    },
+	    bind: {
+		data: {
+		    volumeGroup: "{volumeGroup}",
+		},
+	    },
+	    tpl: [
+		'<tpl if="volumeGroup">',
+		'Volume group {volumeGroup}:',
+		'<tpl else>',
+		Ext.String.format(gettext('No {0} selected'), 'volume group'),
+		'</tpl>',
+	    ],
+	},
+	{
+	    text: gettext('More'),
+	    iconCls: 'fa fa-bars',
+	    disabled: true,
+	    bind: {
+		disabled: '{!volumeGroup}',
+	    },
+	    menu: [
+		{
+		    text: gettext('Destroy'),
+		    itemId: 'remove',
+		    iconCls: 'fa fa-fw fa-trash-o',
+		    handler: 'destroyVolumeGroup',
+		    disabled: true,
+		    bind: {
+			disabled: '{!volumeGroup}',
+		    },
+		},
+	    ],
+	},
     ],
 
     reload: function() {
@@ -142,6 +215,16 @@ Ext.define('PVE.node.LVMList', {
 	activate: function() {
 	    this.reload();
 	},
+	selectionchange: function(model, selected) {
+	    let me = this;
+	    let vm = me.getViewModel();
+
+	    if (selected.length < 1 || selected[0].data.parentId !== 'root') {
+		vm.set('volumeGroup', '');
+	    } else {
+		vm.set('volumeGroup', selected[0].data.name);
+	    }
+	},
     },
 
     selModel: 'treemodel',
diff --git a/www/manager6/node/LVMThin.js b/www/manager6/node/LVMThin.js
index 4a0b21ba..ca32bb3b 100644
--- a/www/manager6/node/LVMThin.js
+++ b/www/manager6/node/LVMThin.js
@@ -50,6 +50,47 @@ Ext.define('PVE.node.LVMThinList', {
     extend: 'Ext.grid.Panel',
     xtype: 'pveLVMThinList',
 
+    viewModel: {
+	data: {
+	    thinPool: '',
+	    volumeGroup: '',
+	},
+    },
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	destroyThinPool: function() {
+	    let me = this;
+	    let vm = me.getViewModel();
+	    let view = me.getView();
+
+	    const thinPool = vm.get('thinPool');
+	    const volumeGroup = vm.get('volumeGroup');
+
+	    if (!view.nodename) {
+		throw "no node name specified";
+	    }
+
+	    if (!thinPool) {
+		throw "no thin pool specified";
+	    }
+
+	    if (!volumeGroup) {
+		throw "no volume group specified";
+	    }
+
+	    Ext.create('Proxmox.window.SafeDestroy', {
+		url: `/nodes/${view.nodename}/disks/lvmthin/${thinPool}`,
+		params: { 'volume-group': volumeGroup },
+		item: { id: `${volumeGroup}/${thinPool}` },
+		showProgress: true,
+		taskName: 'lvmthinremove',
+		taskDone: () => { view.reload(); },
+	    }).show();
+	},
+    },
+
     emptyText: gettext('No thinpools found'),
 
     stateful: true,
@@ -142,6 +183,51 @@ Ext.define('PVE.node.LVMThinList', {
 		});
 	    },
 	},
+	'->',
+	{
+	    xtype: 'tbtext',
+	    data: {
+		thinPool: undefined,
+		volumeGroup: undefined,
+	    },
+	    bind: {
+		data: {
+		    thinPool: "{thinPool}",
+		    volumeGroup: "{volumeGroup}",
+		},
+	    },
+	    tpl: [
+		'<tpl if="thinPool">',
+		'<tpl if="volumeGroup">',
+		'Thinpool {volumeGroup}/{thinPool}:',
+		'<tpl else>', // volumeGroup
+		'Missing volume group (node running old version?)',
+		'</tpl>',
+		'<tpl else>', // thinPool
+		Ext.String.format(gettext('No {0} selected'), 'thinpool'),
+		'</tpl>',
+	    ],
+	},
+	{
+	    text: gettext('More'),
+	    iconCls: 'fa fa-bars',
+	    disabled: true,
+	    bind: {
+		disabled: '{!volumeGroup || !thinPool}',
+	    },
+	    menu: [
+		{
+		    text: gettext('Destroy'),
+		    itemId: 'remove',
+		    iconCls: 'fa fa-fw fa-trash-o',
+		    handler: 'destroyThinPool',
+		    disabled: true,
+		    bind: {
+			disabled: '{!volumeGroup || !thinPool}',
+		    },
+		},
+	    ],
+	},
     ],
 
     reload: function() {
@@ -154,6 +240,13 @@ Ext.define('PVE.node.LVMThinList', {
 	activate: function() {
 	    this.reload();
 	},
+	selectionchange: function(model, selected) {
+	    let me = this;
+	    let vm = me.getViewModel();
+
+	    vm.set('volumeGroup', selected[0]?.data.vg || '');
+	    vm.set('thinPool', selected[0]?.data.lv || '');
+	},
     },
 
     initComponent: function() {
diff --git a/www/manager6/node/ZFS.js b/www/manager6/node/ZFS.js
index 8ea364bf..c5c5aac8 100644
--- a/www/manager6/node/ZFS.js
+++ b/www/manager6/node/ZFS.js
@@ -297,6 +297,40 @@ Ext.define('PVE.node.ZFSList', {
     extend: 'Ext.grid.Panel',
     xtype: 'pveZFSList',
 
+    viewModel: {
+	data: {
+	    pool: '',
+	},
+    },
+
+    controller: {
+	xclass: 'Ext.app.ViewController',
+
+	destroyPool: function() {
+	    let me = this;
+	    let vm = me.getViewModel();
+	    let view = me.getView();
+
+	    const pool = vm.get('pool');
+
+	    if (!view.nodename) {
+		throw "no node name specified";
+	    }
+
+	    if (!pool) {
+		throw "no pool specified";
+	    }
+
+	    Ext.create('Proxmox.window.SafeDestroy', {
+		url: `/nodes/${view.nodename}/disks/zfs/${pool}`,
+		item: { id: pool },
+		showProgress: true,
+		taskName: 'zfsremove',
+		taskDone: () => { view.reload(); },
+	    }).show();
+	},
+    },
+
     stateful: true,
     stateId: 'grid-node-zfs',
     columns: [
@@ -378,6 +412,45 @@ Ext.define('PVE.node.ZFSList', {
 		}
 	    },
 	},
+	'->',
+	{
+	    xtype: 'tbtext',
+	    data: {
+		pool: undefined,
+	    },
+	    bind: {
+		data: {
+		    pool: "{pool}",
+		},
+	    },
+	    tpl: [
+		'<tpl if="pool">',
+		'Pool {pool}:',
+		'<tpl else>',
+		Ext.String.format(gettext('No {0} selected'), 'pool'),
+		'</tpl>',
+	    ],
+	},
+	{
+	    text: gettext('More'),
+	    iconCls: 'fa fa-bars',
+	    disabled: true,
+	    bind: {
+		disabled: '{!pool}',
+	    },
+	    menu: [
+		{
+		    text: gettext('Destroy'),
+		    itemId: 'remove',
+		    iconCls: 'fa fa-fw fa-trash-o',
+		    handler: 'destroyPool',
+		    disabled: true,
+		    bind: {
+			disabled: '{!pool}',
+		    },
+		},
+	    ],
+	},
     ],
 
     show_detail: function(zpool) {
@@ -445,8 +518,12 @@ Ext.define('PVE.node.ZFSList', {
 	activate: function() {
 	    this.reload();
 	},
-	selectionchange: function() {
-	    this.down('#detailbtn').setDisabled(this.getSelection().length === 0);
+	selectionchange: function(model, selected) {
+	    let me = this;
+	    let vm = me.getViewModel();
+
+	    me.down('#detailbtn').setDisabled(selected.length === 0);
+	    vm.set('pool', selected[0]?.data.name || '');
 	},
 	itemdblclick: function(grid, record) {
 	    this.show_detail(record.get('name'));
-- 
2.30.2