]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/node/ACME.js
ui: acme: add External Account Binding (EAB) related fields
[pve-manager.git] / www / manager6 / node / ACME.js
CommitLineData
488be4c2
DC
1Ext.define('PVE.node.ACMEAccountCreate', {
2 extend: 'Proxmox.window.Edit',
fc40915c 3 mixins: ['Proxmox.Mixin.CBind'],
488be4c2 4
04a8058e 5 width: 450,
488be4c2
DC
6 title: gettext('Register Account'),
7 isCreate: true,
8 method: 'POST',
9 submitText: gettext('Register'),
10 url: '/cluster/acme/account',
11 showTaskViewer: true,
fc40915c 12 defaultExists: false,
fdc4c229
FG
13 referenceHolder: true,
14 onlineHelp: "sysadmin_certs_acme_account",
15
16 viewModel: {
17 data: {
18 customDirectory: false,
c18a2db2
FG
19 eabRequired: false,
20 },
21 formulas: {
22 eabEmptyText: function(get) {
23 return get('eabRequired') ? gettext("required") : gettext("optional");
24 },
fdc4c229
FG
25 },
26 },
488be4c2
DC
27
28 items: [
c0afd5cc
DC
29 {
30 xtype: 'proxmoxtextfield',
e023535e 31 fieldLabel: gettext('Account Name'),
c0afd5cc 32 name: 'name',
fc40915c
DC
33 cbind: {
34 emptyText: (get) => get('defaultExists') ? '' : 'default',
35 allowBlank: (get) => !get('defaultExists'),
36 },
c0afd5cc 37 },
04a8058e
DC
38 {
39 xtype: 'textfield',
40 name: 'contact',
41 vtype: 'email',
42 allowBlank: false,
f6710aac 43 fieldLabel: gettext('E-Mail'),
04a8058e 44 },
488be4c2
DC
45 {
46 xtype: 'proxmoxComboGrid',
fdc4c229
FG
47 notFoundIsValid: true,
48 isFormField: false,
488be4c2
DC
49 allowBlank: false,
50 valueField: 'url',
51 displayField: 'name',
52 fieldLabel: gettext('ACME Directory'),
53 store: {
fdc4c229
FG
54 listeners: {
55 'load': function() {
56 this.add({ name: gettext("Custom"), url: '' });
57 },
58 },
488be4c2
DC
59 autoLoad: true,
60 fields: ['name', 'url'],
61 idProperty: ['name'],
62 proxy: {
63 type: 'proxmox',
f6710aac 64 url: '/api2/json/cluster/acme/directories',
488be4c2 65 },
488be4c2
DC
66 },
67 listConfig: {
68 columns: [
69 {
70 header: gettext('Name'),
71 dataIndex: 'name',
f6710aac 72 flex: 1,
488be4c2
DC
73 },
74 {
75 header: gettext('URL'),
76 dataIndex: 'url',
f6710aac
TL
77 flex: 1,
78 },
79 ],
488be4c2
DC
80 },
81 listeners: {
82 change: function(combogrid, value) {
fdc4c229 83 let me = this;
488be4c2 84
fdc4c229
FG
85 let vm = me.up('window').getViewModel();
86 let dirField = me.up('window').lookupReference('directoryInput');
87 let tosButton = me.up('window').lookupReference('queryTos');
488be4c2 88
fdc4c229
FG
89 let isCustom = combogrid.getSelection().get('name') === gettext("Custom");
90 vm.set('customDirectory', isCustom);
488be4c2 91
fdc4c229
FG
92 dirField.setValue(value);
93
94 if (!isCustom) {
95 tosButton.click();
96 } else {
97 me.up('window').clearToSFields();
98 }
99 },
100 },
101 },
102 {
103 xtype: 'fieldcontainer',
104 layout: 'hbox',
105 fieldLabel: gettext('URL'),
106 bind: {
107 hidden: '{!customDirectory}',
108 },
109 items: [
110 {
111 xtype: 'proxmoxtextfield',
112 name: 'directory',
113 reference: 'directoryInput',
114 flex: 1,
115 allowBlank: false,
116 listeners: {
117 change: function(textbox, value) {
118 let me = this;
119 me.up('window').clearToSFields();
488be4c2 120 },
fdc4c229
FG
121 },
122 },
123 {
124 xtype: 'proxmoxButton',
125 margin: '0 0 0 5',
126 reference: 'queryTos',
127 text: gettext('Query URL'),
128 listeners: {
129 click: function(button) {
130 let me = this;
131
132 let w = me.up('window');
c18a2db2 133 let vm = w.getViewModel();
fdc4c229
FG
134 let disp = w.down('#tos_url_display');
135 let field = w.down('#tos_url');
136 let checkbox = w.down('#tos_checkbox');
137 let value = w.lookupReference('directoryInput').getValue();
138 w.clearToSFields();
139
140 if (!value) {
141 return;
7fb70c3b 142 } else {
fdc4c229 143 disp.setValue(gettext("Loading"));
7fb70c3b 144 }
fdc4c229
FG
145
146 Proxmox.Utils.API2Request({
147 url: '/cluster/acme/meta',
148 method: 'GET',
149 params: {
150 directory: value,
151 },
152 success: function(response, opt) {
153 if (response.result.data.termsOfService) {
154 field.setValue(response.result.data.termsOfService);
155 disp.setValue(response.result.data.termsOfService);
156 checkbox.setHidden(false);
157 } else {
158 checkbox.setValue(false);
159 disp.setValue("No terms of service agreement required");
160 }
c18a2db2 161 vm.set('eabRequired', !!response.result.data.externalAccountRequired);
fdc4c229
FG
162 },
163 failure: function(response, opt) {
164 disp.setValue(undefined);
165 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
166 },
167 });
488be4c2 168 },
fdc4c229 169 },
f6710aac 170 },
fdc4c229 171 ],
488be4c2
DC
172 },
173 {
174 xtype: 'displayfield',
175 itemId: 'tos_url_display',
488be4c2 176 renderer: PVE.Utils.render_optional_url,
f6710aac 177 name: 'tos_url_display',
488be4c2
DC
178 },
179 {
180 xtype: 'hidden',
181 itemId: 'tos_url',
f6710aac 182 name: 'tos_url',
488be4c2
DC
183 },
184 {
185 xtype: 'proxmoxcheckbox',
186 itemId: 'tos_checkbox',
04a8058e 187 boxLabel: gettext('Accept TOS'),
488be4c2
DC
188 submitValue: false,
189 validateValue: function(value) {
190 if (value && this.checked) {
191 return true;
192 }
193 return false;
f6710aac 194 },
488be4c2 195 },
c18a2db2
FG
196 {
197 xtype: 'proxmoxtextfield',
198 name: 'eab-kid',
199 fieldLabel: gettext('EAB Key ID'),
200 bind: {
201 hidden: '{!customDirectory}',
202 allowBlank: '{!eabRequired}',
203 emptyText: '{eabEmptyText}',
204 },
205 },
206 {
207 xtype: 'proxmoxtextfield',
208 name: 'eab-hmac-key',
209 fieldLabel: gettext('EAB Key'),
210 bind: {
211 hidden: '{!customDirectory}',
212 allowBlank: '{!eabRequired}',
213 emptyText: '{eabEmptyText}',
214 },
215 },
f6710aac 216 ],
488be4c2 217
fdc4c229
FG
218 clearToSFields: function() {
219 let me = this;
220
221 let disp = me.down('#tos_url_display');
222 let field = me.down('#tos_url');
223 let checkbox = me.down('#tos_checkbox');
224
225 disp.setValue("Terms of service not fetched yet");
226 field.setValue(undefined);
227 checkbox.setValue(undefined);
228 checkbox.setHidden(true);
229 },
230
488be4c2
DC
231});
232
233Ext.define('PVE.node.ACMEAccountView', {
234 extend: 'Proxmox.window.Edit',
235
236 width: 600,
237 fieldDefaults: {
f6710aac 238 labelWidth: 140,
488be4c2
DC
239 },
240
241 title: gettext('Account'),
242
243 items: [
244 {
245 xtype: 'displayfield',
246 fieldLabel: gettext('E-Mail'),
f6710aac 247 name: 'email',
488be4c2
DC
248 },
249 {
250 xtype: 'displayfield',
251 fieldLabel: gettext('Created'),
f6710aac 252 name: 'createdAt',
488be4c2
DC
253 },
254 {
255 xtype: 'displayfield',
256 fieldLabel: gettext('Status'),
f6710aac 257 name: 'status',
488be4c2
DC
258 },
259 {
260 xtype: 'displayfield',
261 fieldLabel: gettext('Directory'),
262 renderer: PVE.Utils.render_optional_url,
f6710aac 263 name: 'directory',
488be4c2
DC
264 },
265 {
266 xtype: 'displayfield',
267 fieldLabel: gettext('Terms of Services'),
268 renderer: PVE.Utils.render_optional_url,
f6710aac
TL
269 name: 'tos',
270 },
488be4c2
DC
271 ],
272
273 initComponent: function() {
274 var me = this;
275
276 if (!me.accountname) {
277 throw "no account name defined";
278 }
279
280 me.url = '/cluster/acme/account/' + me.accountname;
281
282 me.callParent();
283
284 // hide OK/Reset button, because we just want to show data
285 me.down('toolbar[dock=bottom]').setVisible(false);
286
287 me.load({
288 success: function(response) {
289 var data = response.result.data;
290 data.email = data.account.contact[0];
291 data.createdAt = data.account.createdAt;
292 data.status = data.account.status;
293 me.setValues(data);
f6710aac 294 },
488be4c2 295 });
f6710aac 296 },
488be4c2
DC
297});
298
8e49a93f
DC
299Ext.define('PVE.node.ACMEDomainEdit', {
300 extend: 'Proxmox.window.Edit',
301 alias: 'widget.pveACMEDomainEdit',
302
303 subject: gettext('Domain'),
304 isCreate: false,
3c6b4c80 305 width: 450,
eff602d8 306 onlineHelp: 'sysadmin_certificate_management',
8e49a93f
DC
307
308 items: [
309 {
310 xtype: 'inputpanel',
311 onGetValues: function(values) {
312 let me = this;
313 let win = me.up('pveACMEDomainEdit');
314 let nodeconfig = win.nodeconfig;
315 let olddomain = win.domain || {};
316
317 let params = {
318 digest: nodeconfig.digest,
319 };
320
321 let configkey = olddomain.configkey;
6ac64c3a 322 let acmeObj = PVE.Parser.parseACME(nodeconfig.acme);
8e49a93f
DC
323
324 if (values.type === 'dns') {
325 if (!olddomain.configkey || olddomain.configkey === 'acme') {
326 // look for first free slot
327 for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
328 if (nodeconfig[`acmedomain${i}`] === undefined) {
329 configkey = `acmedomain${i}`;
330 break;
331 }
332 }
333 if (olddomain.domain) {
334 // we have to remove the domain from the acme domainlist
335 PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain);
336 params.acme = PVE.Parser.printACME(acmeObj);
337 }
338 }
339
340 delete values.type;
341 params[configkey] = PVE.Parser.printPropertyString(values, 'domain');
342 } else {
343 if (olddomain.configkey && olddomain.configkey !== 'acme') {
344 // delete the old dns entry
345 params.delete = [olddomain.configkey];
346 }
347
348 // add new, remove old and make entries unique
349 PVE.Utils.add_domain_to_acme(acmeObj, values.domain);
350 PVE.Utils.remove_domain_from_acme(acmeObj, olddomain.domain);
351 params.acme = PVE.Parser.printACME(acmeObj);
352 }
353
354 return params;
355 },
356 items: [
357 {
358 xtype: 'proxmoxKVComboBox',
359 name: 'type',
3c6b4c80 360 fieldLabel: gettext('Challenge Type'),
8e49a93f 361 allowBlank: false,
3c6b4c80 362 value: 'standalone',
8e49a93f 363 comboItems: [
9c164224 364 ['standalone', 'HTTP'],
8e49a93f
DC
365 ['dns', 'DNS'],
366 ],
367 validator: function(value) {
368 let me = this;
369 let win = me.up('pveACMEDomainEdit');
370 let oldconfigkey = win.domain ? win.domain.configkey : undefined;
371 let val = me.getValue();
372 if (val === 'dns' && (!oldconfigkey || oldconfigkey === 'acme')) {
373 // we have to check if there is a 'acmedomain' slot left
374 let found = false;
375 for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
376 if (!win.nodeconfig[`acmedomain${i}`]) {
377 found = true;
378 }
379 }
380 if (!found) {
381 return gettext('Only 5 Domains with type DNS can be configured');
382 }
383 }
384
385 return true;
386 },
387 listeners: {
388 change: function(cb, value) {
389 let me = this;
390 let view = me.up('pveACMEDomainEdit');
a94b71fb
TL
391 let pluginField = view.down('field[name=plugin]');
392 pluginField.setDisabled(value !== 'dns');
393 pluginField.setHidden(value !== 'dns');
8e49a93f
DC
394 },
395 },
396 },
397 {
398 xtype: 'hidden',
399 name: 'alias',
400 },
8e49a93f
DC
401 {
402 xtype: 'pveACMEPluginSelector',
403 name: 'plugin',
404 disabled: true,
a94b71fb 405 hidden: true,
8e49a93f
DC
406 allowBlank: false,
407 },
a94b71fb
TL
408 {
409 xtype: 'proxmoxtextfield',
410 name: 'domain',
411 allowBlank: false,
412 vtype: 'DnsName',
413 value: '',
414 fieldLabel: gettext('Domain'),
415 },
8e49a93f
DC
416 ],
417 },
418 ],
419
420 initComponent: function() {
421 let me = this;
422
423 if (!me.nodename) {
424 throw 'no nodename given';
425 }
426
427 if (!me.nodeconfig) {
428 throw 'no nodeconfig given';
429 }
430
431 me.isCreate = !me.domain;
8b779b4a
TL
432 if (me.isCreate) {
433 me.domain = `${me.nodename}.`; // TODO: FQDN of node
434 }
8e49a93f
DC
435
436 me.url = `/api2/extjs/nodes/${me.nodename}/config`;
437
438 me.callParent();
439
440 if (!me.isCreate) {
441 me.setValues(me.domain);
8b779b4a
TL
442 } else {
443 me.setValues({ domain: me.domain });
8e49a93f
DC
444 }
445 },
446});
447
fd254233
DC
448Ext.define('pve-acme-domains', {
449 extend: 'Ext.data.Model',
450 fields: ['domain', 'type', 'alias', 'plugin', 'configkey'],
451 idProperty: 'domain',
452});
453
488be4c2 454Ext.define('PVE.node.ACME', {
fd254233
DC
455 extend: 'Ext.grid.Panel',
456 alias: 'widget.pveACMEView',
488be4c2
DC
457
458 margin: '10 0 0 0',
459 title: 'ACME',
460
e666f688
DC
461 emptyText: gettext('No Domains configured'),
462
fd254233
DC
463 viewModel: {
464 data: {
1580b605 465 domaincount: 0,
3071cc5b
DC
466 account: undefined, // the account we display
467 configaccount: undefined, // the account set in the config
fd254233 468 accountEditable: false,
a8b6a80a 469 accountsAvailable: false,
fd254233
DC
470 },
471
472 formulas: {
1580b605 473 canOrder: (get) => !!get('account') && get('domaincount') > 0,
80bd3209 474 editBtnIcon: (get) => 'fa black fa-' + (get('accountEditable') ? 'check' : 'pencil'),
8fc2d938 475 editBtnText: (get) => get('accountEditable') ? gettext('Apply') : gettext('Edit'),
a8b6a80a
TL
476 accountTextHidden: (get) => get('accountEditable') || !get('accountsAvailable'),
477 accountValueHidden: (get) => !get('accountEditable') || !get('accountsAvailable'),
fd254233
DC
478 },
479 },
480
481 controller: {
482 xclass: 'Ext.app.ViewController',
483
a8b6a80a 484 init: function(view) {
a8b6a80a
TL
485 let accountSelector = this.lookup('accountselector');
486 accountSelector.store.on('load', this.onAccountsLoad, this);
487 },
488
489 onAccountsLoad: function(store, records, success) {
80bd3209
DC
490 let me = this;
491 let vm = me.getViewModel();
3071cc5b 492 let configaccount = vm.get('configaccount');
a8b6a80a 493 vm.set('accountsAvailable', records.length > 0);
80bd3209
DC
494 if (me.autoChangeAccount && records.length > 0) {
495 me.changeAccount(records[0].data.name, () => {
31c9edc8 496 vm.set('accountEditable', false);
80bd3209 497 me.reload();
31c9edc8
TL
498 });
499 me.autoChangeAccount = false;
3071cc5b
DC
500 } else if (configaccount) {
501 if (store.findExact('name', configaccount) !== -1) {
502 vm.set('account', configaccount);
503 } else {
504 vm.set('account', null);
505 }
31c9edc8 506 }
a8b6a80a
TL
507 },
508
fd254233
DC
509 addDomain: function() {
510 let me = this;
511 let view = me.getView();
512
513 Ext.create('PVE.node.ACMEDomainEdit', {
514 nodename: view.nodename,
515 nodeconfig: view.nodeconfig,
516 apiCallDone: function() {
517 me.reload();
518 },
519 }).show();
520 },
521
522 editDomain: function() {
523 let me = this;
524 let view = me.getView();
525
526 let selection = view.getSelection();
527 if (selection.length < 1) return;
528
529 Ext.create('PVE.node.ACMEDomainEdit', {
530 nodename: view.nodename,
531 nodeconfig: view.nodeconfig,
532 domain: selection[0].data,
533 apiCallDone: function() {
534 me.reload();
535 },
536 }).show();
537 },
538
539 removeDomain: function() {
540 let me = this;
541 let view = me.getView();
542 let selection = view.getSelection();
543 if (selection.length < 1) return;
544
545 let rec = selection[0].data;
546 let params = {};
547 if (rec.configkey !== 'acme') {
548 params.delete = rec.configkey;
549 } else {
550 let acme = PVE.Parser.parseACME(view.nodeconfig.acme);
551 PVE.Utils.remove_domain_from_acme(acme, rec.domain);
552 params.acme = PVE.Parser.printACME(acme);
553 }
554
555 Proxmox.Utils.API2Request({
556 method: 'PUT',
557 url: `/nodes/${view.nodename}/config`,
558 params,
559 success: function(response, opt) {
560 me.reload();
561 },
562 failure: function(response, opt) {
563 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
564 },
565 });
566 },
567
568 toggleEditAccount: function() {
569 let me = this;
570 let vm = me.getViewModel();
571 let editable = vm.get('accountEditable');
572 if (editable) {
573 me.changeAccount(vm.get('account'), function() {
574 vm.set('accountEditable', false);
575 me.reload();
576 });
577 } else {
578 vm.set('accountEditable', true);
579 }
580 },
581
582 changeAccount: function(account, callback) {
583 let me = this;
584 let view = me.getView();
585 let params = {};
586
587 let acme = PVE.Parser.parseACME(view.nodeconfig.acme);
588 acme.account = account;
589 params.acme = PVE.Parser.printACME(acme);
590
591 Proxmox.Utils.API2Request({
592 method: 'PUT',
593 waitMsgTarget: view,
594 url: `/nodes/${view.nodename}/config`,
595 params,
596 success: function(response, opt) {
597 if (Ext.isFunction(callback)) {
598 callback();
599 }
600 },
601 failure: function(response, opt) {
602 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
603 },
604 });
605 },
606
607 order: function() {
608 let me = this;
609 let view = me.getView();
610
611 Proxmox.Utils.API2Request({
612 method: 'POST',
613 params: {
614 force: 1,
615 },
616 url: `/nodes/${view.nodename}/certificates/acme/certificate`,
617 success: function(response, opt) {
618 Ext.create('Proxmox.window.TaskViewer', {
619 upid: response.result.data,
620 taskDone: function(success) {
621 me.orderFinished(success);
622 },
623 }).show();
624 },
625 failure: function(response, opt) {
626 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
627 },
628 });
629 },
630
631 orderFinished: function(success) {
632 if (!success) return;
72cfb3d4
FS
633 // reload only if the Web UI is open on the same node that the cert was ordered for
634 if (this.getView().nodename !== Proxmox.NodeName) {
635 return;
636 }
fd254233
DC
637 var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
638 Ext.getBody().mask(txt, ['pve-static-mask']);
639 // reload after 10 seconds automatically
640 Ext.defer(function() {
641 window.location.reload(true);
642 }, 10000);
643 },
644
645 reload: function() {
646 let me = this;
647 let view = me.getView();
648 view.rstore.load();
649 },
650
31c9edc8
TL
651 addAccount: function() {
652 let me = this;
653 Ext.create('PVE.node.ACMEAccountCreate', {
654 autoShow: true,
655 taskDone: function() {
656 me.reload();
657 let accountSelector = me.lookup('accountselector');
658 me.autoChangeAccount = true;
659 accountSelector.store.load();
660 },
661 });
fd254233
DC
662 },
663 },
664
488be4c2
DC
665 tbar: [
666 {
fd254233
DC
667 xtype: 'proxmoxButton',
668 text: gettext('Add'),
669 handler: 'addDomain',
670 selModel: false,
671 },
672 {
673 xtype: 'proxmoxButton',
674 text: gettext('Edit'),
675 disabled: true,
676 handler: 'editDomain',
677 },
678 {
679 xtype: 'proxmoxStdRemoveButton',
680 handler: 'removeDomain',
488be4c2 681 },
fd254233 682 '-',
488be4c2
DC
683 {
684 xtype: 'button',
fd254233 685 reference: 'order',
a8b6a80a 686 text: gettext('Order Certificates Now'),
31c9edc8 687 bind: {
1580b605 688 disabled: '{!canOrder}',
31c9edc8 689 },
fd254233
DC
690 handler: 'order',
691 },
692 '-',
693 {
694 xtype: 'displayfield',
a8b6a80a
TL
695 value: gettext('Using Account') + ':',
696 bind: {
697 hidden: '{!accountsAvailable}',
698 },
fd254233
DC
699 },
700 {
701 xtype: 'displayfield',
702 reference: 'accounttext',
3071cc5b 703 renderer: (val) => val || Proxmox.Utils.NoneText,
fd254233
DC
704 bind: {
705 value: '{account}',
a8b6a80a 706 hidden: '{accountTextHidden}',
fd254233
DC
707 },
708 },
709 {
710 xtype: 'pveACMEAccountSelector',
711 hidden: true,
712 reference: 'accountselector',
713 bind: {
714 value: '{account}',
a8b6a80a 715 hidden: '{accountValueHidden}',
fd254233 716 },
488be4c2
DC
717 },
718 {
719 xtype: 'button',
fd254233 720 iconCls: 'fa black fa-pencil',
fd254233 721 bind: {
a8b6a80a 722 iconCls: '{editBtnIcon}',
8fc2d938 723 text: '{editBtnText}',
a8b6a80a 724 hidden: '{!accountsAvailable}',
fd254233
DC
725 },
726 handler: 'toggleEditAccount',
488be4c2 727 },
a8b6a80a
TL
728 {
729 xtype: 'displayfield',
730 value: gettext('No Account available.'),
731 bind: {
732 hidden: '{accountsAvailable}',
733 },
734 },
488be4c2
DC
735 {
736 xtype: 'button',
fd254233
DC
737 hidden: true,
738 reference: 'accountlink',
31c9edc8 739 text: gettext('Add ACME Account'),
a8b6a80a
TL
740 bind: {
741 hidden: '{accountsAvailable}',
742 },
31c9edc8 743 handler: 'addAccount',
80bd3209 744 },
488be4c2
DC
745 ],
746
fd254233
DC
747 updateStore: function(store, records, success) {
748 let me = this;
749 let data = [];
750 let rec;
751 if (success && records.length > 0) {
752 rec = records[0];
753 } else {
754 rec = {
80bd3209 755 data: {},
fd254233 756 };
488be4c2 757 }
488be4c2 758
fd254233 759 me.nodeconfig = rec.data; // save nodeconfig for updates
488be4c2 760
fd254233 761 let account = 'default';
488be4c2 762
fd254233
DC
763 if (rec.data.acme) {
764 let obj = PVE.Parser.parseACME(rec.data.acme);
765 (obj.domains || []).forEach(domain => {
766 if (domain === '') return;
767 let record = {
768 domain,
769 type: 'standalone',
770 configkey: 'acme',
771 };
772 data.push(record);
773 });
488be4c2 774
fd254233
DC
775 if (obj.account) {
776 account = obj.account;
777 }
778 }
488be4c2 779
fd254233
DC
780 let vm = me.getViewModel();
781 let oldaccount = vm.get('account');
782
783 // account changed, and we do not edit currently, load again to verify
784 if (oldaccount !== account && !vm.get('accountEditable')) {
3071cc5b
DC
785 vm.set('configaccount', account);
786 me.lookup('accountselector').store.load();
fd254233 787 }
488be4c2 788
fd254233
DC
789 for (let i = 0; i < PVE.Utils.acmedomain_count; i++) {
790 let acmedomain = rec.data[`acmedomain${i}`];
791 if (!acmedomain) continue;
488be4c2 792
fd254233
DC
793 let record = PVE.Parser.parsePropertyString(acmedomain, 'domain');
794 record.type = 'dns';
795 record.configkey = `acmedomain${i}`;
796 data.push(record);
797 }
798
1580b605 799 vm.set('domaincount', data.length);
fd254233 800 me.store.loadData(data, false);
488be4c2
DC
801 },
802
803 listeners: {
fd254233 804 itemdblclick: 'editDomain',
488be4c2
DC
805 },
806
fd254233
DC
807 columns: [
808 {
809 dataIndex: 'domain',
3c6b4c80 810 flex: 5,
fd254233
DC
811 text: gettext('Domain'),
812 },
813 {
814 dataIndex: 'type',
3c6b4c80 815 flex: 1,
fd254233
DC
816 text: gettext('Type'),
817 },
818 {
819 dataIndex: 'plugin',
3c6b4c80 820 flex: 1,
fd254233
DC
821 text: gettext('Plugin'),
822 },
823 ],
488be4c2
DC
824
825 initComponent: function() {
826 var me = this;
827
828 if (!me.nodename) {
829 throw "no nodename given";
830 }
831
fd254233 832 me.rstore = Ext.create('Proxmox.data.UpdateStore', {
1b90cfc6 833 interval: 10 * 1000,
fd254233
DC
834 autoStart: true,
835 storeid: `pve-node-domains-${me.nodename}`,
836 proxy: {
837 type: 'proxmox',
838 url: `/api2/json/nodes/${me.nodename}/config`,
839 },
840 });
841
842 me.store = Ext.create('Ext.data.Store', {
843 model: 'pve-acme-domains',
844 sorters: 'domain',
845 });
488be4c2
DC
846
847 me.callParent();
fd254233
DC
848 me.mon(me.rstore, 'load', 'updateStore', me);
849 Proxmox.Utils.monStoreErrors(me, me.rstore);
1f249769 850 me.on('destroy', me.rstore.stopUpdate, me.rstore);
fd254233 851 },
488be4c2 852});