From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <f.ebner@proxmox.com>
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 6111875A7B
 for <pmg-devel@lists.proxmox.com>; Tue, 13 Jul 2021 14:26:47 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 5750622B14
 for <pmg-devel@lists.proxmox.com>; Tue, 13 Jul 2021 14:26:17 +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 id 2FB5122B06
 for <pmg-devel@lists.proxmox.com>; Tue, 13 Jul 2021 14:26:16 +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 0A68E4102B
 for <pmg-devel@lists.proxmox.com>; Tue, 13 Jul 2021 14:26:16 +0200 (CEST)
From: Fabian Ebner <f.ebner@proxmox.com>
To: pmg-devel@lists.proxmox.com
Date: Tue, 13 Jul 2021 14:26:09 +0200
Message-Id: <20210713122610.72675-1-f.ebner@proxmox.com>
X-Mailer: git-send-email 2.30.2
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.511 Adjusted score from AWL reputation of From: address
 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 Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [proxmox.com]
Subject: [pmg-devel] [PATCH pmg-gui 1/2] dashboard: add node info panel
X-BeenThere: pmg-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Mail Gateway development discussion
 <pmg-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pmg-devel>, 
 <mailto:pmg-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pmg-devel/>
List-Post: <mailto:pmg-devel@lists.proxmox.com>
List-Help: <mailto:pmg-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pmg-devel>, 
 <mailto:pmg-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Tue, 13 Jul 2021 12:26:47 -0000

Essentially the same as in PBS, but needed to use 'rootfs' instead of
'root' for the disk usage, avoid 'cpu' as an itemId (already used by
the cluster resources), and get rid of the fingerprint button. Also
added the link to the repositories panel like in Dominik's pending
patch for PBS.

Rename the existing resources panel to clarify what it actually is.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
---

Depends on the APT repo patches:
https://lists.proxmox.com/pipermail/pmg-devel/2021-July/001796.html

 js/Dashboard.js          |  35 +++++++-
 js/Makefile              |   1 +
 js/dashboard/NodeInfo.js | 187 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 js/dashboard/NodeInfo.js

diff --git a/js/Dashboard.js b/js/Dashboard.js
index c92b2f0..79817b3 100644
--- a/js/Dashboard.js
+++ b/js/Dashboard.js
@@ -140,6 +140,8 @@ Ext.define('PMG.Dashboard', {
 	    var subscriptionPanel = me.lookup('subscription');
 	    subscriptionPanel.setSubStatus(subStatus);
 
+	    me.lookup('nodeInfo').setSubscriptionStatus(subStatus);
+
 	    cpu = cpu/count;
 	    mem = mem/count;
 	    hd = hd/count;
@@ -163,6 +165,15 @@ Ext.define('PMG.Dashboard', {
 	    }
 	},
 
+	updateRepositoryStatus: function(store, records, success) {
+	    if (!success) {
+		return;
+	    }
+
+	    let me = this;
+	    me.lookup('nodeInfo').setRepositoryInfo(records[0].data['standard-repos']);
+	},
+
 	init: function(view) {
 	    var me = this;
 	    var sp = Ext.state.Manager.getProvider();
@@ -272,6 +283,21 @@ Ext.define('PMG.Dashboard', {
 		    { type: 'string', name: 'receiver' },
 		],
 	    },
+	    repositories: {
+		storeid: 'dash-repositories',
+		type: 'update',
+		interval: 15000,
+		autoStart: true,
+		autoLoad: true,
+		autoDestroy: true,
+		proxy: {
+		    type: 'proxmox',
+		    url: '/api2/json/nodes/localhost/apt/repositories',
+		},
+		listeners: {
+		    load: 'updateRepositoryStatus',
+		},
+	    },
 	},
     },
 
@@ -385,7 +411,7 @@ Ext.define('PMG.Dashboard', {
 	{
 	    height: 250,
 	    iconCls: 'fa fa-tasks',
-	    title: gettext('Node Resources'),
+	    title: gettext('Cluster Resources (average)'),
 	    bodyPadding: '0 20 0 20',
 	    layout: {
 		type: 'hbox',
@@ -411,6 +437,13 @@ Ext.define('PMG.Dashboard', {
 		},
 	    ],
 	},
+	{
+	    xtype: 'pmgNodeInfoPanel',
+	    reference: 'nodeInfo',
+	    height: 250,
+	    bodyPadding: '10 5 10 5',
+	    iconCls: 'fa fa-tasks',
+	},
 	{
 	    height: 250,
 	    iconCls: 'fa fa-list',
diff --git a/js/Makefile b/js/Makefile
index 43d3ad8..f1ea2c7 100644
--- a/js/Makefile
+++ b/js/Makefile
@@ -27,6 +27,7 @@ JSSRC=							\
 	QuarantineView.js				\
 	Dashboard.js					\
 	dashboard/MailProcessing.js			\
+	dashboard/NodeInfo.js				\
 	dashboard/SubscriptionInfo.js			\
 	dashboard/MiniGraph.js				\
 	VersionInfo.js					\
diff --git a/js/dashboard/NodeInfo.js b/js/dashboard/NodeInfo.js
new file mode 100644
index 0000000..c286558
--- /dev/null
+++ b/js/dashboard/NodeInfo.js
@@ -0,0 +1,187 @@
+Ext.define('PMG.NodeInfoPanel', {
+    extend: 'Proxmox.panel.StatusView',
+    alias: 'widget.pmgNodeInfoPanel',
+
+    layout: {
+	type: 'table',
+	columns: 2,
+	tableAttrs: {
+	    style: {
+		width: '100%',
+	    },
+	},
+    },
+
+    defaults: {
+	xtype: 'pmxInfoWidget',
+	padding: '0 10 5 10',
+    },
+
+    viewModel: {
+	data: {
+	    subscriptionActive: '',
+	    noSubscriptionRepo: '',
+	    enterpriseRepo: '',
+	    testRepo: '',
+	},
+	formulas: {
+	    repoStatus: function(get) {
+		if (get('subscriptionActive') === '' || get('enterpriseRepo') === '') {
+		    return '';
+		}
+
+		if (get('noSubscriptionRepo') || get('testRepo')) {
+		    return 'non-production';
+		} else if (get('subscriptionActive') && get('enterpriseRepo')) {
+		    return 'ok';
+		} else if (!get('subscriptionActive') && get('enterpriseRepo')) {
+		    return 'no-sub';
+		} else if (!get('enterpriseRepo') || !get('noSubscriptionRepo') || !get('testRepo')) {
+		    return 'no-repo';
+		}
+		return 'unknown';
+	    },
+	    repoStatusMessage: function(get) {
+		const status = get('repoStatus');
+		let repoLink = ` <a data-qtip="${gettext("Open Repositories Panel")}"
+		    href="#pmgServerAdministration:aptrepositories">
+		    <i class="fa black fa-chevron-right"></i>
+		    </a>`;
+		return Proxmox.Utils.formatNodeRepoStatus(status, 'Proxmox Mail Gateway') + repoLink;
+	    },
+	},
+    },
+
+    items: [
+	{
+	    itemId: 'nodecpu',
+	    iconCls: 'fa fa-fw pmx-itype-icon-processor pmx-icon',
+	    title: gettext('CPU usage'),
+	    valueField: 'cpu',
+	    maxField: 'cpuinfo',
+	    renderer: Proxmox.Utils.render_node_cpu_usage,
+	},
+	{
+	    itemId: 'wait',
+	    iconCls: 'pmx-icon-size fa fa-fw fa-clock-o',
+	    title: gettext('IO delay'),
+	    valueField: 'wait',
+	},
+	{
+	    xtype: 'box',
+	    colspan: 2,
+	    padding: '0 0 20 0',
+	},
+	{
+	    iconCls: 'fa fa-fw pmx-itype-icon-memory pmx-icon',
+	    itemId: 'memory',
+	    title: gettext('RAM usage'),
+	    valueField: 'memory',
+	    maxField: 'memory',
+	    renderer: Proxmox.Utils.render_node_size_usage,
+	},
+	{
+	    itemId: 'load',
+	    iconCls: 'pmx-icon-size fa fa-fw fa-tasks',
+	    title: gettext('Load average'),
+	    printBar: false,
+	    textField: 'loadavg',
+	},
+	{
+	    iconCls: 'pmx-icon-size fa fa-fw fa-hdd-o',
+	    itemId: 'rootfs',
+	    title: gettext('HD space') + ' (root)',
+	    valueField: 'rootfs',
+	    maxField: 'rootfs',
+	    renderer: Proxmox.Utils.render_node_size_usage,
+	},
+	{
+	    iconCls: 'pmx-icon-size fa fa-fw fa-refresh',
+	    itemId: 'swap',
+	    printSize: true,
+	    title: gettext('SWAP usage'),
+	    valueField: 'swap',
+	    maxField: 'swap',
+	    renderer: Proxmox.Utils.render_node_size_usage,
+	},
+	{
+	    xtype: 'box',
+	    colspan: 2,
+	    padding: '0 0 20 0',
+	},
+	{
+	    itemId: 'cpus',
+	    colspan: 2,
+	    printBar: false,
+	    title: gettext('CPU(s)'),
+	    textField: 'cpuinfo',
+	    renderer: Proxmox.Utils.render_cpu_model,
+	    value: '',
+	},
+	{
+	    itemId: 'kversion',
+	    colspan: 2,
+	    title: gettext('Kernel Version'),
+	    printBar: false,
+	    textField: 'kversion',
+	    value: '',
+	},
+	{
+	    itemId: 'repositoryStatus',
+	    colspan: 2,
+	    printBar: false,
+	    title: gettext('Repository Status'),
+	    setValue: function(value) { // for binding below
+		this.updateValue(value);
+	    },
+	    bind: {
+		value: '{repoStatusMessage}',
+	    },
+	},
+    ],
+
+    updateTitle: function() {
+	var me = this;
+	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
+	me.setTitle(Proxmox.NodeName + ' (' + gettext('Uptime') + ': ' + uptime + ')');
+    },
+
+    setRepositoryInfo: function(standardRepos) {
+	let me = this;
+	let vm = me.getViewModel();
+
+	for (const standardRepo of standardRepos) {
+	    const handle = standardRepo.handle;
+	    const status = standardRepo.status;
+
+	    if (handle === "enterprise") {
+		vm.set('enterpriseRepo', status);
+	    } else if (handle === "no-subscription") {
+		vm.set('noSubscriptionRepo', status);
+	    } else if (handle === "test") {
+		vm.set('testRepo', status);
+	    }
+	}
+    },
+
+    setSubscriptionStatus: function(status) {
+	let me = this;
+	let vm = me.getViewModel();
+
+	vm.set('subscriptionActive', status);
+    },
+
+    initComponent: function() {
+	let me = this;
+
+	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
+	    interval: 3000,
+	    url: '/api2/json/nodes/localhost/status',
+	    autoStart: true,
+	});
+
+	me.callParent();
+
+	me.on('destroy', function() { me.rstore.stopUpdate(); });
+    },
+});
-- 
2.30.2