From 0d1ac958bc6f462ff7fa4833bde3398827415879 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Tue, 31 Jul 2018 10:28:06 +0200 Subject: [PATCH] ui: storage: combine RBD external and hyperconverged add dialog Combine both dialogues. This reduces storage choices from the Storage -> Add menu, and thus improves usability. We make the whole dialog also more intelligent by querying the monitors, so that we can show them for the hyper converged case keeping a similar interface for both cases. Further we can use this to decide if a hyperconverged setup is possible at all. While this information would also be available through the fact if the pool selector has entries I wanted to show them anyway and could make logic a bit easier using it. --- www/manager6/Utils.js | 11 +- www/manager6/dc/StorageView.js | 4 - www/manager6/storage/RBDEdit.js | 200 ++++++++++++++++++++++++-------- 3 files changed, 157 insertions(+), 58 deletions(-) diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js index c062b591..3ff5ef67 100644 --- a/www/manager6/Utils.js +++ b/www/manager6/Utils.js @@ -430,17 +430,12 @@ Ext.define('PVE.Utils', { utilities: { rbd: { name: 'RBD', ipanel: 'RBDInputPanel', - hideAdd: true, - faIcon: 'building' - }, - rbd_ext: { - name: 'RBD (external)', - ipanel: 'RBDInputPanel', faIcon: 'building' }, pveceph: { name: 'RBD (PVE)', - ipanel: 'PVERBDInputPanel', + ipanel: 'RBDInputPanel', + hideAdd: true, faIcon: 'building' }, zfs: { @@ -461,7 +456,7 @@ Ext.define('PVE.Utils', { utilities: { format_storage_type: function(value, md, record) { if (value === 'rbd' && record) { - value = (record.get('monhost')?'rbd_ext':'pveceph'); + value = (record.get('monhost') ? 'rbd' : 'pveceph'); } var schema = PVE.Utils.storageSchema[value]; diff --git a/www/manager6/dc/StorageView.js b/www/manager6/dc/StorageView.js index 57214b7f..cc1e3ed6 100644 --- a/www/manager6/dc/StorageView.js +++ b/www/manager6/dc/StorageView.js @@ -54,10 +54,6 @@ Ext.define('PVE.dc.StorageView', { var type = rec.data.type, sid = rec.data.storage; - if (type === 'rbd' && !rec.data.monhost) { - type = 'pveceph'; - } - me.createStorageEditWindow(type, sid); }; diff --git a/www/manager6/storage/RBDEdit.js b/www/manager6/storage/RBDEdit.js index d26a6ac3..8ae41d1f 100644 --- a/www/manager6/storage/RBDEdit.js +++ b/www/manager6/storage/RBDEdit.js @@ -1,6 +1,86 @@ +/*jslint confusion: true*/ Ext.define('PVE.storage.RBDInputPanel', { extend: 'PVE.panel.StorageBase', + viewModel: { + parent: null, + data: { + pveceph: true, + pvecephPossible: true + } + }, + + controller: { + xclass: 'Ext.app.ViewController', + control: { + '#': { + afterrender: 'queryMonitors' + }, + 'textfield[name=username]': { + disable: 'resetField' + }, + 'displayfield[name=monhost]': { + enable: 'queryMonitors' + }, + 'textfield[name=monhost]': { + disable: 'resetField', + enable: 'resetField' + } + }, + resetField: function(field) { + field.reset(); + }, + queryMonitors: function(field, newVal, oldVal) { + // we get called with two signatures, the above one for a field + // change event and the afterrender from the view, this check only + // can be true for the field change one and omit the API request if + // pveceph got unchecked - as it's not needed there. + if (field && !newVal && oldVal) { + return; + } + var view = this.getView(); + var vm = this.getViewModel(); + if (!(view.isCreate || vm.get('pveceph'))) { + return; // only query on create or if editing a pveceph store + } + + var monhostField = this.lookupReference('monhost'); + + Proxmox.Utils.API2Request({ + url: '/api2/json/nodes/localhost/ceph/mon', + method: 'GET', + scope: this, + callback: function(options, success, response) { + var data = response.result.data; + if (response.status === 200) { + if (data.length > 0) { + var monhost = Ext.Array.pluck(data, 'name').sort().join(','); + monhostField.setValue(monhost); + monhostField.resetOriginalValue(); + if (view.isCreate) { + vm.set('pvecephPossible', true); + } + } else { + vm.set('pveceph', false); + } + } else { + vm.set('pveceph', false); + vm.set('pvecephPossible', false); + } + } + }); + } + }, + + setValues: function(values) { + if (values.monhost) { + this.viewModel.set('pveceph', false); + this.lookupReference('pvecephRef').setValue(false); + this.lookupReference('pvecephRef').resetOriginalValue(); + } + this.callParent([values]); + }, + initComponent : function() { var me = this; @@ -9,48 +89,68 @@ Ext.define('PVE.storage.RBDInputPanel', { } me.type = 'rbd'; - me.column1 = []; + var getBinds = function (activeIfPVECeph, hide) { + var bind = { + disabled: activeIfPVECeph ? '{!pveceph}' : '{pveceph}' + }; - if (me.pveceph) { - me.column1.push( - { - xtype: me.isCreate ? 'pveCephPoolSelector' : 'displayfield', - nodename: me.nodename, - name: 'pool', - fieldLabel: gettext('Pool'), - allowBlank: false - } - ); - } else { - me.column1.push( - { - xtype: me.isCreate ? 'textfield' : 'displayfield', - name: 'pool', - value: 'rbd', - fieldLabel: gettext('Pool'), - allowBlank: false - }, - { - xtype: me.isCreate ? 'textfield' : 'displayfield', - name: 'monhost', - vtype: 'HostList', - value: '', - fieldLabel: 'Monitor(s)', - allowBlank: false + // displayfield has no submitValue and bind mixin cannot handle that + if (me.isCreate) { + bind.submitValue = activeIfPVECeph ? '{pveceph}' : '{!pveceph}'; + } + if (hide) { + bind.hidden = activeIfPVECeph ? '{!pveceph}' : '{pveceph}'; + } + + return bind; + }; + + me.column1 = [ + { + xtype: me.isCreate ? 'pveCephPoolSelector' : 'displayfield', + nodename: me.nodename, + name: 'pool', + bind: getBinds(true, true), + fieldLabel: gettext('Pool'), + allowBlank: false + }, + { + xtype: me.isCreate ? 'textfield' : 'displayfield', + name: 'pool', + value: 'rbd', + bind: getBinds(false, true), + fieldLabel: gettext('Pool'), + allowBlank: false + }, + { + xtype: 'textfield', + name: 'monhost', + vtype: 'HostList', + bind: getBinds(false, true), + value: '', + fieldLabel: 'Monitor(s)', + allowBlank: false + }, + { + xtype: 'displayfield', + reference: 'monhost', + bind: { + disabled: '{!pveceph}', + hidden: '{!pveceph}' }, - { - xtype: me.isCreate ? 'textfield' : 'displayfield', - name: 'username', - value: me.isCreate ? 'admin': '', - fieldLabel: gettext('User name'), - allowBlank: true - } - ); - } + value: '', + fieldLabel: 'Monitor(s)' + }, + { + xtype: me.isCreate ? 'textfield' : 'displayfield', + name: 'username', + bind: me.isCreate ? getBinds(false) : {}, + value: 'admin', + fieldLabel: gettext('User name'), + allowBlank: true + } + ]; - // here value is an array, - // while before it was a string - /*jslint confusion: true*/ me.column2 = [ { xtype: 'pveContentTypeSelector', @@ -68,14 +168,22 @@ Ext.define('PVE.storage.RBDInputPanel', { fieldLabel: 'KRBD' } ]; - /*jslint confusion: false*/ + + me.columnB = [{ + xtype: 'proxmoxcheckbox', + name: 'pveceph', + reference: 'pvecephRef', + bind : { + disabled: '{!pvecephPossible}', + value: '{pveceph}' + }, + checked: true, + uncheckedValue: 0, + submitValue: false, + hidden: !me.isCreate, + boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool') + }]; me.callParent(); } }); - -Ext.define('PVE.storage.PVERBDInputPanel', { - extend: 'PVE.storage.RBDInputPanel', - - pveceph: 1 -}); -- 2.39.2