mirror of
				https://git.proxmox.com/git/pve-manager
				synced 2025-11-04 10:23:04 +00:00 
			
		
		
		
	multiple users were confused[0], as they did not interpret the 'icon only' in the toolbar as a button (and it did not help that we prevented the cursor to change) to improve it, make the button a normal one again, and add some text for context (this is more inline what we do elsewhere in toolbars) 0: https://forum.proxmox.com/threads/acme-over-dnschallenge-failing.71902 Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
		
			
				
	
	
		
			742 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			742 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
Ext.define('PVE.node.ACMEAccountCreate', {
 | 
						|
    extend: 'Proxmox.window.Edit',
 | 
						|
    mixins: ['Proxmox.Mixin.CBind'],
 | 
						|
 | 
						|
    width: 450,
 | 
						|
    title: gettext('Register Account'),
 | 
						|
    isCreate: true,
 | 
						|
    method: 'POST',
 | 
						|
    submitText: gettext('Register'),
 | 
						|
    url: '/cluster/acme/account',
 | 
						|
    showTaskViewer: true,
 | 
						|
    defaultExists: false,
 | 
						|
 | 
						|
    items: [
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxtextfield',
 | 
						|
	    fieldLabel: gettext('Account Name'),
 | 
						|
	    name: 'name',
 | 
						|
	    cbind: {
 | 
						|
		emptyText: (get) => get('defaultExists') ? '' : 'default',
 | 
						|
		allowBlank: (get) => !get('defaultExists'),
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'textfield',
 | 
						|
	    name: 'contact',
 | 
						|
	    vtype: 'email',
 | 
						|
	    allowBlank: false,
 | 
						|
	    fieldLabel: gettext('E-Mail'),
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxComboGrid',
 | 
						|
	    name: 'directory',
 | 
						|
	    allowBlank: false,
 | 
						|
	    valueField: 'url',
 | 
						|
	    displayField: 'name',
 | 
						|
	    fieldLabel: gettext('ACME Directory'),
 | 
						|
	    store: {
 | 
						|
		autoLoad: true,
 | 
						|
		fields: ['name', 'url'],
 | 
						|
		idProperty: ['name'],
 | 
						|
		proxy: {
 | 
						|
		    type: 'proxmox',
 | 
						|
		    url: '/api2/json/cluster/acme/directories',
 | 
						|
		},
 | 
						|
		sorters: {
 | 
						|
		    property: 'name',
 | 
						|
		    order: 'ASC',
 | 
						|
		},
 | 
						|
	    },
 | 
						|
	    listConfig: {
 | 
						|
		columns: [
 | 
						|
		    {
 | 
						|
			header: gettext('Name'),
 | 
						|
			dataIndex: 'name',
 | 
						|
			flex: 1,
 | 
						|
		    },
 | 
						|
		    {
 | 
						|
			header: gettext('URL'),
 | 
						|
			dataIndex: 'url',
 | 
						|
			flex: 1,
 | 
						|
		    },
 | 
						|
		],
 | 
						|
	    },
 | 
						|
	    listeners: {
 | 
						|
		change: function(combogrid, value) {
 | 
						|
		    var me = this;
 | 
						|
		    if (!value) {
 | 
						|
			return;
 | 
						|
		    }
 | 
						|
 | 
						|
		    var disp = me.up('window').down('#tos_url_display');
 | 
						|
		    var field = me.up('window').down('#tos_url');
 | 
						|
		    var checkbox = me.up('window').down('#tos_checkbox');
 | 
						|
 | 
						|
		    disp.setValue(gettext('Loading'));
 | 
						|
		    field.setValue(undefined);
 | 
						|
		    checkbox.setValue(undefined);
 | 
						|
		    checkbox.setHidden(true);
 | 
						|
 | 
						|
		    Proxmox.Utils.API2Request({
 | 
						|
			url: '/cluster/acme/tos',
 | 
						|
			method: 'GET',
 | 
						|
			params: {
 | 
						|
			    directory: value,
 | 
						|
			},
 | 
						|
			success: function(response, opt) {
 | 
						|
			    field.setValue(response.result.data);
 | 
						|
			    disp.setValue(response.result.data);
 | 
						|
			    checkbox.setHidden(false);
 | 
						|
			},
 | 
						|
			failure: function(response, opt) {
 | 
						|
			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
 | 
						|
			},
 | 
						|
		    });
 | 
						|
		},
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    itemId: 'tos_url_display',
 | 
						|
	    renderer: PVE.Utils.render_optional_url,
 | 
						|
	    name: 'tos_url_display',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'hidden',
 | 
						|
	    itemId: 'tos_url',
 | 
						|
	    name: 'tos_url',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxcheckbox',
 | 
						|
	    itemId: 'tos_checkbox',
 | 
						|
	    boxLabel: gettext('Accept TOS'),
 | 
						|
	    submitValue: false,
 | 
						|
	    validateValue: function(value) {
 | 
						|
		if (value && this.checked) {
 | 
						|
		    return true;
 | 
						|
		}
 | 
						|
		return false;
 | 
						|
	    },
 | 
						|
	},
 | 
						|
    ],
 | 
						|
 | 
						|
});
 | 
						|
 | 
						|
Ext.define('PVE.node.ACMEAccountView', {
 | 
						|
    extend: 'Proxmox.window.Edit',
 | 
						|
 | 
						|
    width: 600,
 | 
						|
    fieldDefaults: {
 | 
						|
	labelWidth: 140,
 | 
						|
    },
 | 
						|
 | 
						|
    title: gettext('Account'),
 | 
						|
 | 
						|
    items: [
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    fieldLabel: gettext('E-Mail'),
 | 
						|
	    name: 'email',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    fieldLabel: gettext('Created'),
 | 
						|
	    name: 'createdAt',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    fieldLabel: gettext('Status'),
 | 
						|
	    name: 'status',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    fieldLabel: gettext('Directory'),
 | 
						|
	    renderer: PVE.Utils.render_optional_url,
 | 
						|
	    name: 'directory',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    fieldLabel: gettext('Terms of Services'),
 | 
						|
	    renderer: PVE.Utils.render_optional_url,
 | 
						|
	    name: 'tos',
 | 
						|
	},
 | 
						|
    ],
 | 
						|
 | 
						|
    initComponent: function() {
 | 
						|
	var me = this;
 | 
						|
 | 
						|
	if (!me.accountname) {
 | 
						|
	    throw "no account name defined";
 | 
						|
	}
 | 
						|
 | 
						|
	me.url = '/cluster/acme/account/' + me.accountname;
 | 
						|
 | 
						|
	me.callParent();
 | 
						|
 | 
						|
	// hide OK/Reset button, because we just want to show data
 | 
						|
	me.down('toolbar[dock=bottom]').setVisible(false);
 | 
						|
 | 
						|
	me.load({
 | 
						|
	    success: function(response) {
 | 
						|
		var data = response.result.data;
 | 
						|
		data.email = data.account.contact[0];
 | 
						|
		data.createdAt = data.account.createdAt;
 | 
						|
		data.status = data.account.status;
 | 
						|
		me.setValues(data);
 | 
						|
	    },
 | 
						|
	});
 | 
						|
    },
 | 
						|
});
 | 
						|
 | 
						|
Ext.define('PVE.node.ACMEDomainEdit', {
 | 
						|
    extend: 'Proxmox.window.Edit',
 | 
						|
    alias: 'widget.pveACMEDomainEdit',
 | 
						|
 | 
						|
    subject: gettext('Domain'),
 | 
						|
    isCreate: false,
 | 
						|
    width: 450,
 | 
						|
    onlineHelp: 'sysadmin_certificate_management',
 | 
						|
 | 
						|
    items: [
 | 
						|
	{
 | 
						|
	    xtype: 'inputpanel',
 | 
						|
	    onGetValues: function(values) {
 | 
						|
		let me = this;
 | 
						|
		let win = me.up('pveACMEDomainEdit');
 | 
						|
		let nodeconfig = win.nodeconfig;
 | 
						|
		let olddomain = win.domain || {};
 | 
						|
 | 
						|
		let params = {
 | 
						|
		    digest: nodeconfig.digest,
 | 
						|
		};
 | 
						|
 | 
						|
		let configkey = olddomain.configkey;
 | 
						|
		let acmeObj = PVE.Parser.parseACME(nodeconfig.acme);
 | 
						|
 | 
						|
		if (values.type === 'dns') {
 | 
						|
		    if (!olddomain.configkey || olddomain.configkey === 'acme') {
 | 
						|
			// look for first free slot
 | 
						|
			for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
 | 
						|
			    if (nodeconfig[`acmedomain${i}`] === undefined) {
 | 
						|
				configkey = `acmedomain${i}`;
 | 
						|
				break;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
			if (olddomain.domain) {
 | 
						|
			    // we have to remove the domain from the acme domainlist
 | 
						|
			    PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain);
 | 
						|
			    params.acme = PVE.Parser.printACME(acmeObj);
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		    delete values.type;
 | 
						|
		    params[configkey] = PVE.Parser.printPropertyString(values, 'domain');
 | 
						|
		} else {
 | 
						|
		    if (olddomain.configkey && olddomain.configkey !== 'acme') {
 | 
						|
			// delete the old dns entry
 | 
						|
			params.delete = [olddomain.configkey];
 | 
						|
		    }
 | 
						|
 | 
						|
		    // add new, remove old and make entries unique
 | 
						|
		    PVE.Utils.add_domain_to_acme(acmeObj, values.domain);
 | 
						|
		    PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain);
 | 
						|
		    params.acme = PVE.Parser.printACME(acmeObj);
 | 
						|
		}
 | 
						|
 | 
						|
		return params;
 | 
						|
	    },
 | 
						|
	    items: [
 | 
						|
		{
 | 
						|
		    xtype: 'proxmoxKVComboBox',
 | 
						|
		    name: 'type',
 | 
						|
		    fieldLabel: gettext('Challenge Type'),
 | 
						|
		    allowBlank: false,
 | 
						|
		    value: 'standalone',
 | 
						|
		    comboItems: [
 | 
						|
			['standalone', 'HTTP'],
 | 
						|
			['dns', 'DNS'],
 | 
						|
		    ],
 | 
						|
		    validator: function(value) {
 | 
						|
			let me = this;
 | 
						|
			let win = me.up('pveACMEDomainEdit');
 | 
						|
			let oldconfigkey = win.domain ? win.domain.configkey : undefined;
 | 
						|
			let val = me.getValue();
 | 
						|
			if (val === 'dns' && (!oldconfigkey || oldconfigkey === 'acme')) {
 | 
						|
			    // we have to check if there is a 'acmedomain' slot left
 | 
						|
			    let found = false;
 | 
						|
			    for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
 | 
						|
				if (!win.nodeconfig[`acmedomain${i}`]) {
 | 
						|
				    found = true;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			    if (!found) {
 | 
						|
				return gettext('Only 5 Domains with type DNS can be configured');
 | 
						|
			    }
 | 
						|
			}
 | 
						|
 | 
						|
			return true;
 | 
						|
		    },
 | 
						|
		    listeners: {
 | 
						|
			change: function(cb, value) {
 | 
						|
			    let me = this;
 | 
						|
			    let view = me.up('pveACMEDomainEdit');
 | 
						|
			    let pluginField = view.down('field[name=plugin]');
 | 
						|
			    pluginField.setDisabled(value !== 'dns');
 | 
						|
			    pluginField.setHidden(value !== 'dns');
 | 
						|
			},
 | 
						|
		    },
 | 
						|
		},
 | 
						|
		{
 | 
						|
		    xtype: 'hidden',
 | 
						|
		    name: 'alias',
 | 
						|
		},
 | 
						|
		{
 | 
						|
		    xtype: 'pveACMEPluginSelector',
 | 
						|
		    name: 'plugin',
 | 
						|
		    disabled: true,
 | 
						|
		    hidden: true,
 | 
						|
		    allowBlank: false,
 | 
						|
		},
 | 
						|
		{
 | 
						|
		    xtype: 'proxmoxtextfield',
 | 
						|
		    name: 'domain',
 | 
						|
		    allowBlank: false,
 | 
						|
		    vtype: 'DnsName',
 | 
						|
		    value: '',
 | 
						|
		    fieldLabel: gettext('Domain'),
 | 
						|
		},
 | 
						|
	    ],
 | 
						|
	},
 | 
						|
    ],
 | 
						|
 | 
						|
    initComponent: function() {
 | 
						|
	let me = this;
 | 
						|
 | 
						|
	if (!me.nodename) {
 | 
						|
	    throw 'no nodename given';
 | 
						|
	}
 | 
						|
 | 
						|
	if (!me.nodeconfig) {
 | 
						|
	    throw 'no nodeconfig given';
 | 
						|
	}
 | 
						|
 | 
						|
	me.isCreate = !me.domain;
 | 
						|
	if (me.isCreate) {
 | 
						|
	    me.domain = `${me.nodename}.`; // TODO: FQDN of node
 | 
						|
	}
 | 
						|
 | 
						|
	me.url = `/api2/extjs/nodes/${me.nodename}/config`;
 | 
						|
 | 
						|
	me.callParent();
 | 
						|
 | 
						|
	if (!me.isCreate) {
 | 
						|
	    me.setValues(me.domain);
 | 
						|
	} else {
 | 
						|
	    me.setValues({ domain: me.domain });
 | 
						|
	}
 | 
						|
    },
 | 
						|
});
 | 
						|
 | 
						|
Ext.define('pve-acme-domains', {
 | 
						|
    extend: 'Ext.data.Model',
 | 
						|
    fields: ['domain', 'type', 'alias', 'plugin', 'configkey'],
 | 
						|
    idProperty: 'domain',
 | 
						|
});
 | 
						|
 | 
						|
Ext.define('PVE.node.ACME', {
 | 
						|
    extend: 'Ext.grid.Panel',
 | 
						|
    alias: 'widget.pveACMEView',
 | 
						|
 | 
						|
    margin: '10 0 0 0',
 | 
						|
    title: 'ACME',
 | 
						|
 | 
						|
    emptyText: gettext('No Domains configured'),
 | 
						|
 | 
						|
    viewModel: {
 | 
						|
	data: {
 | 
						|
	    domaincount: 0,
 | 
						|
	    account: undefined, // the account we display
 | 
						|
	    configaccount: undefined, // the account set in the config
 | 
						|
	    accountEditable: false,
 | 
						|
	    accountsAvailable: false,
 | 
						|
	},
 | 
						|
 | 
						|
	formulas: {
 | 
						|
	    canOrder: (get) => !!get('account') && get('domaincount') > 0,
 | 
						|
	    editBtnIcon: (get) => 'fa black fa-' + (get('accountEditable') ? 'check' : 'pencil'),
 | 
						|
	    editBtnText: (get) => get('accountEditable') ? gettext('Apply') : gettext('Edit'),
 | 
						|
	    accountTextHidden: (get) => get('accountEditable') || !get('accountsAvailable'),
 | 
						|
	    accountValueHidden: (get) => !get('accountEditable') || !get('accountsAvailable'),
 | 
						|
	},
 | 
						|
    },
 | 
						|
 | 
						|
    controller: {
 | 
						|
	xclass: 'Ext.app.ViewController',
 | 
						|
 | 
						|
	init: function(view) {
 | 
						|
	    let accountSelector = this.lookup('accountselector');
 | 
						|
	    accountSelector.store.on('load', this.onAccountsLoad, this);
 | 
						|
	},
 | 
						|
 | 
						|
	onAccountsLoad: function(store, records, success) {
 | 
						|
	    let me = this;
 | 
						|
	    let vm = me.getViewModel();
 | 
						|
	    let configaccount = vm.get('configaccount');
 | 
						|
	    vm.set('accountsAvailable', records.length > 0);
 | 
						|
	    if (me.autoChangeAccount && records.length > 0) {
 | 
						|
		me.changeAccount(records[0].data.name, () => {
 | 
						|
		    vm.set('accountEditable', false);
 | 
						|
		    me.reload();
 | 
						|
		});
 | 
						|
		me.autoChangeAccount = false;
 | 
						|
	    } else if (configaccount) {
 | 
						|
		if (store.findExact('name', configaccount) !== -1) {
 | 
						|
		    vm.set('account', configaccount);
 | 
						|
		} else {
 | 
						|
		    vm.set('account', null);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	},
 | 
						|
 | 
						|
	addDomain: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
 | 
						|
	    Ext.create('PVE.node.ACMEDomainEdit', {
 | 
						|
		nodename: view.nodename,
 | 
						|
		nodeconfig: view.nodeconfig,
 | 
						|
		apiCallDone: function() {
 | 
						|
		    me.reload();
 | 
						|
		},
 | 
						|
	    }).show();
 | 
						|
	},
 | 
						|
 | 
						|
	editDomain: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
 | 
						|
	    let selection = view.getSelection();
 | 
						|
	    if (selection.length < 1) return;
 | 
						|
 | 
						|
	    Ext.create('PVE.node.ACMEDomainEdit', {
 | 
						|
		nodename: view.nodename,
 | 
						|
		nodeconfig: view.nodeconfig,
 | 
						|
		domain: selection[0].data,
 | 
						|
		apiCallDone: function() {
 | 
						|
		    me.reload();
 | 
						|
		},
 | 
						|
	    }).show();
 | 
						|
	},
 | 
						|
 | 
						|
	removeDomain: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
	    let selection = view.getSelection();
 | 
						|
	    if (selection.length < 1) return;
 | 
						|
 | 
						|
	    let rec = selection[0].data;
 | 
						|
	    let params = {};
 | 
						|
	    if (rec.configkey !== 'acme') {
 | 
						|
		params.delete = rec.configkey;
 | 
						|
	    } else {
 | 
						|
		let acme = PVE.Parser.parseACME(view.nodeconfig.acme);
 | 
						|
		PVE.Utils.remove_domain_from_acme(acme, rec.domain);
 | 
						|
		params.acme = PVE.Parser.printACME(acme);
 | 
						|
	    }
 | 
						|
 | 
						|
	    Proxmox.Utils.API2Request({
 | 
						|
		method: 'PUT',
 | 
						|
		url: `/nodes/${view.nodename}/config`,
 | 
						|
		params,
 | 
						|
		success: function(response, opt) {
 | 
						|
		    me.reload();
 | 
						|
		},
 | 
						|
		failure: function(response, opt) {
 | 
						|
		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
 | 
						|
		},
 | 
						|
	    });
 | 
						|
	},
 | 
						|
 | 
						|
	toggleEditAccount: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let vm = me.getViewModel();
 | 
						|
	    let editable = vm.get('accountEditable');
 | 
						|
	    if (editable) {
 | 
						|
		me.changeAccount(vm.get('account'), function() {
 | 
						|
		    vm.set('accountEditable', false);
 | 
						|
		    me.reload();
 | 
						|
		});
 | 
						|
	    } else {
 | 
						|
		vm.set('accountEditable', true);
 | 
						|
	    }
 | 
						|
	},
 | 
						|
 | 
						|
	changeAccount: function(account, callback) {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
	    let params = {};
 | 
						|
 | 
						|
	    let acme = PVE.Parser.parseACME(view.nodeconfig.acme);
 | 
						|
	    acme.account = account;
 | 
						|
	    params.acme = PVE.Parser.printACME(acme);
 | 
						|
 | 
						|
	    Proxmox.Utils.API2Request({
 | 
						|
		method: 'PUT',
 | 
						|
		waitMsgTarget: view,
 | 
						|
		url: `/nodes/${view.nodename}/config`,
 | 
						|
		params,
 | 
						|
		success: function(response, opt) {
 | 
						|
		    if (Ext.isFunction(callback)) {
 | 
						|
			callback();
 | 
						|
		    }
 | 
						|
		},
 | 
						|
		failure: function(response, opt) {
 | 
						|
		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
 | 
						|
		},
 | 
						|
	    });
 | 
						|
	},
 | 
						|
 | 
						|
	order: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
 | 
						|
	    Proxmox.Utils.API2Request({
 | 
						|
		method: 'POST',
 | 
						|
		params: {
 | 
						|
		    force: 1,
 | 
						|
		},
 | 
						|
		url: `/nodes/${view.nodename}/certificates/acme/certificate`,
 | 
						|
		success: function(response, opt) {
 | 
						|
		    Ext.create('Proxmox.window.TaskViewer', {
 | 
						|
		        upid: response.result.data,
 | 
						|
		        taskDone: function(success) {
 | 
						|
			    me.orderFinished(success);
 | 
						|
		        },
 | 
						|
		    }).show();
 | 
						|
		},
 | 
						|
		failure: function(response, opt) {
 | 
						|
		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
 | 
						|
		},
 | 
						|
	    });
 | 
						|
	},
 | 
						|
 | 
						|
	orderFinished: function(success) {
 | 
						|
	    if (!success) return;
 | 
						|
	    var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
 | 
						|
	    Ext.getBody().mask(txt, ['pve-static-mask']);
 | 
						|
	    // reload after 10 seconds automatically
 | 
						|
	    Ext.defer(function() {
 | 
						|
		window.location.reload(true);
 | 
						|
	    }, 10000);
 | 
						|
	},
 | 
						|
 | 
						|
	reload: function() {
 | 
						|
	    let me = this;
 | 
						|
	    let view = me.getView();
 | 
						|
	    view.rstore.load();
 | 
						|
	},
 | 
						|
 | 
						|
	addAccount: function() {
 | 
						|
	    let me = this;
 | 
						|
	    Ext.create('PVE.node.ACMEAccountCreate', {
 | 
						|
		autoShow: true,
 | 
						|
		taskDone: function() {
 | 
						|
		    me.reload();
 | 
						|
		    let accountSelector = me.lookup('accountselector');
 | 
						|
		    me.autoChangeAccount = true;
 | 
						|
		    accountSelector.store.load();
 | 
						|
		},
 | 
						|
	    });
 | 
						|
	},
 | 
						|
    },
 | 
						|
 | 
						|
    tbar: [
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxButton',
 | 
						|
	    text: gettext('Add'),
 | 
						|
	    handler: 'addDomain',
 | 
						|
	    selModel: false,
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxButton',
 | 
						|
	    text: gettext('Edit'),
 | 
						|
	    disabled: true,
 | 
						|
	    handler: 'editDomain',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'proxmoxStdRemoveButton',
 | 
						|
	    handler: 'removeDomain',
 | 
						|
	},
 | 
						|
	'-',
 | 
						|
	{
 | 
						|
	    xtype: 'button',
 | 
						|
	    reference: 'order',
 | 
						|
	    text: gettext('Order Certificates Now'),
 | 
						|
	    bind: {
 | 
						|
		disabled: '{!canOrder}',
 | 
						|
	    },
 | 
						|
	    handler: 'order',
 | 
						|
	},
 | 
						|
	'-',
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    value: gettext('Using Account') + ':',
 | 
						|
	    bind: {
 | 
						|
		hidden: '{!accountsAvailable}',
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    reference: 'accounttext',
 | 
						|
	    renderer: (val) => val || Proxmox.Utils.NoneText,
 | 
						|
	    bind: {
 | 
						|
		value: '{account}',
 | 
						|
		hidden: '{accountTextHidden}',
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'pveACMEAccountSelector',
 | 
						|
	    hidden: true,
 | 
						|
	    reference: 'accountselector',
 | 
						|
	    bind: {
 | 
						|
		value: '{account}',
 | 
						|
		hidden: '{accountValueHidden}',
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'button',
 | 
						|
	    iconCls: 'fa black fa-pencil',
 | 
						|
	    bind: {
 | 
						|
		iconCls: '{editBtnIcon}',
 | 
						|
		text: '{editBtnText}',
 | 
						|
		hidden: '{!accountsAvailable}',
 | 
						|
	    },
 | 
						|
	    handler: 'toggleEditAccount',
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'displayfield',
 | 
						|
	    value: gettext('No Account available.'),
 | 
						|
	    bind: {
 | 
						|
		hidden: '{accountsAvailable}',
 | 
						|
	    },
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    xtype: 'button',
 | 
						|
	    hidden: true,
 | 
						|
	    reference: 'accountlink',
 | 
						|
	    text: gettext('Add ACME Account'),
 | 
						|
	    bind: {
 | 
						|
		hidden: '{accountsAvailable}',
 | 
						|
	    },
 | 
						|
	    handler: 'addAccount',
 | 
						|
	},
 | 
						|
    ],
 | 
						|
 | 
						|
    updateStore: function(store, records, success) {
 | 
						|
	let me = this;
 | 
						|
	let data = [];
 | 
						|
	let rec;
 | 
						|
	if (success && records.length > 0) {
 | 
						|
	    rec = records[0];
 | 
						|
	} else {
 | 
						|
	    rec = {
 | 
						|
		data: {},
 | 
						|
	    };
 | 
						|
	}
 | 
						|
 | 
						|
	me.nodeconfig = rec.data; // save nodeconfig for updates
 | 
						|
 | 
						|
	let account = 'default';
 | 
						|
 | 
						|
	if (rec.data.acme) {
 | 
						|
	    let obj = PVE.Parser.parseACME(rec.data.acme);
 | 
						|
	    (obj.domains || []).forEach(domain => {
 | 
						|
		if (domain === '') return;
 | 
						|
		let record = {
 | 
						|
		    domain,
 | 
						|
		    type: 'standalone',
 | 
						|
		    configkey: 'acme',
 | 
						|
		};
 | 
						|
		data.push(record);
 | 
						|
	    });
 | 
						|
 | 
						|
	    if (obj.account) {
 | 
						|
		account = obj.account;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	let vm = me.getViewModel();
 | 
						|
	let oldaccount = vm.get('account');
 | 
						|
 | 
						|
	// account changed, and we do not edit currently, load again to verify
 | 
						|
	if (oldaccount !== account && !vm.get('accountEditable')) {
 | 
						|
	    vm.set('configaccount', account);
 | 
						|
	    me.lookup('accountselector').store.load();
 | 
						|
	}
 | 
						|
 | 
						|
	for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
 | 
						|
	    let acmedomain = rec.data[`acmedomain${i}`];
 | 
						|
	    if (!acmedomain) continue;
 | 
						|
 | 
						|
	    let record = PVE.Parser.parsePropertyString(acmedomain, 'domain');
 | 
						|
	    record.type = 'dns';
 | 
						|
	    record.configkey = `acmedomain${i}`;
 | 
						|
	    data.push(record);
 | 
						|
	}
 | 
						|
 | 
						|
	vm.set('domaincount', data.length);
 | 
						|
	me.store.loadData(data, false);
 | 
						|
    },
 | 
						|
 | 
						|
    listeners: {
 | 
						|
	itemdblclick: 'editDomain',
 | 
						|
    },
 | 
						|
 | 
						|
    columns: [
 | 
						|
	{
 | 
						|
	    dataIndex: 'domain',
 | 
						|
	    flex: 5,
 | 
						|
	    text: gettext('Domain'),
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    dataIndex: 'type',
 | 
						|
	    flex: 1,
 | 
						|
	    text: gettext('Type'),
 | 
						|
	},
 | 
						|
	{
 | 
						|
	    dataIndex: 'plugin',
 | 
						|
	    flex: 1,
 | 
						|
	    text: gettext('Plugin'),
 | 
						|
	},
 | 
						|
    ],
 | 
						|
 | 
						|
    initComponent: function() {
 | 
						|
	var me = this;
 | 
						|
 | 
						|
	if (!me.nodename) {
 | 
						|
	    throw "no nodename given";
 | 
						|
	}
 | 
						|
 | 
						|
	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
 | 
						|
	    interval: 10 * 1000,
 | 
						|
	    autoStart: true,
 | 
						|
	    storeid: `pve-node-domains-${me.nodename}`,
 | 
						|
	    proxy: {
 | 
						|
		type: 'proxmox',
 | 
						|
		url: `/api2/json/nodes/${me.nodename}/config`,
 | 
						|
	    },
 | 
						|
	});
 | 
						|
 | 
						|
	me.store = Ext.create('Ext.data.Store', {
 | 
						|
	    model: 'pve-acme-domains',
 | 
						|
	    sorters: 'domain',
 | 
						|
	});
 | 
						|
 | 
						|
	me.callParent();
 | 
						|
	me.mon(me.rstore, 'load', 'updateStore', me);
 | 
						|
	Proxmox.Utils.monStoreErrors(me, me.rstore);
 | 
						|
	me.on('destroy', me.rstore.stopUpdate, me.rstore);
 | 
						|
    },
 | 
						|
});
 |