public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH manager v2] ui: wizards: allow adding tags in the qemu/lxc create wizard
Date: Wed, 25 Oct 2023 13:09:38 +0200	[thread overview]
Message-ID: <20231025110938.3854872-1-d.csapak@proxmox.com> (raw)

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 <d.csapak@proxmox.com>
---
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





             reply	other threads:[~2023-10-25 11:09 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-25 11:09 Dominik Csapak [this message]
2023-11-06 16:12 ` [pve-devel] applied: " Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231025110938.3854872-1-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal