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 D153B83E1 for ; Tue, 15 Nov 2022 14:03:21 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 79D812ED5 for ; Tue, 15 Nov 2022 14:03:01 +0100 (CET) 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)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 15 Nov 2022 14:02:54 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id F361044C0C for ; Tue, 15 Nov 2022 14:02:51 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Date: Tue, 15 Nov 2022 14:02:41 +0100 Message-Id: <20221115130248.1007325-17-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221115130248.1007325-1-d.csapak@proxmox.com> References: <20221115130248.1007325-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: =?UTF-8?Q?0=0A=09?=AWL 0.065 Adjusted score from AWL reputation of From: =?UTF-8?Q?address=0A=09?=BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict =?UTF-8?Q?Alignment=0A=09?=SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF =?UTF-8?Q?Record=0A=09?=SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH manager v10 06/13] ui: add PVE.form.ListField 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: Tue, 15 Nov 2022 13:03:21 -0000 a field which contains just a list of textfields, e.g. useful for a list of simple tags Signed-off-by: Dominik Csapak --- www/manager6/Makefile | 1 + www/manager6/form/ListField.js | 165 +++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 www/manager6/form/ListField.js diff --git a/www/manager6/Makefile b/www/manager6/Makefile index 572aa9392..83c2effcf 100644 --- a/www/manager6/Makefile +++ b/www/manager6/Makefile @@ -74,6 +74,7 @@ JSSRC= \ form/ViewSelector.js \ form/iScsiProviderSelector.js \ form/TagColorGrid.js \ + form/ListField.js \ grid/BackupView.js \ grid/FirewallAliases.js \ grid/FirewallOptions.js \ diff --git a/www/manager6/form/ListField.js b/www/manager6/form/ListField.js new file mode 100644 index 000000000..faa8e168b --- /dev/null +++ b/www/manager6/form/ListField.js @@ -0,0 +1,165 @@ +Ext.define('PVE.form.ListField', { + extend: 'Ext.grid.Panel', + alias: 'widget.pveListField', + + mixins: [ + 'Ext.form.field.Field', + ], + + // override for column header + fieldTitle: gettext('Item'), + + // will be applied to the textfields + maskRe: undefined, + + allowBlank: true, + 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(';'); + if (list.length > 0) { + me.getStore().setData(list.map(item => ({ item }))); + } else { + me.getStore().removeAll(); + } + me.checkChange(); + return me; + }, + + getValue: function() { + let me = this; + let values = []; + me.getStore().each((rec) => { + if (rec.data.item) { + values.push(rec.data.item); + } + }); + return values.join(';'); + }, + + getErrors: function(value) { + let me = this; + let empty = false; + me.getStore().each((rec) => { + if (!rec.data.item) { + empty = true; + } + }); + if (empty) { + return [gettext('Tag must not be empty.')]; + } + return []; + }, + + // override framework function to implement deleteEmpty behaviour + getSubmitData: function() { + let me = this, + data = null, + val; + if (!me.disabled && me.submitValue) { + val = me.getValue(); + if (val !== null && val !== '') { + data = {}; + data[me.getName()] = val; + } else if (me.getDeleteEmpty()) { + data = {}; + data.delete = me.getName(); + } + } + return data; + }, + + controller: { + xclass: 'Ext.app.ViewController', + + addLine: function() { + let me = this; + me.getView().getStore().add({ + item: '', + }); + }, + + removeSelection: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (selection === undefined) { + return; + } + + selection.forEach((sel) => { + view.getStore().remove(sel); + }); + view.checkChange(); + }, + + itemChange: function(field, newValue) { + let rec = field.getWidgetRecord(); + if (!rec) { + return; + } + let column = field.getWidgetColumn(); + rec.set(column.dataIndex, newValue); + field.up('pveListField').checkChange(); + }, + }, + + tbar: [ + { + text: gettext('Add'), + handler: 'addLine', + }, + { + xtype: 'proxmoxButton', + text: gettext('Remove'), + handler: 'removeSelection', + disabled: true, + }, + ], + + store: { + listeners: { + update: function() { + this.commitChanges(); + }, + }, + }, + + initComponent: function() { + let me = this; + + me.columns = [ + { + header: me.fieldTtitle, + dataIndex: 'item', + xtype: 'widgetcolumn', + widget: { + xtype: 'textfield', + isFormField: false, + maskRe: me.maskRe, + allowBlank: false, + queryMode: 'local', + listeners: { + change: 'itemChange', + }, + }, + flex: 1, + }, + ]; + + me.callParent(); + me.initField(); + }, +}); -- 2.30.2