[pbs-devel] [PATCH proxmox-backup v3 2/2] ui/cli: added support for the removal of mount-units

Hannes Laimer h.laimer at proxmox.com
Thu Aug 13 12:58:53 CEST 2020


Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
 src/bin/proxmox_backup_manager/disk.rs |  29 +++-
 www/DirectoryList.js                   | 150 ++++++++++--------
 www/Makefile                           |   1 +
 www/window/SafeRemove.js               | 209 +++++++++++++++++++++++++
 4 files changed, 325 insertions(+), 64 deletions(-)
 create mode 100644 www/window/SafeRemove.js

diff --git a/src/bin/proxmox_backup_manager/disk.rs b/src/bin/proxmox_backup_manager/disk.rs
index a93a6f6b..b7eec592 100644
--- a/src/bin/proxmox_backup_manager/disk.rs
+++ b/src/bin/proxmox_backup_manager/disk.rs
@@ -319,6 +319,32 @@ async fn create_datastore_disk(
     Ok(Value::Null)
 }
 
+#[api(
+    input: {
+        properties: {
+            name: {
+                schema: DATASTORE_SCHEMA,
+            },
+        },
+    },
+)]
+/// Remove a Filesystem mounted under '/mnt/datastore/<name>'.".
+async fn delete_datastore_disk(
+    mut param: Value,
+    rpcenv: &mut dyn RpcEnvironment,
+) -> Result<Value, Error> {
+
+    param["node"] = "localhost".into();
+
+    let info = &api2::node::disks::directory::API_METHOD_DELETE_DATASTORE_DISK;
+    match info.handler {
+        ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
+        _ => unreachable!(),
+    };
+
+    Ok(Value::Null)
+}
+
 pub fn filesystem_commands() -> CommandLineInterface {
 
     let cmd_def = CliCommandMap::new()
@@ -327,7 +353,8 @@ pub fn filesystem_commands() -> CommandLineInterface {
                 CliCommand::new(&API_METHOD_CREATE_DATASTORE_DISK)
                 .arg_param(&["name"])
                 .completion_cb("disk", complete_disk_name)
-        );
+        ).insert("remove", CliCommand::new(&API_METHOD_DELETE_DATASTORE_DISK)
+                .arg_param(&["name"]));
 
     cmd_def.into()
 }
diff --git a/www/DirectoryList.js b/www/DirectoryList.js
index 00531fd0..6ec91e6a 100644
--- a/www/DirectoryList.js
+++ b/www/DirectoryList.js
@@ -8,83 +8,107 @@ Ext.define('PBS.admin.Directorylist', {
     emptyText: gettext('No Mount-Units found'),
 
     controller: {
-	xclass: 'Ext.app.ViewController',
+        xclass: 'Ext.app.ViewController',
 
-	createDirectory: function() {
-	    let me = this;
-	    Ext.create('PBS.window.CreateDirectory', {
-		listeners: {
-		    destroy: function() {
-			me.reload();
-		    },
-		},
-	    }).show();
-	},
+        createDirectory: function () {
+            console.log(this);
+            let me = this;
+            Ext.create('PBS.window.CreateDirectory', {
+                listeners: {
+                    destroy: function () {
+                        me.reload();
+                    },
+                },
+            }).show();
+        },
 
-	reload: function() {
-	    let me = this;
-	    let store = me.getView().getStore();
-	    store.load();
-	    store.sort();
-	},
+        removeDir: function () {
+            let me = this;
+            let view = me.getView();
+            let rec = view.getSelection();
+            let dialog = Ext.create('PBS.window.SafeDestroy', {
+                url: rec[0].data.path.replace(
+                    '/mnt/datastore/',
+                    '/nodes/localhost/disks/directory/'),
+                item: {type: 'Dir', id: rec[0].data.path.replace('/mnt/datastore/', '')},
+                note: 'Data and partitions on the disk will be left untouched.'
+            });
+            dialog.on('destroy', function() {
+                me.reload();
+            });
+            dialog.show();
+        },
 
-	init: function(view) {
-	    let me = this;
-	    Proxmox.Utils.monStoreErrors(view, view.getStore(), true);
-	    me.reload();
-	},
-    },
+        reload: function () {
+            let me = this;
+            let store = me.getView().getStore();
+            store.load();
+            store.sort();
+        },
 
+        init: function (view) {
+            let me = this;
+            Proxmox.Utils.monStoreErrors(view, view.getStore(), true);
+            me.reload();
+        },
+    },
 
     rootVisible: false,
     useArrows: true,
 
     tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: 'reload',
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: 'createDirectory',
-	},
+        {
+            text: gettext('Reload'),
+            iconCls: 'fa fa-refresh',
+            handler: 'reload',
+        },
+        {
+            text: gettext('Create') + ': Directory',
+            handler: 'createDirectory',
+        },
+        {
+            xtype: 'proxmoxButton',
+            text: gettext('Remove'),
+            handler: 'removeDir',
+            disabled: true,
+            iconCls: 'fa fa-trash-o'
+        }
     ],
 
     columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1,
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device',
-	},
-	{
-	    header: gettext('Filesystem'),
-	    width: 100,
-	    dataIndex: 'filesystem',
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options',
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile',
-	},
+        {
+            text: gettext('Path'),
+            dataIndex: 'path',
+            flex: 1,
+        },
+        {
+            header: gettext('Device'),
+            flex: 1,
+            dataIndex: 'device',
+        },
+        {
+            header: gettext('Filesystem'),
+            width: 100,
+            dataIndex: 'filesystem',
+        },
+        {
+            header: gettext('Options'),
+            width: 100,
+            dataIndex: 'options',
+        },
+        {
+            header: gettext('Unit File'),
+            hidden: true,
+            dataIndex: 'unitfile',
+        },
     ],
 
     store: {
-	fields: ['path', 'device', 'filesystem', 'options', 'unitfile'],
-	proxy: {
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/localhost/disks/directory',
-	},
-	sorters: 'path',
+        fields: ['path', 'device', 'filesystem', 'options', 'unitfile'],
+        proxy: {
+            type: 'proxmox',
+            url: '/api2/json/nodes/localhost/disks/directory',
+        },
+        sorters: 'path',
     },
 });
diff --git a/www/Makefile b/www/Makefile
index edce8cb3..57db54ee 100644
--- a/www/Makefile
+++ b/www/Makefile
@@ -23,6 +23,7 @@ JSSRC=							\
 	window/SyncJobEdit.js				\
 	window/ACLEdit.js				\
 	window/DataStoreEdit.js				\
+	window/SafeRemove.js				\
 	window/CreateDirectory.js			\
 	window/ZFSCreate.js				\
 	window/FileBrowser.js				\
diff --git a/www/window/SafeRemove.js b/www/window/SafeRemove.js
new file mode 100644
index 00000000..fdbefeae
--- /dev/null
+++ b/www/window/SafeRemove.js
@@ -0,0 +1,209 @@
+/* Popup a message window
+ * where the user has to manually enter the resource ID
+ * to enable the destroy button
+ * (mostly taken from PVE-Manager(git.proxmox.com/git/pve-manager.git))
+ */
+Ext.define('PBS.window.SafeDestroy', {
+    extend: 'Ext.window.Window',
+
+    title: gettext('Confirm'),
+    modal: true,
+    buttonAlign: 'center',
+    bodyPadding: 10,
+    width: 450,
+    layout: {type: 'hbox'},
+    defaultFocus: 'confirmField',
+    showProgress: false,
+
+    config: {
+        item: {
+            id: undefined,
+            type: undefined
+        },
+        url: undefined,
+        note: undefined,
+        params: {}
+    },
+
+    getParams: function () {
+        var me = this;
+        var wipeCheckbox = me.lookupReference('wipeCheckbox');
+        if (wipeCheckbox.checked) {
+            me.params.wipe = 1;
+        }
+        if (Ext.Object.isEmpty(me.params)) {
+            return '';
+        }
+        return '?' + Ext.Object.toQueryString(me.params);
+    },
+
+    controller: {
+
+        xclass: 'Ext.app.ViewController',
+
+        control: {
+            'field[name=confirm]': {
+                change: function (f, value) {
+                    var view = this.getView();
+                    var removeButton = this.lookupReference('removeButton');
+                    if (value === view.getItem().id.toString()) {
+                        removeButton.enable();
+                    } else {
+                        removeButton.disable();
+                    }
+                },
+                specialkey: function (field, event) {
+                    var removeButton = this.lookupReference('removeButton');
+                    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
+                        removeButton.fireEvent('click', removeButton, event);
+                    }
+                }
+            },
+            'button[reference=removeButton]': {
+                click: function () {
+                    var view = this.getView();
+                    Proxmox.Utils.API2Request({
+                        url: view.getUrl() + view.getParams(),
+                        method: 'DELETE',
+                        waitMsgTarget: view,
+                        failure: function (response, opts) {
+                            view.close();
+                            Ext.Msg.alert('Error', response.htmlStatus);
+                        },
+                        success: function (response, options) {
+                            var hasProgressBar = view.showProgress &&
+                            response.result.data ? true : false;
+
+                            if (hasProgressBar) {
+                                // stay around so we can trigger our close events
+                                // when background action is completed
+                                view.hide();
+
+                                var upid = response.result.data;
+                                var win = Ext.create('Proxmox.window.TaskProgress', {
+                                    upid: upid,
+                                    listeners: {
+                                        destroy: function () {
+                                            view.close();
+                                        }
+                                    }
+                                });
+                                win.show();
+                            } else {
+                                view.close();
+                            }
+                        }
+                    });
+                }
+            }
+        }
+    },
+
+    items: [
+        {
+            xtype: 'component',
+            cls: [Ext.baseCSSPrefix + 'message-box-icon',
+                Ext.baseCSSPrefix + 'message-box-warning',
+                Ext.baseCSSPrefix + 'dlg-icon']
+        },
+        {
+            xtype: 'container',
+            flex: 1,
+            layout: {
+                type: 'vbox',
+                align: 'stretch'
+            },
+            items: [
+                {
+                    xtype: 'component',
+                    reference: 'messageCmp'
+                },
+                {
+                    itemId: 'confirmField',
+                    reference: 'confirmField',
+                    xtype: 'textfield',
+                    name: 'confirm',
+                    labelWidth: 300,
+                    hideTrigger: true,
+                    allowBlank: false
+                },
+                {
+                    xtype: 'proxmoxcheckbox',
+                    name: 'wipe',
+                    reference: 'wipeCheckbox',
+                    boxLabel: gettext('Wipe'),
+                    checked: false,
+                    autoEl: {
+                        tag: 'div',
+                        'data-qtip': gettext('Wipe disk after the removal of mountpoint')
+                    }
+                },
+                {
+                    xtype: 'container',
+                    flex: 1,
+                    layout: {
+                        type: 'vbox',
+                        align: 'middle'
+                    },
+                    height: 25,
+                    items: [
+                        {
+                            xtype: 'component',
+                            reference: 'noteCmp'
+                        },
+                    ]
+                },
+            ]
+        }
+    ],
+    buttons: [
+        {
+            reference: 'removeButton',
+            text: gettext('Remove'),
+            disabled: true
+        }
+    ],
+
+    initComponent: function () {
+        var me = this;
+
+        me.callParent();
+
+        var item = me.getItem();
+
+        if (!Ext.isDefined(item.id)) {
+            throw "no ID specified";
+        }
+
+        if (!Ext.isDefined(item.type)) {
+            throw "no Disk type specified";
+        }
+
+        var messageCmp = me.lookupReference('messageCmp');
+        var noteCmp = me.lookupReference('noteCmp');
+        var msg;
+
+        if (item.type === 'Dir') {
+            msg = `Directory ${item.id} - Remove`
+        } else {
+            throw "unknown item type specified";
+        }
+
+        if(me.getNote()) {
+            noteCmp.setHtml(`<small>${me.getNote()}</small>`);
+        }
+
+        messageCmp.setHtml(msg);
+
+        if (item.type === 'Dir') {
+            let wipeCheckbox = me.lookupReference('wipeCheckbox');
+            wipeCheckbox.setDisabled(true);
+            wipeCheckbox.setHidden(true);
+        }
+
+        var confirmField = me.lookupReference('confirmField');
+        msg = gettext('Please enter the ID to confirm') +
+            ' (' + item.id + ')';
+        confirmField.setFieldLabel(msg);
+    }
+});
-- 
2.20.1






More information about the pbs-devel mailing list