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 08EA9EA99 for ; Wed, 19 Jul 2023 15:33:23 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id D6ACC825E for ; Wed, 19 Jul 2023 15:32:52 +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)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Wed, 19 Jul 2023 15:32:52 +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 E12B44105A; Wed, 19 Jul 2023 15:32:51 +0200 (CEST) Message-ID: <69a5020f-eb69-c87b-78d6-7e0858a8ea78@proxmox.com> Date: Wed, 19 Jul 2023 15:32:50 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: Proxmox VE development discussion , Lukas Wagner References: <20230717150051.710464-1-l.wagner@proxmox.com> <20230717150051.710464-64-l.wagner@proxmox.com> From: Dominik Csapak In-Reply-To: <20230717150051.710464-64-l.wagner@proxmox.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.016 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 T_SCC_BODY_TEXT_LINE -0.01 - URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [me.name] Subject: Re: [pve-devel] [PATCH v3 proxmox-widget-toolkit 63/66] notification: add gui for notification groups 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, 19 Jul 2023 13:33:23 -0000 comments inline On 7/17/23 17:00, Lukas Wagner wrote: > Signed-off-by: Lukas Wagner > --- > src/Makefile | 1 + > src/Schema.js | 5 + > src/panel/NotificationGroupEditPanel.js | 177 ++++++++++++++++++++++++ > src/window/EndpointEditBase.js | 6 +- > 4 files changed, 188 insertions(+), 1 deletion(-) > create mode 100644 src/panel/NotificationGroupEditPanel.js > > diff --git a/src/Makefile b/src/Makefile > index 2e620e3..829081d 100644 > --- a/src/Makefile > +++ b/src/Makefile > @@ -61,6 +61,7 @@ JSSRC= \ > panel/LogView.js \ > panel/NodeInfoRepoStatus.js \ > panel/NotificationConfigView.js \ > + panel/NotificationGroupEditPanel.js \ > panel/JournalView.js \ > panel/PermissionView.js \ > panel/PruneKeepPanel.js \ > diff --git a/src/Schema.js b/src/Schema.js > index 37ecd88..a7ffdf8 100644 > --- a/src/Schema.js > +++ b/src/Schema.js > @@ -48,6 +48,11 @@ Ext.define('Proxmox.Schema', { // a singleton > ipanel: 'pmxGotifyEditPanel', > iconCls: 'fa-bell-o', > }, > + group: { > + name: gettext('Notification Group'), > + ipanel: 'pmxNotificationGroupEditPanel', > + iconCls: 'fa-bell-o', > + }, > }, > > pxarFileTypes: { > diff --git a/src/panel/NotificationGroupEditPanel.js b/src/panel/NotificationGroupEditPanel.js > new file mode 100644 > index 0000000..0a7a469 > --- /dev/null > +++ b/src/panel/NotificationGroupEditPanel.js > @@ -0,0 +1,177 @@ > +Ext.define('Proxmox.panel.NotificationGroupEditPanel', { > + extend: 'Proxmox.panel.InputPanel', > + xtype: 'pmxNotificationGroupEditPanel', > + mixins: ['Proxmox.Mixin.CBind'], > + > + type: 'group', > + > + columnT: [ > + { > + xtype: 'pmxDisplayEditField', > + name: 'name', > + cbind: { > + value: '{name}', > + editable: '{isCreate}', > + }, > + fieldLabel: gettext('Group Name'), > + allowBlank: false, > + }, > + { > + xtype: 'pmxNotificationEndpointSelector', > + name: 'endpoint', > + allowBlank: false, > + }, > + ], > + > + column1: [], > + > + column2: [], > + > + columnB: [ > + { > + xtype: 'proxmoxtextfield', > + name: 'comment', > + fieldLabel: gettext('Comment'), > + cbind: { > + deleteEmpty: '{!isCreate}', > + }, > + }, > + ], > +}); > + > +Ext.define('Proxmox.form.NotificationEndpointSelector', { > + extend: 'Ext.grid.Panel', > + alias: 'widget.pmxNotificationEndpointSelector', > + > + mixins: { > + field: 'Ext.form.field.Field', > + }, when implementing the field mixin you have to (quote from the extjs docs) ---8<--- You will also need to make sure that initField is called during the component's initialization. --->8--- so you normally need a (small) initComponent that calls that (otherwise you can have some strange effects when using the field) > + > + allowBlank: true, > + selectAll: false, > + isFormField: true, > + > + store: { > + autoLoad: true, > + model: 'proxmox-notification-endpoints', > + sorters: 'name', > + filters: item => item.data.type !== 'group', > + }, > + > + columns: [ > + { > + header: gettext('Endpoint Name'), > + dataIndex: 'name', > + flex: 1, > + }, > + { > + header: gettext('Type'), > + dataIndex: 'type', > + flex: 1, > + }, > + { > + header: gettext('Comment'), > + dataIndex: 'comment', > + flex: 3, > + }, > + ], > + > + selModel: { > + selType: 'checkboxmodel', > + mode: 'SIMPLE', > + }, > + > + checkChangeEvents: [ > + 'selectionchange', > + 'change', > + ], > + > + listeners: { > + selectionchange: function() { > + // to trigger validity and error checks > + this.checkChange(); > + }, > + }, > + > + getSubmitData: function() { > + let me = this; > + let res = {}; > + res[me.name] = me.getValue(); > + return res; > + }, > + > + getValue: function() { > + let me = this; > + if (me.savedValue !== undefined) { > + return me.savedValue; > + } > + let sm = me.getSelectionModel(); > + let selection = sm.getSelection(); > + let values = []; > + selection.forEach(function(item) { > + values.push(item.data.name); > + }); > + return values; could also be: return (sm.getSelection() ?? []).map(item => item.data.name); > + }, > + > + setValueSelection: function(value) { > + let me = this; > + > + let store = me.getStore(); > + > + let notFound = []; > + let selection = value.map(item => { > + let found = store.findRecord('name', item, 0, false, true, true); > + if (!found) { > + notFound.push(item); > + } > + return found; > + }).filter(r => r); > + > + for (const name of notFound) { > + let rec = store.add({ > + name, > + type: '-', > + comment: gettext('Included endpoint does not exist!'), > + }); > + selection.push(rec[0]); > + } > + > + let sm = me.getSelectionModel(); > + if (selection.length) { > + sm.select(selection); > + } else { > + sm.deselectAll(); > + } > + // to correctly trigger invalid class > + me.getErrors(); > + }, > + > + setValue: function(value) { > + let me = this; > + > + let store = me.getStore(); > + if (!store.isLoaded()) { > + me.savedValue = value; > + store.on('load', function() { > + me.setValueSelection(value); > + delete me.savedValue; > + }, { single: true }); > + } else { > + me.setValueSelection(value); > + } > + return me.mixins.field.setValue.call(me, value); > + }, > + > + getErrors: function(value) { > + let me = this; > + if (!me.isDisabled() && me.allowBlank === false && > + me.getSelectionModel().getCount() === 0) { > + me.addBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']); > + return [gettext('No endpoint selected')]; > + } > + > + me.removeBodyCls(['x-form-trigger-wrap-default', 'x-form-trigger-wrap-invalid']); > + return []; > + }, > +}); > diff --git a/src/window/EndpointEditBase.js b/src/window/EndpointEditBase.js > index 81e5951..bcf6879 100644 > --- a/src/window/EndpointEditBase.js > +++ b/src/window/EndpointEditBase.js > @@ -16,7 +16,11 @@ Ext.define('Proxmox.window.EndpointEditBase', { > throw "baseUrl not set"; > } > > - me.url = `/api2/extjs${me.baseUrl}/endpoints/${me.type}`; > + if (me.type === 'group') { > + me.url = `/api2/extjs${me.baseUrl}/groups`; > + } else { > + me.url = `/api2/extjs${me.baseUrl}/endpoints/${me.type}`; > + } > > if (me.isCreate) { > me.method = 'POST';