mirror of
https://git.proxmox.com/git/proxmox-widget-toolkit
synced 2025-05-23 09:11:03 +00:00
notification: add gui for sendmail notification endpoints
This commit adds a new panel 'NotificationConfigView' that is supposed to be embedded in the datacenter configuration side-bar. This new view lists all notification endpoints, allowing to add/modify/delete/test them. Furthermore, this commits adds the dialog for adding/modifying sendmail endpoints. The dialog is 'plugin-in' based, meaning that it consists of a base window (EndpointEditBase) and a panel that holds the actual fields for the endpoint type configuration. This will show be beneficial once the GUI for other endpoint types is added. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> Reviewed-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
a60c8dc0c0
commit
84f70dfaad
@ -22,6 +22,7 @@ JSSRC= \
|
|||||||
data/ObjectStore.js \
|
data/ObjectStore.js \
|
||||||
data/RRDStore.js \
|
data/RRDStore.js \
|
||||||
data/TimezoneStore.js \
|
data/TimezoneStore.js \
|
||||||
|
data/model/NotificationConfig.js \
|
||||||
data/model/Realm.js \
|
data/model/Realm.js \
|
||||||
data/model/Certificates.js \
|
data/model/Certificates.js \
|
||||||
data/model/ACME.js \
|
data/model/ACME.js \
|
||||||
@ -59,6 +60,7 @@ JSSRC= \
|
|||||||
panel/InfoWidget.js \
|
panel/InfoWidget.js \
|
||||||
panel/LogView.js \
|
panel/LogView.js \
|
||||||
panel/NodeInfoRepoStatus.js \
|
panel/NodeInfoRepoStatus.js \
|
||||||
|
panel/NotificationConfigView.js \
|
||||||
panel/JournalView.js \
|
panel/JournalView.js \
|
||||||
panel/PermissionView.js \
|
panel/PermissionView.js \
|
||||||
panel/PruneKeepPanel.js \
|
panel/PruneKeepPanel.js \
|
||||||
@ -68,6 +70,7 @@ JSSRC= \
|
|||||||
panel/ACMEAccount.js \
|
panel/ACMEAccount.js \
|
||||||
panel/ACMEPlugin.js \
|
panel/ACMEPlugin.js \
|
||||||
panel/ACMEDomains.js \
|
panel/ACMEDomains.js \
|
||||||
|
panel/SendmailEditPanel.js \
|
||||||
panel/StatusView.js \
|
panel/StatusView.js \
|
||||||
panel/TfaView.js \
|
panel/TfaView.js \
|
||||||
panel/NotesView.js \
|
panel/NotesView.js \
|
||||||
@ -83,6 +86,7 @@ JSSRC= \
|
|||||||
window/ACMEAccount.js \
|
window/ACMEAccount.js \
|
||||||
window/ACMEPluginEdit.js \
|
window/ACMEPluginEdit.js \
|
||||||
window/ACMEDomains.js \
|
window/ACMEDomains.js \
|
||||||
|
window/EndpointEditBase.js \
|
||||||
window/FileBrowser.js \
|
window/FileBrowser.js \
|
||||||
window/AuthEditBase.js \
|
window/AuthEditBase.js \
|
||||||
window/AuthEditOpenId.js \
|
window/AuthEditOpenId.js \
|
||||||
|
@ -37,6 +37,14 @@ Ext.define('Proxmox.Schema', { // a singleton
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
notificationEndpointTypes: {
|
||||||
|
sendmail: {
|
||||||
|
name: gettext('Sendmail'),
|
||||||
|
ipanel: 'pmxSendmailEditPanel',
|
||||||
|
iconCls: 'fa-envelope-o',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
pxarFileTypes: {
|
pxarFileTypes: {
|
||||||
b: { icon: 'cube', label: gettext('Block Device') },
|
b: { icon: 'cube', label: gettext('Block Device') },
|
||||||
c: { icon: 'tty', label: gettext('Character Device') },
|
c: { icon: 'tty', label: gettext('Character Device') },
|
||||||
|
8
src/data/model/NotificationConfig.js
Normal file
8
src/data/model/NotificationConfig.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Ext.define('proxmox-notification-endpoints', {
|
||||||
|
extend: 'Ext.data.Model',
|
||||||
|
fields: ['name', 'type', 'comment'],
|
||||||
|
proxy: {
|
||||||
|
type: 'proxmox',
|
||||||
|
},
|
||||||
|
idProperty: 'name',
|
||||||
|
});
|
196
src/panel/NotificationConfigView.js
Normal file
196
src/panel/NotificationConfigView.js
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
Ext.define('Proxmox.panel.NotificationConfigView', {
|
||||||
|
extend: 'Ext.panel.Panel',
|
||||||
|
alias: 'widget.pmxNotificationConfigView',
|
||||||
|
mixins: ['Proxmox.Mixin.CBind'],
|
||||||
|
layout: {
|
||||||
|
type: 'border',
|
||||||
|
},
|
||||||
|
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
region: 'center',
|
||||||
|
border: false,
|
||||||
|
xtype: 'pmxNotificationEndpointView',
|
||||||
|
cbind: {
|
||||||
|
baseUrl: '{baseUrl}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Ext.define('Proxmox.panel.NotificationEndpointView', {
|
||||||
|
extend: 'Ext.grid.Panel',
|
||||||
|
alias: 'widget.pmxNotificationEndpointView',
|
||||||
|
|
||||||
|
title: gettext('Notification Targets'),
|
||||||
|
|
||||||
|
controller: {
|
||||||
|
xclass: 'Ext.app.ViewController',
|
||||||
|
|
||||||
|
openEditWindow: function(endpointType, endpoint) {
|
||||||
|
let me = this;
|
||||||
|
|
||||||
|
if (endpoint === 'mail-to-root') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ext.create('Proxmox.window.EndpointEditBase', {
|
||||||
|
baseUrl: me.getView().baseUrl,
|
||||||
|
type: endpointType,
|
||||||
|
|
||||||
|
name: endpoint,
|
||||||
|
autoShow: true,
|
||||||
|
listeners: {
|
||||||
|
destroy: () => me.reload(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
openEditForSelectedItem: function() {
|
||||||
|
let me = this;
|
||||||
|
let view = me.getView();
|
||||||
|
|
||||||
|
let selection = view.getSelection();
|
||||||
|
if (selection.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.openEditWindow(selection[0].data.type, selection[0].data.name);
|
||||||
|
},
|
||||||
|
|
||||||
|
reload: function() {
|
||||||
|
let me = this;
|
||||||
|
let view = me.getView();
|
||||||
|
view.getStore().rstore.load();
|
||||||
|
},
|
||||||
|
|
||||||
|
testEndpoint: function() {
|
||||||
|
let me = this;
|
||||||
|
let view = me.getView();
|
||||||
|
|
||||||
|
let selection = view.getSelection();
|
||||||
|
if (selection.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = selection[0].data.name;
|
||||||
|
|
||||||
|
Ext.Msg.confirm(
|
||||||
|
gettext("Notification Target Test"),
|
||||||
|
gettext(`Do you want to send a test notification to '${target}'?`),
|
||||||
|
function(decision) {
|
||||||
|
if (decision !== "yes") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Proxmox.Utils.API2Request({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${view.baseUrl}/targets/${target}/test`,
|
||||||
|
|
||||||
|
success: function(response, opt) {
|
||||||
|
Ext.Msg.show({
|
||||||
|
title: gettext('Notification Target Test'),
|
||||||
|
message: gettext(`Sent test notification to '${target}'.`),
|
||||||
|
buttons: Ext.Msg.OK,
|
||||||
|
icon: Ext.Msg.INFO,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
autoErrorAlert: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
listeners: {
|
||||||
|
itemdblclick: 'openEditForSelectedItem',
|
||||||
|
activate: 'reload',
|
||||||
|
},
|
||||||
|
|
||||||
|
emptyText: gettext('No notification targets configured'),
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
dataIndex: 'name',
|
||||||
|
text: gettext('Target Name'),
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'type',
|
||||||
|
text: gettext('Type'),
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'comment',
|
||||||
|
text: gettext('Comment'),
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
store: {
|
||||||
|
type: 'diff',
|
||||||
|
autoDestroy: true,
|
||||||
|
autoDestroyRstore: true,
|
||||||
|
rstore: {
|
||||||
|
type: 'update',
|
||||||
|
storeid: 'proxmox-notification-endpoints',
|
||||||
|
model: 'proxmox-notification-endpoints',
|
||||||
|
autoStart: true,
|
||||||
|
},
|
||||||
|
sorters: 'name',
|
||||||
|
},
|
||||||
|
|
||||||
|
initComponent: function() {
|
||||||
|
let me = this;
|
||||||
|
|
||||||
|
let menuItems = [];
|
||||||
|
for (const [endpointType, config] of Object.entries(
|
||||||
|
Proxmox.Schema.notificationEndpointTypes).sort()) {
|
||||||
|
menuItems.push({
|
||||||
|
text: config.name,
|
||||||
|
iconCls: 'fa fa-fw ' + (config.iconCls || 'fa-bell-o'),
|
||||||
|
handler: () => me.controller.openEditWindow(endpointType),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ext.apply(me, {
|
||||||
|
tbar: [
|
||||||
|
{
|
||||||
|
text: gettext('Add'),
|
||||||
|
menu: menuItems,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxButton',
|
||||||
|
text: gettext('Modify'),
|
||||||
|
handler: 'openEditForSelectedItem',
|
||||||
|
enableFn: rec => rec.data.name !== 'mail-to-root',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxStdRemoveButton',
|
||||||
|
callback: 'reload',
|
||||||
|
enableFn: rec => rec.data.name !== 'mail-to-root',
|
||||||
|
getUrl: function(rec) {
|
||||||
|
if (rec.data.type === 'group') {
|
||||||
|
return `${me.baseUrl}/groups/${rec.getId()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${me.baseUrl}/endpoints/${rec.data.type}/${rec.getId()}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'-',
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxButton',
|
||||||
|
text: gettext('Test'),
|
||||||
|
handler: 'testEndpoint',
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
me.callParent();
|
||||||
|
me.store.rstore.proxy.setUrl(`/api2/json/${me.baseUrl}/targets`);
|
||||||
|
},
|
||||||
|
});
|
130
src/panel/SendmailEditPanel.js
Normal file
130
src/panel/SendmailEditPanel.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
Ext.define('Proxmox.panel.SendmailEditPanel', {
|
||||||
|
extend: 'Proxmox.panel.InputPanel',
|
||||||
|
xtype: 'pmxSendmailEditPanel',
|
||||||
|
mixins: ['Proxmox.Mixin.CBind'],
|
||||||
|
|
||||||
|
type: 'sendmail',
|
||||||
|
|
||||||
|
mailValidator: function() {
|
||||||
|
let mailto_user = this.down(`[name=mailto-user]`);
|
||||||
|
let mailto = this.down(`[name=mailto]`);
|
||||||
|
|
||||||
|
if (!mailto_user.getValue()?.length && !mailto.getValue()) {
|
||||||
|
return gettext('Either mailto or mailto-user must be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
xtype: 'pmxDisplayEditField',
|
||||||
|
name: 'name',
|
||||||
|
cbind: {
|
||||||
|
value: '{name}',
|
||||||
|
editable: '{isCreate}',
|
||||||
|
},
|
||||||
|
fieldLabel: gettext('Endpoint Name'),
|
||||||
|
allowBlank: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'pmxUserSelector',
|
||||||
|
name: 'mailto-user',
|
||||||
|
reference: 'mailto-user',
|
||||||
|
multiSelect: true,
|
||||||
|
allowBlank: true,
|
||||||
|
editable: false,
|
||||||
|
skipEmptyText: true,
|
||||||
|
fieldLabel: gettext('User(s)'),
|
||||||
|
cbind: {
|
||||||
|
deleteEmpty: '{!isCreate}',
|
||||||
|
},
|
||||||
|
validator: function() {
|
||||||
|
return this.up('pmxSendmailEditPanel').mailValidator();
|
||||||
|
},
|
||||||
|
listConfig: {
|
||||||
|
width: 600,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: gettext('User'),
|
||||||
|
sortable: true,
|
||||||
|
dataIndex: 'userid',
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: gettext('E-Mail'),
|
||||||
|
sortable: true,
|
||||||
|
dataIndex: 'email',
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: gettext('Comment'),
|
||||||
|
sortable: false,
|
||||||
|
dataIndex: 'comment',
|
||||||
|
renderer: Ext.String.htmlEncode,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxtextfield',
|
||||||
|
fieldLabel: gettext('Additional Recipient(s)'),
|
||||||
|
name: 'mailto',
|
||||||
|
reference: 'mailto',
|
||||||
|
allowBlank: true,
|
||||||
|
cbind: {
|
||||||
|
deleteEmpty: '{!isCreate}',
|
||||||
|
},
|
||||||
|
autoEl: {
|
||||||
|
tag: 'div',
|
||||||
|
'data-qtip': gettext(
|
||||||
|
'Multiple recipients must be separated by spaces, commas or semicolons',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
validator: function() {
|
||||||
|
return this.up('pmxSendmailEditPanel').mailValidator();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxtextfield',
|
||||||
|
name: 'comment',
|
||||||
|
fieldLabel: gettext('Comment'),
|
||||||
|
cbind: {
|
||||||
|
deleteEmpty: '{!isCreate}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
advancedItems: [
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxtextfield',
|
||||||
|
fieldLabel: gettext('Author'),
|
||||||
|
name: 'author',
|
||||||
|
allowBlank: true,
|
||||||
|
emptyText: gettext('Proxmox VE'),
|
||||||
|
cbind: {
|
||||||
|
deleteEmpty: '{!isCreate}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
xtype: 'proxmoxtextfield',
|
||||||
|
fieldLabel: gettext('From Address'),
|
||||||
|
name: 'from-address',
|
||||||
|
allowBlank: true,
|
||||||
|
emptyText: gettext('Defaults to datacenter configuration, or root@$hostname'),
|
||||||
|
cbind: {
|
||||||
|
deleteEmpty: '{!isCreate}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
onGetValues: (values) => {
|
||||||
|
if (values.mailto) {
|
||||||
|
values.mailto = values.mailto.split(/[\s,;]+/);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
});
|
52
src/window/EndpointEditBase.js
Normal file
52
src/window/EndpointEditBase.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Ext.define('Proxmox.window.EndpointEditBase', {
|
||||||
|
extend: 'Proxmox.window.Edit',
|
||||||
|
|
||||||
|
isAdd: true,
|
||||||
|
|
||||||
|
fieldDefaults: {
|
||||||
|
labelWidth: 120,
|
||||||
|
},
|
||||||
|
|
||||||
|
width: 700,
|
||||||
|
|
||||||
|
initComponent: function() {
|
||||||
|
let me = this;
|
||||||
|
|
||||||
|
me.isCreate = !me.name;
|
||||||
|
|
||||||
|
if (!me.baseUrl) {
|
||||||
|
throw "baseUrl not set";
|
||||||
|
}
|
||||||
|
|
||||||
|
me.url = `/api2/extjs${me.baseUrl}/endpoints/${me.type}`;
|
||||||
|
|
||||||
|
if (me.isCreate) {
|
||||||
|
me.method = 'POST';
|
||||||
|
} else {
|
||||||
|
me.url += `/${me.name}`;
|
||||||
|
me.method = 'PUT';
|
||||||
|
}
|
||||||
|
|
||||||
|
let endpointConfig = Proxmox.Schema.notificationEndpointTypes[me.type];
|
||||||
|
if (!endpointConfig) {
|
||||||
|
throw 'unknown endpoint type';
|
||||||
|
}
|
||||||
|
|
||||||
|
me.subject = endpointConfig.name;
|
||||||
|
|
||||||
|
Ext.apply(me, {
|
||||||
|
items: [{
|
||||||
|
name: me.name,
|
||||||
|
xtype: endpointConfig.ipanel,
|
||||||
|
isCreate: me.isCreate,
|
||||||
|
type: me.type,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
me.callParent();
|
||||||
|
|
||||||
|
if (!me.isCreate) {
|
||||||
|
me.load();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user