mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-04 20:49:13 +00:00
ui: allow to configure notification event -> target mapping
This commit adds a new view that allows configuring notification targets for all existing notification events (replication, updates, fencing). Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
parent
d7e1976810
commit
80c49bb56d
@ -159,6 +159,7 @@ JSSRC= \
|
||||
dc/Health.js \
|
||||
dc/Log.js \
|
||||
dc/NodeView.js \
|
||||
dc/NotificationEvents.js \
|
||||
dc/OptionView.js \
|
||||
dc/PermissionView.js \
|
||||
dc/PoolEdit.js \
|
||||
|
@ -317,6 +317,18 @@ Ext.define('PVE.dc.Config', {
|
||||
);
|
||||
}
|
||||
|
||||
if (caps.dc['Sys.Audit']) {
|
||||
me.items.push(
|
||||
{
|
||||
xtype: 'pveNotificationEvents',
|
||||
title: gettext('Notifications'),
|
||||
onlineHelp: 'notification_events',
|
||||
iconCls: 'fa fa-bell-o',
|
||||
itemId: 'notifications',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (caps.dc['Sys.Audit']) {
|
||||
me.items.push({
|
||||
xtype: 'pveDcSupport',
|
||||
|
277
www/manager6/dc/NotificationEvents.js
Normal file
277
www/manager6/dc/NotificationEvents.js
Normal file
@ -0,0 +1,277 @@
|
||||
Ext.define('PVE.dc.NotificationEventsPolicySelector', {
|
||||
alias: ['widget.pveNotificationEventsPolicySelector'],
|
||||
extend: 'Proxmox.form.KVComboBox',
|
||||
deleteEmpty: false,
|
||||
value: '__default__',
|
||||
|
||||
config: {
|
||||
warningRef: null,
|
||||
warnIfValIs: null,
|
||||
},
|
||||
|
||||
listeners: {
|
||||
change: function(field, newValue) {
|
||||
let me = this;
|
||||
if (!me.warningRef && !me.warnIfValIs) {
|
||||
return;
|
||||
}
|
||||
|
||||
let warningField = field.nextSibling(
|
||||
`displayfield[reference=${me.warningRef}]`,
|
||||
);
|
||||
warningField.setVisible(newValue === me.warnIfValIs);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Ext.define('PVE.dc.NotificationEventDisabledWarning', {
|
||||
alias: ['widget.pveNotificationEventDisabledWarning'],
|
||||
extend: 'Ext.form.field.Display',
|
||||
userCls: 'pmx-hint',
|
||||
hidden: true,
|
||||
value: gettext('Disabling notifications is not ' +
|
||||
'recommended for production systems!'),
|
||||
});
|
||||
|
||||
Ext.define('PVE.dc.NotificationEventsTargetSelector', {
|
||||
alias: ['widget.pveNotificationEventsTargetSelector'],
|
||||
extend: 'PVE.form.NotificationTargetSelector',
|
||||
fieldLabel: gettext('Notification Target'),
|
||||
allowBlank: true,
|
||||
editable: true,
|
||||
autoSelect: false,
|
||||
deleteEmpty: false,
|
||||
emptyText: `${Proxmox.Utils.defaultText} (${gettext("mail-to-root")})`,
|
||||
});
|
||||
|
||||
Ext.define('PVE.dc.NotificationEvents', {
|
||||
extend: 'Proxmox.grid.ObjectGrid',
|
||||
alias: ['widget.pveNotificationEvents'],
|
||||
|
||||
// Taken from OptionView.js, but adapted slightly.
|
||||
// The modified version allows us to have multiple rows in the ObjectGrid
|
||||
// for the same underlying property (notify).
|
||||
// Every setting is eventually stored as a property string in the
|
||||
// notify key of datacenter.cfg.
|
||||
// When updating 'notify', all properties that were already set
|
||||
// also have to be submitted, even if they were not modified.
|
||||
// This means that we need to save the old value somewhere.
|
||||
addInputPanelRow: function(name, propertyName, text, opts) {
|
||||
let me = this;
|
||||
|
||||
opts = opts || {};
|
||||
me.rows = me.rows || {};
|
||||
|
||||
me.rows[name] = {
|
||||
required: true,
|
||||
defaultValue: opts.defaultValue,
|
||||
header: text,
|
||||
renderer: opts.renderer,
|
||||
name: propertyName,
|
||||
editor: {
|
||||
xtype: 'proxmoxWindowEdit',
|
||||
width: opts.width || 400,
|
||||
subject: text,
|
||||
onlineHelp: opts.onlineHelp,
|
||||
fieldDefaults: {
|
||||
labelWidth: opts.labelWidth || 150,
|
||||
},
|
||||
setValues: function(values) {
|
||||
let value = values[propertyName];
|
||||
|
||||
if (opts.parseBeforeSet) {
|
||||
value = PVE.Parser.parsePropertyString(value);
|
||||
}
|
||||
|
||||
Ext.Array.each(this.query('inputpanel'), function(panel) {
|
||||
panel.setValues(value);
|
||||
|
||||
// Save the original value
|
||||
panel.originalValue = {
|
||||
...value,
|
||||
};
|
||||
});
|
||||
},
|
||||
url: opts.url,
|
||||
items: [{
|
||||
xtype: 'inputpanel',
|
||||
onGetValues: function(values) {
|
||||
let fields = this.config.items.map(field => field.name).filter(n => n);
|
||||
|
||||
// Restore old, unchanged values
|
||||
for (const [key, value] of Object.entries(this.originalValue)) {
|
||||
if (!fields.includes(key)) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
let value = {};
|
||||
if (Object.keys(values).length > 0) {
|
||||
value[propertyName] = PVE.Parser.printPropertyString(values);
|
||||
} else {
|
||||
Proxmox.Utils.assemble_field_data(value, { 'delete': propertyName });
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
items: opts.items,
|
||||
}],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
let me = this;
|
||||
|
||||
// Helper function for rendering the property
|
||||
// Needed since the actual value is always stored in the 'notify' property
|
||||
let render_value = (store, target_key, mode_key, default_val) => {
|
||||
let value = store.getById('notify')?.get('value') ?? {};
|
||||
let target = value[target_key] ?? gettext('mail-to-root');
|
||||
let template;
|
||||
|
||||
switch (value[mode_key]) {
|
||||
case 'always':
|
||||
template = gettext('Always, notify via target \'{0}\'');
|
||||
break;
|
||||
case 'never':
|
||||
template = gettext('Never');
|
||||
break;
|
||||
case 'auto':
|
||||
template = gettext('Automatically, notify via target \'{0}\'');
|
||||
break;
|
||||
default:
|
||||
template = gettext('{1} ({2}), notify via target \'{0}\'');
|
||||
break;
|
||||
}
|
||||
|
||||
return Ext.String.format(template, target, Proxmox.Utils.defaultText, default_val);
|
||||
};
|
||||
|
||||
me.addInputPanelRow('fencing', 'notify', gettext('Node Fencing'), {
|
||||
renderer: (value, metaData, record, rowIndex, colIndex, store) =>
|
||||
render_value(store, 'target-fencing', 'fencing', gettext('Always')),
|
||||
url: "/api2/extjs/cluster/options",
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveNotificationEventsPolicySelector',
|
||||
name: 'fencing',
|
||||
fieldLabel: gettext('Notify'),
|
||||
comboItems: [
|
||||
['__default__', `${Proxmox.Utils.defaultText} (${gettext('Always')})`],
|
||||
['always', gettext('Always')],
|
||||
['never', gettext('Never')],
|
||||
],
|
||||
warningRef: 'warning',
|
||||
warnIfValIs: 'never',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventsTargetSelector',
|
||||
name: 'target-fencing',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventDisabledWarning',
|
||||
reference: 'warning',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
me.addInputPanelRow('replication', 'notify', gettext('Replication'), {
|
||||
renderer: (value, metaData, record, rowIndex, colIndex, store) =>
|
||||
render_value(store, 'target-replication', 'replication', gettext('Always')),
|
||||
url: "/api2/extjs/cluster/options",
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveNotificationEventsPolicySelector',
|
||||
name: 'replication',
|
||||
fieldLabel: gettext('Notify'),
|
||||
comboItems: [
|
||||
['__default__', `${Proxmox.Utils.defaultText} (${gettext('Always')})`],
|
||||
['always', gettext('Always')],
|
||||
['never', gettext('Never')],
|
||||
],
|
||||
warningRef: 'warning',
|
||||
warnIfValIs: 'never',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventsTargetSelector',
|
||||
name: 'target-replication',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventDisabledWarning',
|
||||
reference: 'warning',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
me.addInputPanelRow('updates', 'notify', gettext('Package Updates'), {
|
||||
renderer: (value, metaData, record, rowIndex, colIndex, store) =>
|
||||
render_value(
|
||||
store,
|
||||
'target-package-updates',
|
||||
'package-updates',
|
||||
gettext('Automatically'),
|
||||
),
|
||||
url: "/api2/extjs/cluster/options",
|
||||
items: [
|
||||
{
|
||||
xtype: 'pveNotificationEventsPolicySelector',
|
||||
name: 'package-updates',
|
||||
fieldLabel: gettext('Notify'),
|
||||
comboItems: [
|
||||
[
|
||||
'__default__',
|
||||
`${Proxmox.Utils.defaultText} (${gettext('Automatically')})`,
|
||||
],
|
||||
['auto', gettext('Automatically')],
|
||||
['always', gettext('Always')],
|
||||
['never', gettext('Never')],
|
||||
],
|
||||
warningRef: 'warning',
|
||||
warnIfValIs: 'never',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventsTargetSelector',
|
||||
name: 'target-package-updates',
|
||||
},
|
||||
{
|
||||
xtype: 'pveNotificationEventDisabledWarning',
|
||||
reference: 'warning',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Hack: Also load the notify property to make it accessible
|
||||
// for our render functions.
|
||||
me.rows.notify = {
|
||||
visible: false,
|
||||
};
|
||||
|
||||
me.selModel = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: [{
|
||||
text: gettext('Edit'),
|
||||
xtype: 'proxmoxButton',
|
||||
disabled: true,
|
||||
handler: () => me.run_editor(),
|
||||
selModel: me.selModel,
|
||||
}],
|
||||
url: "/api2/json/cluster/options",
|
||||
editorConfig: {
|
||||
url: "/api2/extjs/cluster/options",
|
||||
},
|
||||
interval: 5000,
|
||||
cwidth1: 200,
|
||||
listeners: {
|
||||
itemdblclick: me.run_editor,
|
||||
},
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('activate', me.rstore.startUpdate);
|
||||
me.on('destroy', me.rstore.stopUpdate);
|
||||
me.on('deactivate', me.rstore.stopUpdate);
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user