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 04F887045A for ; Fri, 2 Apr 2021 13:21:34 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 024C4E319 for ; Fri, 2 Apr 2021 13:21:03 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (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 DFD71E26B for ; Fri, 2 Apr 2021 13:20:58 +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 A72D1415E8 for ; Fri, 2 Apr 2021 13:20:58 +0200 (CEST) From: Fabian Ebner To: pbs-devel@lists.proxmox.com Date: Fri, 2 Apr 2021 13:20:51 +0200 Message-Id: <20210402112051.14628-11-f.ebner@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210402112051.14628-1-f.ebner@proxmox.com> References: <20210402112051.14628-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.007 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust 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. [values.name] Subject: [pbs-devel] [PATCH v4 widget-toolkit 10/10] APT repositories: add warnings X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Apr 2021 11:21:34 -0000 Signed-off-by: Fabian Ebner --- Changes from v3: * adapt to API changes, handle the special "ignore-pre-upgrade" warning and show when a repository has an offical URI * use digest for checkrepositories call * let the main panel be the target for monStoreErrrors * The main warning didn't look good as a label, especially when there are also unparsable files. Having it as a panel title felt more uniform and prominent, but I'm open for alternatives. src/node/APTRepositories.js | 167 +++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 2 deletions(-) diff --git a/src/node/APTRepositories.js b/src/node/APTRepositories.js index 0ad034c..a2ff0fe 100644 --- a/src/node/APTRepositories.js +++ b/src/node/APTRepositories.js @@ -3,6 +3,7 @@ Ext.define('apt-repolist', { fields: [ 'Path', 'Number', + 'OfficialHost', 'FileType', 'Enabled', 'Comment', @@ -56,6 +57,22 @@ Ext.define('Proxmox.node.APTRepositoriesGrid', { sortableColumns: false, columns: [ + { + header: gettext('Official'), + dataIndex: 'OfficialHost', + renderer: function(value, cell, record) { + let icon = (cls) => ``; + + if (value === undefined || value === null) { + return icon('fa-question-circle-o'); + } + if (!value) { + return icon('fa-times critical'); + } + return icon('fa-check good'); + }, + width: 70, + }, { header: gettext('Enabled'), dataIndex: 'Enabled', @@ -128,9 +145,87 @@ Ext.define('Proxmox.node.APTRepositoriesGrid', { }, ], + check_repositories: function(gridData) { + let me = this; + let panel = me.up('proxmoxNodeAPTRepositories'); + let vm = panel.getViewModel(); + + Proxmox.Utils.API2Request({ + url: `/nodes/${me.nodename}/apt/checkrepositories`, + method: 'GET', + params: { + digest: panel.digest, + }, + failure: function(response, opts) { + me.rowBodyFeature.getAdditionalData = function() { + return { + rowBody: undefined, + rowBodyCls: Ext.baseCSSPrefix + 'grid-row-body-hidden', + }; + }; + me.store.loadData(gridData); + Ext.Msg.alert(gettext('Error'), response.htmlStatus); + }, + success: function(response, opts) { + const data = response.result.data; + + vm.set('enterpriseRepo', data.enterprise); + vm.set('noSubscriptionRepo', data.nosubscription); + + let warnings = {}; + let officialHosts = {}; + + let addLine = function(obj, key, line) { + if (obj[key]) { + obj[key] += "\n"; + obj[key] += line; + } else { + obj[key] = line; + } + }; + + for (const info of data.infos) { + const key = `${info.path}:${info.number}`; + if (info.kind === 'warning' || + (info.kind === 'ignore-pre-upgrade-warning' && !me.majorUpgradeAllowed)) { + addLine(warnings, key, gettext('Warning') + ": " + info.message); + } else if (info.kind === 'badge' && info.message === 'official host name') { + officialHosts[key] = true; + } + } + + gridData.forEach(function(record) { + const key = `${record.Path}:${record.Number}`; + record.OfficialHost = !!officialHosts[key]; + }); + + me.rowBodyFeature.getAdditionalData = function(innerData, rowIndex, record, orig) { + let headerCt = this.view.headerCt; + let colspan = headerCt.getColumnCount(); + + const key = `${innerData.Path}:${innerData.Number}`; + const warning_text = warnings[key]; + + return { + rowBody: '
' + + Ext.String.htmlEncode(warning_text) + '
', + rowBodyCls: warning_text ? '' : Ext.baseCSSPrefix + 'grid-row-body-hidden', + rowBodyColspan: colspan, + }; + }; + + me.store.loadData(gridData); + }, + }); + }, + initComponent: function() { let me = this; + if (!me.nodename) { + throw "no node name specified"; + } + let store = Ext.create('Ext.data.Store', { model: 'apt-repolist', groupField: 'Path', @@ -142,6 +237,8 @@ Ext.define('Proxmox.node.APTRepositoriesGrid', { ], }); + let rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {}); + let groupingFeature = Ext.create('Ext.grid.feature.Grouping', { groupHeaderTpl: '{[ "File: " + values.name ]} ({rows.length} ' + 'repositor{[values.rows.length > 1 ? "ies" : "y"]})', @@ -153,7 +250,8 @@ Ext.define('Proxmox.node.APTRepositoriesGrid', { Ext.apply(me, { store: store, selModel: sm, - features: [groupingFeature], + rowBodyFeature: rowBodyFeature, + features: [groupingFeature, rowBodyFeature], }); me.callParent(); @@ -164,19 +262,59 @@ Ext.define('Proxmox.node.APTRepositories', { extend: 'Ext.panel.Panel', xtype: 'proxmoxNodeAPTRepositories', + mixins: ['Proxmox.Mixin.CBind'], digest: undefined, viewModel: { data: { errorCount: 0, + subscriptionActive: '', + noSubscriptionRepo: '', + enterpriseRepo: '', }, formulas: { noErrors: (get) => get('errorCount') === 0, + mainWarning: function(get) { + if (get('subscriptionActive') === '' || + get('noSubscriptionRepo') === '' || + get('enterpriseRepo') === '') { + return ''; + } + + let withStyle = (msg) => "
" + gettext('Warning') + ': ' + msg + "
"; + + if (!get('subscriptionActive') && get('enterpriseRepo')) { + return withStyle(gettext('The enterprise repository is ' + + 'configured, but there is no active subscription!')); + } + + if (get('noSubscriptionRepo')) { + return withStyle(gettext('The no-subscription repository is ' + + 'not recommended for production use!')); + } + + if (!get('enterpriseRepo') && !get('noSubscriptionRepo')) { + return withStyle(gettext('Neither the enterprise repository ' + + 'nor the no-subscription repository is configured!')); + } + + return ''; + }, }, }, items: [ + { + title: gettext('Warning'), + name: 'repositoriesMainWarning', + xtype: 'panel', + bind: { + title: '{mainWarning}', + hidden: '{!mainWarning}', + }, + }, { xtype: 'proxmoxNodeAPTRepositoriesErrors', name: 'repositoriesErrors', @@ -188,9 +326,32 @@ Ext.define('Proxmox.node.APTRepositories', { { xtype: 'proxmoxNodeAPTRepositoriesGrid', name: 'repositoriesGrid', + cbind: { + nodename: '{nodename}', + majorUpgradeAllowed: '{majorUpgradeAllowed}', + }, }, ], + check_subscription: function() { + let me = this; + let vm = me.getViewModel(); + + Proxmox.Utils.API2Request({ + url: `/nodes/${me.nodename}/subscription`, + method: 'GET', + failure: function(response, opts) { + Ext.Msg.alert(gettext('Error'), response.htmlStatus); + }, + success: function(response, opts) { + const res = response.result; + const subscription = !(res === null || res === undefined || + !res || res.data.status.toLowerCase() !== 'active'); + vm.set('subscriptionActive', subscription); + }, + }); + }, + listeners: { activate: function() { let me = this; @@ -221,11 +382,13 @@ Ext.define('Proxmox.node.APTRepositories', { me.digest = digest; - repoGrid.store.loadData(gridData); + repoGrid.check_repositories(gridData); // loads gridData after updating it vm.set('errorCount', errors.length); errorGrid.store.loadData(errors); }); + + me.check_subscription(); }, }, -- 2.20.1