public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH manager 0/5] tags ui follow up patches
@ 2022-11-17 14:56 Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 1/5] ui: rework inline tag editing Dominik Csapak
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

overall ui improvements of the tags ui, see the individual patches
for details

intended as follow up to my v11 tags ui series

Dominik Csapak (5):
  ui: rework inline tag editing
  ui: tags: make sorting more natural
  ui: tags: hide already set tags in dropdown
  ui: change style of ListField
  ui: tags: add preview to tag shape option

 www/css/ext6-pve.css                  |  28 ++---
 www/manager6/Utils.js                 |   8 +-
 www/manager6/dc/OptionView.js         |  37 ++++++-
 www/manager6/dc/RegisteredTagsEdit.js |   6 +-
 www/manager6/dc/UserTagAccessEdit.js  |   6 +-
 www/manager6/form/ListField.js        |  86 +++++++++------
 www/manager6/form/Tag.js              | 118 ++++++++++-----------
 www/manager6/form/TagEdit.js          | 144 ++++++++++++++------------
 8 files changed, 240 insertions(+), 193 deletions(-)

-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH manager 1/5] ui: rework inline tag editing
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
@ 2022-11-17 14:56 ` Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 2/5] ui: tags: make sorting more natural Dominik Csapak
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

things that changed:
* removed 'add Tag' inline button with proper button that adds
  empty tag
* don't require to confirm each tag, simply update the color "live"
* set a minimum width for the editing box, so that it's easier to click
* replace cancel/finish icons with proper buttons
* fix tagCharRegex for multichar text (necessary for paste)

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/css/ext6-pve.css         |  28 +++-----
 www/manager6/Utils.js        |   2 +-
 www/manager6/form/Tag.js     | 116 +++++++++++++++-----------------
 www/manager6/form/TagEdit.js | 124 ++++++++++++++++-------------------
 4 files changed, 120 insertions(+), 150 deletions(-)

diff --git a/www/css/ext6-pve.css b/www/css/ext6-pve.css
index b8c713c48..a9ead5d3b 100644
--- a/www/css/ext6-pve.css
+++ b/www/css/ext6-pve.css
@@ -657,10 +657,11 @@ table.osds td:first-of-type {
     padding-bottom: 0px;
 }
 
-.pve-edit-tag > i,
-.pve-add-tag > i {
+.pve-edit-tag > i {
     cursor: pointer;
     font-size: 14px;
+    line-height: 15px;
+    height: 15px;
 }
 
 .pve-edit-tag > i.handle {
@@ -673,8 +674,7 @@ table.osds td:first-of-type {
     padding-right: 0px;
 }
 
-.pve-edit-tag > i.action,
-.pve-add-tag > i.action {
+.pve-edit-tag > i.action {
     padding-left: 5px;
 }
 
@@ -682,26 +682,18 @@ table.osds td:first-of-type {
     display: none;
 }
 
-.pve-edit-tag.editable span,
-.pve-edit-tag.inEdit span,
-.pve-add-tag.editable span,
-.pve-add-tag.inEdit span {
+.pve-edit-tag.editable span {
     background-color: #ffffff;
     border: 1px solid #a8a8a8;
     color: #000;
     padding-left: 2px;
     padding-right: 2px;
     min-width: 2em;
-}
-
-.pve-edit-tag.inEdit span,
-.pve-add-tag.inEdit span {
-    border: 1px solid #000;
-}
-
-.pve-add-tag {
-    background-color: #d5d5d5 ! important;
-    color: #000000 ! important;
+    display: inline-block;
+    line-height: 15px;
+    height: 15px;
+    vertical-align: top;
+    box-sizing: content-box;
 }
 
 .pve-tag-inline-button {
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 8484372f2..e4b6207c6 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1955,7 +1955,7 @@ Ext.define('PVE.Utils', {
 	return !(PVE.UIOptions?.['tag-style']?.ordering === 'config');
     },
 
-    tagCharRegex: /^[a-z0-9+_.-]$/i,
+    tagCharRegex: /^[a-z0-9+_.-]+$/i,
 },
 
     singleton: true,
diff --git a/www/manager6/form/Tag.js b/www/manager6/form/Tag.js
index 9acedb527..9da0db951 100644
--- a/www/manager6/form/Tag.js
+++ b/www/manager6/form/Tag.js
@@ -4,53 +4,44 @@ Ext.define('Proxmox.form.Tag', {
 
     mode: 'editable',
 
-    icons: {
-	editable: 'fa fa-minus-square',
-	normal: '',
-	inEdit: 'fa fa-check-square',
-    },
-
     tag: '',
     cls: 'pve-edit-tag',
 
     tpl: [
 	'<i class="handle fa fa-bars"></i>',
 	'<span>{tag}</span>',
-	'<i class="action {iconCls}"></i>',
+	'<i class="action fa fa-minus-square"></i>',
     ],
 
-    // we need to do this in mousedown, because that triggers before
-    // focusleave (which triggers before click)
-    onMouseDown: function(event) {
-	let me = this;
-	if (event.target.tagName !== 'I' || event.target.classList.contains('handle')) {
-	    return;
-	}
-	switch (me.mode) {
-	    case 'editable':
-		me.setVisible(false);
-		me.setTag('');
-		break;
-	    case 'inEdit':
-		me.setTag(me.tagEl().innerHTML);
-		me.setMode('editable');
-		break;
-	    default: break;
-	}
+    // contains tags not to show in the picker and not allowing to set
+    filter: [],
+
+    updateFilter: function(tags) {
+	this.filter = tags;
     },
 
     onClick: function(event) {
 	let me = this;
-	if (event.target.tagName !== 'SPAN' || me.mode !== 'editable') {
+	if (event.target.tagName === 'I' && !event.target.classList.contains('handle')) {
+	    if (me.mode === 'editable') {
+		me.destroy();
+		return;
+	    }
+	} else if (event.target.tagName !== 'SPAN' || me.mode !== 'editable') {
 	    return;
 	}
-	me.setMode('inEdit');
+	me.selectText();
+    },
 
-	// select text in the element
+    selectText: function(collapseToEnd) {
+	let me = this;
 	let tagEl = me.tagEl();
 	tagEl.contentEditable = true;
 	let range = document.createRange();
 	range.selectNodeContents(tagEl);
+	if (collapseToEnd) {
+	    range.collapse(false);
+	}
 	let sel = window.getSelection();
 	sel.removeAllRanges();
 	sel.addRange(range);
@@ -75,8 +66,10 @@ Ext.define('Proxmox.form.Tag', {
 		store: [],
 		listeners: {
 		    select: function(picker, rec) {
-			me.setTag(rec.data.tag);
-			me.setMode('editable');
+			me.tagEl().innerHTML = rec.data.tag;
+			me.setTag(rec.data.tag, true);
+			me.selectText(true);
+			me.setColor(rec.data.tag);
 			me.picker.hide();
 		    },
 		},
@@ -94,17 +87,16 @@ Ext.define('Proxmox.form.Tag', {
 
     setMode: function(mode) {
 	let me = this;
-	if (me.icons[mode] === undefined) {
-	    throw "invalid mode";
-	}
 	let tagEl = me.tagEl();
 	if (tagEl) {
-	    tagEl.contentEditable = mode === 'inEdit';
+	    tagEl.contentEditable = mode === 'editable';
 	}
 	me.removeCls(me.mode);
 	me.addCls(mode);
 	me.mode = mode;
-	me.updateData();
+	if (me.mode !== 'editable') {
+	    me.picker?.hide();
+	}
     },
 
     onKeyPress: function(event) {
@@ -112,15 +104,10 @@ Ext.define('Proxmox.form.Tag', {
 	let key = event.browserEvent.key;
 	switch (key) {
 	    case 'Enter':
-		if (me.tagEl().innerHTML !== '') {
-		    me.setTag(me.tagEl().innerHTML);
-		    me.setMode('editable');
-		    return;
-		}
 		break;
+	    case 'ArrowLeft':
+	    case 'ArrowRight':
 	    case 'Escape':
-		me.cancelEdit();
-		return;
 	    case 'Backspace':
 	    case 'Delete':
 		return;
@@ -128,11 +115,13 @@ Ext.define('Proxmox.form.Tag', {
 		if (key.match(PVE.Utils.tagCharRegex)) {
 		    return;
 		}
+		me.setTag(me.tagEl().innerHTML);
 	}
 	event.browserEvent.preventDefault();
 	event.browserEvent.stopPropagation();
     },
 
+    // for pasting text
     beforeInput: function(event) {
 	let me = this;
 	me.updateLayout();
@@ -153,22 +142,17 @@ Ext.define('Proxmox.form.Tag', {
 	    value: me.tagEl().innerHTML,
 	    anyMatch: true,
 	});
+	me.setTag(me.tagEl().innerHTML);
     },
 
-    cancelEdit: function(list, event) {
+    lostFocus: function(list, event) {
 	let me = this;
-	if (me.mode === 'inEdit') {
-	    me.setTag(me.tag);
-	    me.setMode('editable');
-	}
 	me.picker?.hide();
+	window.getSelection().removeAllRanges();
     },
 
-
-    setTag: function(tag) {
+    setColor: function(tag) {
 	let me = this;
-	let oldtag = me.tag;
-	me.tag = tag;
 	let rgb = PVE.Utils.tagOverrides[tag] ?? Proxmox.Utils.stringToRGB(tag);
 
 	let cls = Proxmox.Utils.getTextContrastClass(rgb);
@@ -182,21 +166,20 @@ Ext.define('Proxmox.form.Tag', {
 	} else {
 	    me.setStyle('color');
 	}
-	me.updateData();
-	if (oldtag !== tag) {
-	    me.fireEvent('change', me, tag, oldtag);
-	}
     },
 
-    updateData: function() {
+    setTag: function(tag) {
 	let me = this;
-	if (me.destroying || me.destroyed) {
-	    return;
+	let oldtag = me.tag;
+	me.tag = tag;
+
+	clearTimeout(me.colorTimeout);
+	me.colorTimeout = setTimeout(() => me.setColor(tag), 200);
+
+	me.updateLayout();
+	if (oldtag !== tag) {
+	    me.fireEvent('change', me, tag, oldtag);
 	}
-	me.update({
-	    tag: me.tag,
-	    iconCls: me.icons[me.mode],
-	});
     },
 
     tagEl: function() {
@@ -204,9 +187,8 @@ Ext.define('Proxmox.form.Tag', {
     },
 
     listeners: {
-	mousedown: 'onMouseDown',
 	click: 'onClick',
-	focusleave: 'cancelEdit',
+	focusleave: 'lostFocus',
 	keydown: 'onKeyPress',
 	beforeInput: 'beforeInput',
 	input: 'onInput',
@@ -217,7 +199,12 @@ Ext.define('Proxmox.form.Tag', {
     initComponent: function() {
 	let me = this;
 
+	me.data = {
+	    tag: me.tag,
+	};
+
 	me.setTag(me.tag);
+	me.setColor(me.tag);
 	me.setMode(me.mode ?? 'normal');
 	me.callParent();
     },
@@ -227,6 +214,7 @@ Ext.define('Proxmox.form.Tag', {
 	if (me.picker) {
 	    Ext.destroy(me.picker);
 	}
+	clearTimeout(me.colorTimeout);
 	me.callParent();
     },
 });
diff --git a/www/manager6/form/TagEdit.js b/www/manager6/form/TagEdit.js
index 6325d39df..4e3fec384 100644
--- a/www/manager6/form/TagEdit.js
+++ b/www/manager6/form/TagEdit.js
@@ -4,7 +4,7 @@ Ext.define('PVE.panel.TagEditContainer', {
 
     layout: {
 	type: 'hbox',
-	align: 'stretch',
+	align: 'middle',
     },
 
     controller: {
@@ -120,9 +120,6 @@ Ext.define('PVE.panel.TagEditContainer', {
 	    let me = this;
 	    let view = me.getView();
 	    view.items.each((field) => {
-		if (field.reference === 'addTagBtn') {
-		    return false;
-		}
 		if (field.getXType() === 'pveTag') {
 		    func(field);
 		}
@@ -133,6 +130,7 @@ Ext.define('PVE.panel.TagEditContainer', {
 	toggleEdit: function(cancel) {
 	    let me = this;
 	    let vm = me.getViewModel();
+	    let view = me.getView();
 	    let editMode = !vm.get('editMode');
 	    vm.set('editMode', editMode);
 
@@ -150,14 +148,19 @@ Ext.define('PVE.panel.TagEditContainer', {
 		if (cancel) {
 		    me.loadTags(me.oldTags, true);
 		} else {
+		    let toRemove = [];
 		    me.forEachTag((cmp) => {
 			if (cmp.isVisible() && cmp.tag) {
 			    tags.push(cmp.tag);
+			} else {
+			    toRemove.push(cmp);
 			}
 		    });
+		    toRemove.forEach(cmp => view.remove(cmp));
 		    tags = tags.join(',');
 		    if (me.oldTags !== tags) {
 			me.oldTags = tags;
+			me.loadTags(tags, true);
 			me.getView().fireEvent('change', tags);
 		    }
 		}
@@ -165,60 +168,44 @@ Ext.define('PVE.panel.TagEditContainer', {
 	    me.getView().updateLayout();
 	},
 
-	addTag: function(tag) {
+	addTag: function(tag, isNew) {
 	    let me = this;
 	    let view = me.getView();
 	    let vm = me.getViewModel();
-	    let index = view.items.indexOf(me.lookup('addTagBtn'));
-	    if (PVE.Utils.shouldSortTags()) {
+	    let index = view.items.length - 5;
+	    if (PVE.Utils.shouldSortTags() && !isNew) {
 		index = view.items.findIndexBy(tagField => {
-		    if (tagField.reference === 'addTagBtn') {
+		    if (tagField.reference === 'noTagsField') {
+			return false;
+		    }
+		    if (tagField.xtype !== 'pveTag') {
 			return true;
 		    }
 		    return tagField.tag >= tag;
 		}, 1);
 	    }
-	    view.insert(index, {
+	    let tagField = view.insert(index, {
 		xtype: 'pveTag',
 		tag,
 		mode: vm.get('editMode') ? 'editable' : 'normal',
 		listeners: {
-		    change: (field, newTag) => {
-			if (newTag === '') {
-			    view.remove(field);
-			    vm.set('tagCount', vm.get('tagCount') - 1);
-			}
+		    destroy: function() {
+			vm.set('tagCount', vm.get('tagCount') - 1);
 		    },
 		},
 	    });
 
-	    vm.set('tagCount', vm.get('tagCount') + 1);
-	},
-
-	addTagClick: function(event) {
-	    let me = this;
-	    if (event.target.tagName === 'SPAN') {
-		me.lookup('addTagBtn').tagEl().innerHTML = '';
-		me.lookup('addTagBtn').updateLayout();
+	    if (isNew) {
+		tagField.selectText();
 	    }
-	},
 
-	addTagMouseDown: function(event) {
-	    let me = this;
-	    if (event.target.tagName === 'I') {
-		let tag = me.lookup('addTagBtn').tagEl().innerHTML;
-		if (tag !== '') {
-		    me.addTag(tag, true);
-		}
-	    }
+	    vm.set('tagCount', vm.get('tagCount') + 1);
 	},
 
-	addTagChange: function(field, tag) {
+	addTagClick: function(event) {
 	    let me = this;
-	    if (tag !== '') {
-		me.addTag(tag, true);
-	    }
-	    field.tag = '';
+	    me.lookup('noTagsField').setVisible(false);
+	    me.addTag('', true);
 	},
 
 	cancelClick: function() {
@@ -250,12 +237,7 @@ Ext.define('PVE.panel.TagEditContainer', {
 
 	formulas: {
 	    hideNoTags: function(get) {
-		return get('editMode') || get('tagCount') !== 0;
-	    },
-	    editBtnHtml: function(get) {
-		let cls = get('editMode') ? 'check' : 'pencil';
-		let qtip = get('editMode') ? gettext('Apply Changes') : gettext('Edit Tags');
-		return `<i data-qtip="${qtip}" class="fa fa-${cls}"></i>`;
+		return get('tagCount') !== 0;
 	    },
 	},
     },
@@ -267,53 +249,61 @@ Ext.define('PVE.panel.TagEditContainer', {
     items: [
 	{
 	    xtype: 'box',
+	    reference: 'noTagsField',
 	    bind: {
 		hidden: '{hideNoTags}',
 	    },
 	    html: gettext('No Tags'),
 	},
 	{
-	    xtype: 'pveTag',
-	    reference: 'addTagBtn',
-	    cls: 'pve-add-tag',
-	    mode: 'editable',
-	    tag: '',
-	    tpl: `<span>${gettext('Add Tag')}</span><i class="action fa fa-plus-square"></i>`,
+	    xtype: 'button',
+	    iconCls: 'fa fa-plus',
+	    tooltip: gettext('Add Tag'),
 	    bind: {
 		hidden: '{!editMode}',
 	    },
 	    hidden: true,
-	    onMouseDown: Ext.emptyFn, // prevent default behaviour
-	    listeners: {
-		click: {
-		    element: 'el',
-		    fn: 'addTagClick',
-		},
-		mousedown: {
-		    element: 'el',
-		    fn: 'addTagMouseDown',
-		},
-		change: 'addTagChange',
-	    },
+	    margin: '0 8 0 5',
+	    ui: 'default-toolbar',
+	    handler: 'addTagClick',
 	},
 	{
-	    xtype: 'box',
-	    html: `<i data-qtip="${gettext('Cancel')}" class="fa fa-times"></i>`,
-	    cls: 'pve-tag-inline-button',
+	    xtype: 'tbseparator',
+	    ui: 'horizontal',
+	    bind: {
+		hidden: '{!editMode}',
+	    },
 	    hidden: true,
+	},
+	{
+	    xtype: 'button',
+	    iconCls: 'fa fa-times',
+	    tooltip: gettext('Cancel Edit'),
 	    bind: {
 		hidden: '{!editMode}',
 	    },
-	    listeners: {
-		click: 'cancelClick',
-		element: 'el',
+	    hidden: true,
+	    margin: '0 5 0 0',
+	    ui: 'default-toolbar',
+	    handler: 'cancelClick',
+	},
+	{
+	    xtype: 'button',
+	    iconCls: 'fa fa-check',
+	    tooltip: gettext('Finish Edit'),
+	    bind: {
+		hidden: '{!editMode}',
 	    },
+	    hidden: true,
+	    ui: 'default-toolbar',
+	    handler: 'editClick',
 	},
 	{
 	    xtype: 'box',
 	    cls: 'pve-tag-inline-button',
+	    html: `<i data-qtip="${gettext('Edit Tags')}" class="fa fa-pencil"></i>`,
 	    bind: {
-		html: '{editBtnHtml}',
+		hidden: '{editMode}',
 	    },
 	    listeners: {
 		click: 'editClick',
-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH manager 2/5] ui: tags: make sorting more natural
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 1/5] ui: rework inline tag editing Dominik Csapak
@ 2022-11-17 14:56 ` Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 3/5] ui: tags: hide already set tags in dropdown Dominik Csapak
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

by sorting the lower cased variants, and only if they are identical
sort the original values with 'localeCompare'

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/Utils.js        | 6 +++++-
 www/manager6/form/TagEdit.js | 4 +++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index e4b6207c6..9ceda0a97 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1941,7 +1941,11 @@ Ext.define('PVE.Utils', {
 	if (tagstext) {
 	    let tags = (tagstext.split(/[,; ]/) || []).filter(t => !!t);
 	    if (PVE.Utils.shouldSortTags()) {
-		tags = tags.sort();
+		tags = tags.sort((a,b) => {
+		    let alc = a.toLowerCase();
+		    let blc = b.toLowerCase();
+		    return alc < blc ? -1 : blc < alc ? 1 : a.localeCompare(b);
+		});
 	    }
 	    text += ' ';
 	    tags.forEach((tag) => {
diff --git a/www/manager6/form/TagEdit.js b/www/manager6/form/TagEdit.js
index 4e3fec384..9015bd653 100644
--- a/www/manager6/form/TagEdit.js
+++ b/www/manager6/form/TagEdit.js
@@ -181,7 +181,9 @@ Ext.define('PVE.panel.TagEditContainer', {
 		    if (tagField.xtype !== 'pveTag') {
 			return true;
 		    }
-		    return tagField.tag >= tag;
+		    let a = tagField.tag.toLowerCase()
+		    let b = tag.toLowerCase();
+		    return a > b ? true : a < b ? false : tagField.tag.localeCompare(tag) > 0;
 		}, 1);
 	    }
 	    let tagField = view.insert(index, {
-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH manager 3/5] ui: tags: hide already set tags in dropdown
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 1/5] ui: rework inline tag editing Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 2/5] ui: tags: make sorting more natural Dominik Csapak
@ 2022-11-17 14:56 ` Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 4/5] ui: change style of ListField Dominik Csapak
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

on every change, collect all tags and update the filter of all tag
fields

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/form/Tag.js     |  2 +-
 www/manager6/form/TagEdit.js | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/www/manager6/form/Tag.js b/www/manager6/form/Tag.js
index 9da0db951..8d003ca97 100644
--- a/www/manager6/form/Tag.js
+++ b/www/manager6/form/Tag.js
@@ -76,7 +76,7 @@ Ext.define('Proxmox.form.Tag', {
 	    });
 	}
 	me.picker.getStore()?.clearFilter();
-	let taglist = PVE.Utils.tagList.map(v => ({ tag: v }));
+	let taglist = PVE.Utils.tagList.filter(v => !me.filter.includes(v)).map(v => ({ tag: v }));
 	if (taglist.length < 1) {
 	    return;
 	}
diff --git a/www/manager6/form/TagEdit.js b/www/manager6/form/TagEdit.js
index 9015bd653..3806bbdf3 100644
--- a/www/manager6/form/TagEdit.js
+++ b/www/manager6/form/TagEdit.js
@@ -27,6 +27,7 @@ Ext.define('PVE.panel.TagEditContainer', {
 	    newtags.forEach((tag) => {
 		me.addTag(tag);
 	    });
+	    me.updateFilter();
 	    view.suspendLayout = false;
 	    view.updateLayout();
 	    if (!force) {
@@ -168,6 +169,19 @@ Ext.define('PVE.panel.TagEditContainer', {
 	    me.getView().updateLayout();
 	},
 
+	updateFilter: function() {
+	    let me = this;
+	    let tags = [];
+	    me.forEachTag(cmp => {
+		if (cmp.tag) {
+		    tags.push(cmp.tag);
+		}
+	    });
+	    me.forEachTag(cmp => {
+		cmp.updateFilter(tags);
+	    });
+	},
+
 	addTag: function(tag, isNew) {
 	    let me = this;
 	    let view = me.getView();
@@ -191,6 +205,9 @@ Ext.define('PVE.panel.TagEditContainer', {
 		tag,
 		mode: vm.get('editMode') ? 'editable' : 'normal',
 		listeners: {
+		    change: (field, newTag) => {
+			me.updateFilter();
+		    },
 		    destroy: function() {
 			vm.set('tagCount', vm.get('tagCount') - 1);
 		    },
@@ -198,6 +215,7 @@ Ext.define('PVE.panel.TagEditContainer', {
 	    });
 
 	    if (isNew) {
+		me.updateFilter();
 		tagField.selectText();
 	    }
 
-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH manager 4/5] ui: change style of ListField
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
                   ` (2 preceding siblings ...)
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 3/5] ui: tags: hide already set tags in dropdown Dominik Csapak
@ 2022-11-17 14:56 ` Dominik Csapak
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 5/5] ui: tags: add preview to tag shape option Dominik Csapak
  2022-11-17 17:22 ` [pve-devel] applied-series: [PATCH manager 0/5] tags ui follow up patches Thomas Lamprecht
  5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

and make it more like the 'traffic control' time grid in pbs

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/dc/RegisteredTagsEdit.js |  6 +-
 www/manager6/dc/UserTagAccessEdit.js  |  6 +-
 www/manager6/form/ListField.js        | 86 ++++++++++++++++-----------
 3 files changed, 60 insertions(+), 38 deletions(-)

diff --git a/www/manager6/dc/RegisteredTagsEdit.js b/www/manager6/dc/RegisteredTagsEdit.js
index 92e076e0a..75b4f9ba3 100644
--- a/www/manager6/dc/RegisteredTagsEdit.js
+++ b/www/manager6/dc/RegisteredTagsEdit.js
@@ -52,8 +52,10 @@ Ext.define('PVE.dc.RegisteredTagsEdit', {
 		    emptyText: gettext('No Tags defined'),
 		    fieldTitle: gettext('Tag'),
 		    maskRe: PVE.Utils.tagCharRegex,
-		    height: 200,
-		    scrollable: true,
+		    gridConfig: {
+			height: 200,
+			scrollable: true,
+		    },
 		    listeners: {
 			change: 'tagChange',
 		    },
diff --git a/www/manager6/dc/UserTagAccessEdit.js b/www/manager6/dc/UserTagAccessEdit.js
index 701d1de4f..f22ac9b3d 100644
--- a/www/manager6/dc/UserTagAccessEdit.js
+++ b/www/manager6/dc/UserTagAccessEdit.js
@@ -72,8 +72,10 @@ Ext.define('PVE.dc.UserTagAccessEdit', {
 		    emptyText: gettext('No Tags defined'),
 		    fieldTitle: gettext('Tag'),
 		    maskRe: PVE.Utils.tagCharRegex,
-		    height: 200,
-		    scrollable: true,
+		    gridConfig: {
+			height: 200,
+			scrollable: true,
+		    },
 		    listeners: {
 			change: 'tagChange',
 		    },
diff --git a/www/manager6/form/ListField.js b/www/manager6/form/ListField.js
index faa8e168b..77e9ebfca 100644
--- a/www/manager6/form/ListField.js
+++ b/www/manager6/form/ListField.js
@@ -1,5 +1,5 @@
 Ext.define('PVE.form.ListField', {
-    extend: 'Ext.grid.Panel',
+    extend: 'Ext.container.Container',
     alias: 'widget.pveListField',
 
     mixins: [
@@ -16,23 +16,18 @@ Ext.define('PVE.form.ListField', {
     selectAll: false,
     isFormField: true,
     deleteEmpty: false,
-    selModel: 'checkboxmodel',
-
     config: {
 	deleteEmpty: false,
     },
 
-    viewConfig: {
-	deferEmptyText: false,
-    },
-
     setValue: function(list) {
 	let me = this;
 	list = Ext.isArray(list) ? list : (list ?? '').split(';');
+	let store = me.lookup('grid').getStore();
 	if (list.length > 0) {
-	    me.getStore().setData(list.map(item => ({ item })));
+	    store.setData(list.map(item => ({ item })));
 	} else {
-	    me.getStore().removeAll();
+	    store.removeAll();
 	}
 	me.checkChange();
 	return me;
@@ -41,7 +36,7 @@ Ext.define('PVE.form.ListField', {
     getValue: function() {
 	let me = this;
 	let values = [];
-	me.getStore().each((rec) => {
+	me.lookup('grid').getStore().each((rec) => {
 	    if (rec.data.item) {
 		values.push(rec.data.item);
 	    }
@@ -52,7 +47,7 @@ Ext.define('PVE.form.ListField', {
     getErrors: function(value) {
 	let me = this;
 	let empty = false;
-	me.getStore().each((rec) => {
+	me.lookup('grid').getStore().each((rec) => {
 	    if (!rec.data.item) {
 		empty = true;
 	    }
@@ -86,22 +81,23 @@ Ext.define('PVE.form.ListField', {
 
 	addLine: function() {
 	    let me = this;
-	    me.getView().getStore().add({
+	    me.lookup('grid').getStore().add({
 		item: '',
 	    });
 	},
 
-	removeSelection: function() {
+	removeSelection: function(field) {
 	    let me = this;
 	    let view = me.getView();
-	    let selection = view.getSelection();
-	    if (selection === undefined) {
+	    let grid = me.lookup('grid');
+
+	    let record = field.getWidgetRecord();
+	    if (record === undefined) {
+		// this is sometimes called before a record/column is initialized
 		return;
 	    }
 
-	    selection.forEach((sel) => {
-		view.getStore().remove(sel);
-	    });
+	    grid.getStore().remove(record);
 	    view.checkChange();
 	},
 
@@ -114,33 +110,47 @@ Ext.define('PVE.form.ListField', {
 	    rec.set(column.dataIndex, newValue);
 	    field.up('pveListField').checkChange();
 	},
+
+	control: {
+	    'grid button': {
+		click: 'removeSelection',
+	    },
+	},
     },
 
-    tbar: [
+    items: [
 	{
-	    text: gettext('Add'),
-	    handler: 'addLine',
+	    xtype: 'grid',
+	    reference: 'grid',
+
+	    viewConfig: {
+		deferEmptyText: false,
+	    },
+
+	    store: {
+		listeners: {
+		    update: function() {
+			this.commitChanges();
+		    },
+		},
+	    },
 	},
 	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Remove'),
-	    handler: 'removeSelection',
-	    disabled: true,
+	    xtype: 'button',
+	    text: gettext('Add'),
+	    iconCls: 'fa fa-plus-circle',
+	    handler: 'addLine',
 	},
     ],
 
-    store: {
-	listeners: {
-	    update: function() {
-		this.commitChanges();
-	    },
-	},
-    },
-
     initComponent: function() {
 	let me = this;
 
-	me.columns = [
+	for (const [key, value] of Object.entries(me.gridConfig ?? {})) {
+	    me.items[0][key] = value;
+	}
+
+	me.items[0].columns = [
 	    {
 		header: me.fieldTtitle,
 		dataIndex: 'item',
@@ -157,6 +167,14 @@ Ext.define('PVE.form.ListField', {
 		},
 		flex: 1,
 	    },
+	    {
+		xtype: 'widgetcolumn',
+		width: 40,
+		widget: {
+		    xtype: 'button',
+		    iconCls: 'fa fa-trash-o',
+		},
+	    },
 	];
 
 	me.callParent();
-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH manager 5/5] ui: tags: add preview to tag shape option
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
                   ` (3 preceding siblings ...)
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 4/5] ui: change style of ListField Dominik Csapak
@ 2022-11-17 14:56 ` Dominik Csapak
  2022-11-17 17:22 ` [pve-devel] applied-series: [PATCH manager 0/5] tags ui follow up patches Thomas Lamprecht
  5 siblings, 0 replies; 7+ messages in thread
From: Dominik Csapak @ 2022-11-17 14:56 UTC (permalink / raw)
  To: pve-devel

with a combogrid and the example text 'preview'

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 www/manager6/dc/OptionView.js | 37 ++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/www/manager6/dc/OptionView.js b/www/manager6/dc/OptionView.js
index aeab024e4..8c0357bbf 100644
--- a/www/manager6/dc/OptionView.js
+++ b/www/manager6/dc/OptionView.js
@@ -360,7 +360,7 @@ Ext.define('PVE.dc.OptionView', {
 			    if (values.colors) {
 				style['color-map'] = values.colors;
 			    }
-			    if (values.shape) {
+			    if (values.shape && values.shape !== '__default__') {
 				style.shape = values.shape;
 			    }
 			    if (values.ordering) {
@@ -378,10 +378,41 @@ Ext.define('PVE.dc.OptionView', {
 			},
 			items: [
 			    {
+
 				name: 'shape',
-				xtype: 'proxmoxKVComboBox',
+				xtype: 'proxmoxComboGrid',
 				fieldLabel: gettext('Tree Shape'),
-				comboItems: Object.entries(PVE.Utils.tagTreeStyles),
+				valueField: 'value',
+				displayField:'display',
+				listConfig: {
+				    columns: [
+					{
+					    header: gettext('Option'),
+					    dataIndex: 'display',
+					    flex: 1,
+					},
+					{
+					    header: gettext('Preview'),
+					    dataIndex: 'value',
+					    renderer: function(value) {
+						let cls = value ?? '__default__';
+						if (value === '__default__') {
+						    cls = 'circle'
+						}
+						let tags = PVE.Utils.renderTags('preview');
+						return `<div class="proxmox-tags-${cls}">${tags}</div>`;
+					    },
+					    flex: 1,
+					}
+				    ],
+				},
+				store: {
+				    data: Object.entries(PVE.Utils.tagTreeStyles).map(v => ({
+					value: v[0],
+					display: v[1],
+				    })),
+				},
+				deleteDefault: true,
 				defaultValue: '__default__',
 				deleteEmpty: true,
 			    },
-- 
2.30.2





^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] applied-series: [PATCH manager 0/5] tags ui follow up patches
  2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
                   ` (4 preceding siblings ...)
  2022-11-17 14:56 ` [pve-devel] [PATCH manager 5/5] ui: tags: add preview to tag shape option Dominik Csapak
@ 2022-11-17 17:22 ` Thomas Lamprecht
  5 siblings, 0 replies; 7+ messages in thread
From: Thomas Lamprecht @ 2022-11-17 17:22 UTC (permalink / raw)
  To: Proxmox VE development discussion, Dominik Csapak

Am 17/11/2022 um 15:56 schrieb Dominik Csapak:
> overall ui improvements of the tags ui, see the individual patches
> for details
> 
> intended as follow up to my v11 tags ui series
> 
> Dominik Csapak (5):
>   ui: rework inline tag editing
>   ui: tags: make sorting more natural
>   ui: tags: hide already set tags in dropdown
>   ui: change style of ListField
>   ui: tags: add preview to tag shape option
> 
>  www/css/ext6-pve.css                  |  28 ++---
>  www/manager6/Utils.js                 |   8 +-
>  www/manager6/dc/OptionView.js         |  37 ++++++-
>  www/manager6/dc/RegisteredTagsEdit.js |   6 +-
>  www/manager6/dc/UserTagAccessEdit.js  |   6 +-
>  www/manager6/form/ListField.js        |  86 +++++++++------
>  www/manager6/form/Tag.js              | 118 ++++++++++-----------
>  www/manager6/form/TagEdit.js          | 144 ++++++++++++++------------
>  8 files changed, 240 insertions(+), 193 deletions(-)
> 


applied series, thanks!




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-11-17 17:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-17 14:56 [pve-devel] [PATCH manager 0/5] tags ui follow up patches Dominik Csapak
2022-11-17 14:56 ` [pve-devel] [PATCH manager 1/5] ui: rework inline tag editing Dominik Csapak
2022-11-17 14:56 ` [pve-devel] [PATCH manager 2/5] ui: tags: make sorting more natural Dominik Csapak
2022-11-17 14:56 ` [pve-devel] [PATCH manager 3/5] ui: tags: hide already set tags in dropdown Dominik Csapak
2022-11-17 14:56 ` [pve-devel] [PATCH manager 4/5] ui: change style of ListField Dominik Csapak
2022-11-17 14:56 ` [pve-devel] [PATCH manager 5/5] ui: tags: add preview to tag shape option Dominik Csapak
2022-11-17 17:22 ` [pve-devel] applied-series: [PATCH manager 0/5] tags ui follow up patches Thomas Lamprecht

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