return false;
}
- if (!info.status) {
+ if (info.status) {
return Ext.String.format(gettext('{0} is already configured'), renderedValue);
}
return valid;
xtype: 'proxmoxNodeAPTRepositoriesErrors',
- title: gettext('Errors'),
-
store: {},
- border: false,
+ scrollable: true,
viewConfig: {
stripeRows: false,
- getRowClass: () => 'proxmox-invalid-row',
+ getRowClass: (record) => {
+ switch (record.data.status) {
+ case 'warning': return 'proxmox-warning-row';
+ case 'critical': return 'proxmox-invalid-row';
+ default: return '';
+ }
+ },
},
+ hideHeaders: true,
+
columns: [
{
- header: gettext('File'),
- dataIndex: 'path',
- renderer: value => `<i class='pve-grid-fa fa fa-fw fa-exclamation-triangle'></i>${value}`,
- width: 350,
+ dataIndex: 'status',
+ renderer: (value) => `<i class="fa fa-fw ${Proxmox.Utils.get_health_icon(value, true)}"></i>`,
+ width: 50,
},
{
- header: gettext('Error'),
- dataIndex: 'error',
+ dataIndex: 'message',
flex: 1,
},
],
{
header: gettext('Components'),
dataIndex: 'Components',
- renderer: function(components, cell, record) {
- return components.join(' ');
+ renderer: function(components, metaData, record) {
+ let err = '';
+ if (components.length === 1) {
+ // FIXME: this should be a flag set to the actual repsotiories, i.e., a tristate
+ // like production-ready = <yes|no|other> (Option<bool>)
+ if (components[0].match(/\w+(-no-subscription|test)\s*$/i)) {
+ metaData.tdCls = 'proxmox-warning-row';
+ err = '<i class="fa fa-fw warning fa-exclamation-circle"></i> ';
+
+ let qtip = components[0].match(/no-subscription/)
+ ? gettext('The no-subscription repository is NOT production-ready')
+ : gettext('The test repository may contain unstable updates')
+ ;
+ metaData.tdAttr = `data-qtip="${Ext.htmlEncode(qtip)}"`;
+ }
+ }
+ return components.join(' ') + err;
},
width: 170,
},
let rec = selection[0];
let vm = me.getViewModel();
vm.set('selectionenabled', rec.get('Enabled'));
+ vm.notify();
+ },
+
+ updateState: function() {
+ let me = this;
+ let vm = me.getViewModel();
+
+ let store = vm.get('errorstore');
+ store.removeAll();
+
+ let status = 'good'; // start with best, the helper below will downgrade if needed
+ let text = gettext('All OK, you have production-ready repositories configured!');
+
+ let errors = vm.get('errors');
+ errors.forEach((error) => {
+ status = 'critical';
+ store.add({
+ status: 'critical',
+ message: `${error.path} - ${error.error}`,
+ });
+ });
+
+ let addGood = message => store.add({ status: 'good', message });
+
+ let addWarn = message => {
+ if (status === 'good') {
+ status = 'warning';
+ text = message;
+ }
+ store.add({ status: 'warning', message });
+ };
+
+ let activeSubscription = vm.get('subscriptionActive');
+ let enterprise = vm.get('enterpriseRepo');
+ let nosubscription = vm.get('noSubscriptionRepo');
+ let test = vm.get('testRepo');
+ let wrongSuites = vm.get('suitesWarning');
+
+ if (!enterprise && !nosubscription && !test) {
+ addWarn(Ext.String.format(gettext('No {0} repository is enabled!'), vm.get('product')));
+ } else if (enterprise && !nosubscription && !test && activeSubscription) {
+ addGood(Ext.String.format(gettext('You get supported updates for {0}'), vm.get('product')));
+ } else if (nosubscription || test) {
+ addGood(Ext.String.format(gettext('You get updates for {0}'), vm.get('product')));
+ }
+
+ if (wrongSuites) {
+ addWarn(gettext('Some Suites are misconfigured'));
+ }
+
+ if (!activeSubscription && enterprise) {
+ addWarn(gettext('The enterprise repository is enabled, but there is no active subscription!'));
+ }
+
+ if (nosubscription) {
+ addWarn(gettext('The no-subscription repository is not recommended for production use!'));
+ }
+
+ if (test) {
+ addWarn(gettext('The test repository is not recommended for production use!'));
+ }
+
+ if (errors.length > 0) {
+ text = gettext('Error parsing repositories');
+ }
+
+ let iconCls = Proxmox.Utils.get_health_icon(status, true);
+
+ vm.set('state', {
+ iconCls,
+ text,
+ });
},
},
viewModel: {
data: {
product: 'Proxmox VE', // default
- errorCount: 0,
+ errors: [],
+ suitesWarning: false,
subscriptionActive: '',
noSubscriptionRepo: '',
enterpriseRepo: '',
+ testRepo: '',
selectionenabled: false,
+ state: {},
},
formulas: {
- noErrors: (get) => get('errorCount') === 0,
enableButtonText: (get) => get('selectionenabled')
? gettext('Disable') : gettext('Enable'),
- mainWarning: function(get) {
- // Not yet initialized
- if (get('subscriptionActive') === '' ||
- get('enterpriseRepo') === '') {
- return '';
- }
-
- let icon = `<i class='fa fa-fw fa-exclamation-triangle critical'></i>`;
- let fmt = (msg) => `<div class="black">${icon}${gettext('Warning')}: ${msg}</div>`;
-
- if (!get('subscriptionActive') && get('enterpriseRepo')) {
- return fmt(gettext('The enterprise repository is enabled, but there is no active subscription!'));
- }
-
- if (get('noSubscriptionRepo')) {
- return fmt(gettext('The no-subscription repository is not recommended for production use!'));
- }
-
- if (!get('enterpriseRepo') && !get('noSubscriptionRepo')) {
- let msg = Ext.String.format(gettext('No {0} repository is enabled!'), get('product'));
- return fmt(msg);
- }
-
- return '';
+ },
+ stores: {
+ errorstore: {
+ fields: ['status', 'message'],
},
},
},
items: [
{
- xtype: 'header',
- baseCls: 'x-panel-header',
- bind: {
- hidden: '{!mainWarning}',
- title: '{mainWarning}',
- },
- },
- {
- xtype: 'box',
- bind: {
- hidden: '{!mainWarning}',
- },
- height: 5,
- },
- {
- xtype: 'proxmoxNodeAPTRepositoriesErrors',
- name: 'repositoriesErrors',
- hidden: true,
- padding: '0 0 5 0',
- bind: {
- hidden: '{noErrors}',
+ xtype: 'panel',
+ border: false,
+ layout: {
+ type: 'hbox',
+ align: 'stretch',
},
+ height: 200,
+ title: gettext('Status'),
+ items: [
+ {
+ xtype: 'box',
+ flex: 2,
+ margin: 10,
+ data: {
+ iconCls: Proxmox.Utils.get_health_icon(undefined, true),
+ text: '',
+ },
+ bind: {
+ data: '{state}',
+ },
+ tpl: [
+ '<center class="centered-flex-column" style="font-size:15px;line-height: 25px;">',
+ '<i class="fa fa-4x {iconCls}"></i>',
+ '<br/><br/>',
+ '{text}',
+ '</center>',
+ ],
+ },
+ {
+ xtype: 'proxmoxNodeAPTRepositoriesErrors',
+ name: 'repositoriesErrors',
+ flex: 7,
+ margin: 10,
+ bind: {
+ store: '{errorstore}',
+ },
+ },
+ ],
},
{
xtype: 'proxmoxNodeAPTRepositoriesGrid',
name: 'repositoriesGrid',
+ flex: 1,
cbind: {
nodename: '{nodename}',
},
const res = response.result;
const subscription = !(!res || !res.data || res.data.status.toLowerCase() !== 'active');
vm.set('subscriptionActive', subscription);
+ me.getController().updateState();
},
});
},
vm.set('enterpriseRepo', status);
} else if (handle === "no-subscription") {
vm.set('noSubscriptionRepo', status);
+ } else if (handle === 'test') {
+ vm.set('testRepo', status);
}
+ me.getController().updateState();
addButton.repoInfo.push(standardRepo);
addButton.digest = me.digest;
let me = this;
let vm = me.getViewModel();
let repoGrid = me.down('proxmoxNodeAPTRepositoriesGrid');
- let errorGrid = me.down('proxmoxNodeAPTRepositoriesErrors');
me.store.load(function(records, operation, success) {
let gridData = [];
let errors = [];
let digest;
+ let suitesWarning = false;
if (success && records.length > 0) {
let data = records[0].data;
(info.kind === 'ignore-pre-upgrade-warning' && !repoGrid.majorUpgradeAllowed)
) {
infos[path][idx].warnings.push(info);
+ if (!suitesWarning && info.property === 'Suites') {
+ suitesWarning = true;
+ }
} else {
throw 'unknown info';
}
me.digest = digest;
- vm.set('errorCount', errors.length);
- errorGrid.store.loadData(errors);
+ vm.set('errors', errors);
+ vm.set('suitesWarning', suitesWarning);
+ me.getController().updateState();
});
me.check_subscription();