notification: add gui for notification groups

The GUI is based on the 'plugin-based' dialog window EndpointEditBase
that was introduced in an earlier commit.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Lukas Wagner 2023-08-03 14:17:16 +02:00 committed by Wolfgang Bumiller
parent 6669a59fd1
commit ea5aa12261
4 changed files with 185 additions and 1 deletions

View File

@ -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 \

View File

@ -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: {

View File

@ -0,0 +1,174 @@
Ext.define('Proxmox.panel.NotificationGroupEditPanel', {
extend: 'Proxmox.panel.InputPanel',
xtype: 'pmxNotificationGroupEditPanel',
mixins: ['Proxmox.Mixin.CBind'],
type: 'group',
items: [
{
xtype: 'pmxDisplayEditField',
name: 'name',
cbind: {
value: '{name}',
editable: '{isCreate}',
},
fieldLabel: gettext('Group Name'),
allowBlank: false,
},
{
xtype: 'pmxNotificationEndpointSelector',
name: 'endpoint',
allowBlank: false,
},
{
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',
},
padding: '0 0 10 0',
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();
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 [];
},
initComponent: function() {
let me = this;
me.callParent();
me.initField();
},
});

View File

@ -18,7 +18,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';