From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 04F759D0F6 for ; Wed, 25 Oct 2023 13:09:41 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id DA8FC133A7 for ; Wed, 25 Oct 2023 13:09:40 +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) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Wed, 25 Oct 2023 13:09:39 +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 97EBE45212 for ; Wed, 25 Oct 2023 13:09:39 +0200 (CEST) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Wed, 25 Oct 2023 13:09:38 +0200 Message-Id: <20231025110938.3854872-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.012 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy 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 v2] ui: wizards: allow adding tags in the qemu/lxc create wizard X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 25 Oct 2023 11:09:41 -0000 in the general tab in the advanced section. For that to work, we introduce a new option for the TagEditContainer named 'editOnly', which controls now the cancel/finish buttons, automatically enter edit mode and disable enter/escape keypresses. We also prevent now the loading of tags while in edit mode, so the tags don't change while editing (this can be jarring and unexpected). Then we wrap that all in a FieldSet that implements the Field mixin, so we can easily use that in the wizard. There we set a maxHeight so that the field can grow so that it still fits in the wizard. To properly align the input with the '+' button, we have to add a custom css class there. (In the hbox we could set the alignment, but this is not possible in the 'column' layout) Signed-off-by: Dominik Csapak --- changes from v1: * rebase on master * drop unnecessary/applied patches * wrap the tagedit in a fieldset to better emphasize that its an (unconventional) field, and move the submit logic there, keeping the wizard a bit cleaner www/css/ext6-pve.css | 5 +++ www/manager6/Makefile | 1 + www/manager6/form/TagEdit.js | 35 +++++++++++++++-- www/manager6/form/TagFieldSet.js | 64 +++++++++++++++++++++++++++++++ www/manager6/lxc/CreateWizard.js | 7 ++++ www/manager6/qemu/CreateWizard.js | 9 +++++ 6 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 www/manager6/form/TagFieldSet.js diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css index 85cf4039..105adc45 100644 --- a/www/css/ext6-pve.css +++ b/www/css/ext6-pve.css @@ -721,3 +721,8 @@ table.osds td:first-of-type { .pmx-opacity-75 { opacity: 0.75; } + +/* tag edit fields must be aligned manually in the fieldset */ +.proxmox-tag-fieldset.proxmox-tags-full .x-component.x-column { + margin: 2px; +} diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 17e0ad05..fa110035 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -87,6 +87,7 @@ JSSRC= \ form/Tag.js \ form/TagEdit.js \ form/MultiFileButton.js \ + form/TagFieldSet.js \ grid/BackupView.js \ grid/FirewallAliases.js \ grid/FirewallOptions.js \ diff --git a/www/manager6/form/TagEdit.js b/www/manager6/form/TagEdit.js index 094f4462..7d5b19ec 100644 --- a/www/manager6/form/TagEdit.js +++ b/www/manager6/form/TagEdit.js @@ -9,6 +9,7 @@ Ext.define('PVE.panel.TagEditContainer', { // set to false to hide the 'no tags' field and the edit button canEdit: true, + editOnly: false, controller: { xclass: 'Ext.app.ViewController', @@ -216,6 +217,9 @@ Ext.define('PVE.panel.TagEditContainer', { me.tagsChanged(); }, keypress: function(key) { + if (vm.get('hideFinishButtons')) { + return; + } if (key === 'Enter') { me.editClick(); } else if (key === 'Escape') { @@ -253,20 +257,40 @@ Ext.define('PVE.panel.TagEditContainer', { me.loadTags(view.tags); } me.getViewModel().set('canEdit', view.canEdit); + me.getViewModel().set('editOnly', view.editOnly); me.mon(Ext.GlobalEvents, 'loadedUiOptions', () => { + let vm = me.getViewModel(); view.toggleCls('hide-handles', PVE.UIOptions.shouldSortTags()); - me.loadTags(me.oldTags, true); // refresh tag colors and order + me.loadTags(me.oldTags, !vm.get('editMode')); // refresh tag colors and order }); + + if (view.editOnly) { + me.toggleEdit(); + } }, }, + getTags: function() { + let me =this; + let controller = me.getController(); + let tags = []; + controller.forEachTag((cmp) => { + if (cmp.tag.length) { + tags.push(cmp.tag); + } + }); + + return tags; + }, + viewModel: { data: { tagCount: 0, editMode: false, canEdit: true, isDirty: false, + editOnly: true, }, formulas: { @@ -276,6 +300,9 @@ Ext.define('PVE.panel.TagEditContainer', { hideEditBtn: function(get) { return get('editMode') || !get('canEdit'); }, + hideFinishButtons: function(get) { + return !get('editMode') || get('editOnly'); + }, }, }, @@ -311,7 +338,7 @@ Ext.define('PVE.panel.TagEditContainer', { xtype: 'tbseparator', ui: 'horizontal', bind: { - hidden: '{!editMode}', + hidden: '{hideFinishButtons}', }, hidden: true, }, @@ -320,7 +347,7 @@ Ext.define('PVE.panel.TagEditContainer', { iconCls: 'fa fa-times', tooltip: gettext('Cancel Edit'), bind: { - hidden: '{!editMode}', + hidden: '{hideFinishButtons}', }, hidden: true, margin: '0 5 0 0', @@ -332,7 +359,7 @@ Ext.define('PVE.panel.TagEditContainer', { iconCls: 'fa fa-check', tooltip: gettext('Finish Edit'), bind: { - hidden: '{!editMode}', + hidden: '{hideFinishButtons}', disabled: '{!isDirty}', }, hidden: true, diff --git a/www/manager6/form/TagFieldSet.js b/www/manager6/form/TagFieldSet.js new file mode 100644 index 00000000..132b215c --- /dev/null +++ b/www/manager6/form/TagFieldSet.js @@ -0,0 +1,64 @@ +Ext.define('PVE.form.TagFieldSet', { + extend: 'Ext.form.FieldSet', + alias: 'widget.pveTagFieldSet', + mixins: ['Ext.form.field.Field'], + + title: gettext('Tags'), + padding: '0 5 5 5', + + getValue: function() { + let me = this; + let tags = me.down('pveTagEditContainer').getTags().filter(t => t !== ''); + return tags.join(';'); + }, + + setValue: function(value) { + let me = this; + value ??= []; + if (!Ext.isArray(value)) { + value = value.split(/[;, ]/).filter(t => t !== ''); + } + me.down('pveTagEditContainer').loadTags(value.join(';')); + }, + + getErrors: function(value) { + value ??= []; + if (!Ext.isArray(value)) { + value = value.split(/[;, ]/).filter(t => t !== ''); + } + if (value.some(t => !t.match(PVE.Utils.tagCharRegex))) { + return [gettext("Tags contain invalid characters.")]; + } + return []; + }, + + getSubmitData: function() { + let me = this; + let value = me.getValue(); + if (me.disabled || !me.submitValue || value === '') { + return null; + } + let data = {}; + data[me.getName()] = value; + return data; + }, + + layout: 'fit', + + items: [ + { + xtype: 'pveTagEditContainer', + userCls: 'proxmox-tags-full proxmox-tag-fieldset', + editOnly: true, + allowBlank: true, + layout: 'column', + scrollable: true, + }, + ], + + initComponent: function() { + let me = this; + me.callParent(); + me.initField(); + }, +}); diff --git a/www/manager6/lxc/CreateWizard.js b/www/manager6/lxc/CreateWizard.js index e3635297..b57b3050 100644 --- a/www/manager6/lxc/CreateWizard.js +++ b/www/manager6/lxc/CreateWizard.js @@ -178,6 +178,13 @@ Ext.define('PVE.lxc.CreateWizard', { }, }, ], + advancedColumnB: [ + { + xtype: 'pveTagFieldSet', + name: 'tags', + maxHeight: 150, + }, + ], }, { xtype: 'inputpanel', diff --git a/www/manager6/qemu/CreateWizard.js b/www/manager6/qemu/CreateWizard.js index a65067ea..74b1feb6 100644 --- a/www/manager6/qemu/CreateWizard.js +++ b/www/manager6/qemu/CreateWizard.js @@ -108,6 +108,15 @@ Ext.define('PVE.qemu.CreateWizard', { fieldLabel: gettext('Shutdown timeout'), }, ], + + advancedColumnB: [ + { + xtype: 'pveTagFieldSet', + name: 'tags', + maxHeight: 150, + }, + ], + onGetValues: function(values) { ['name', 'pool', 'onboot', 'agent'].forEach(function(field) { if (!values[field]) { -- 2.30.2