all lists on 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal