]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/grid/FirewallRules.js
ext6migrate: set valueField as a class property
[pve-manager.git] / www / manager6 / grid / FirewallRules.js
CommitLineData
435cce27
DM
1Ext.define('PVE.form.FWMacroSelector', {
2 extend: 'PVE.form.ComboGrid',
3 alias: 'widget.pveFWMacroSelector',
3d990919
EK
4 allowBlank: true,
5 autoSelect: false,
6 valueField: 'macro',
7 displayField: 'macro',
8 listConfig: {
9 columns: [
10 {
11 header: gettext('Macro'),
12 dataIndex: 'macro',
13 hideable: false,
14 width: 100
15 },
16 {
17 header: gettext('Description'),
18 flex: 1,
19 dataIndex: 'descr'
20 }
21 ]
22 },
435cce27
DM
23 initComponent: function() {
24 var me = this;
25
26 var store = Ext.create('Ext.data.Store', {
27 autoLoad: true,
28 fields: [ 'macro', 'descr' ],
29 idProperty: 'macro',
30 proxy: {
31 type: 'pve',
32 url: "/api2/json/cluster/firewall/macros"
33 },
34 sorters: {
35 property: 'macro',
36 order: 'DESC'
37 }
38 });
39
40 Ext.apply(me, {
41 store: store,
435cce27
DM
42 });
43
44 me.callParent();
45 }
46});
47
48Ext.define('PVE.FirewallRulePanel', {
49 extend: 'PVE.panel.InputPanel',
50
51 allow_iface: false,
52
53 list_refs_url: undefined,
54
55 onGetValues: function(values) {
56 var me = this;
57
58 // hack: editable ComboGrid returns nothing when empty, so we need to set ''
59 // Also, disabled text fields return nothing, so we need to set ''
60
61 Ext.Array.each(['source', 'dest', 'proto', 'sport', 'dport'], function(key) {
62 if (values[key] === undefined) {
63 values[key] = '';
64 }
65 });
66
67 delete values.modified_marker;
68
69 return values;
70 },
71
72 initComponent : function() {
73 var me = this;
74
75 if (!me.list_refs_url) {
76 throw "no list_refs_url specified";
77 }
78
79 me.column1 = [
80 {
81 // hack: we use this field to mark the form 'dirty' when the
82 // record has errors- so that the user can safe the unmodified
83 // form again.
84 xtype: 'hiddenfield',
85 name: 'modified_marker',
86 value: '',
87 },
88 {
89 xtype: 'pveKVComboBox',
90 name: 'type',
91 value: 'in',
e7bc7f31 92 comboItems: [['in', 'in'], ['out', 'out']],
435cce27
DM
93 fieldLabel: gettext('Direction'),
94 allowBlank: false
95 },
96 {
97 xtype: 'pveKVComboBox',
98 name: 'action',
99 value: 'ACCEPT',
e7bc7f31 100 comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
435cce27
DM
101 fieldLabel: gettext('Action'),
102 allowBlank: false
103 }
104 ];
105
106 if (me.allow_iface) {
107 me.column1.push({
108 xtype: 'pvetextfield',
109 name: 'iface',
110 deleteEmpty: !me.create,
111 value: '',
112 fieldLabel: gettext('Interface')
113 });
114 } else {
115 me.column1.push({
116 xtype: 'displayfield',
117 fieldLabel: '',
118 height: 22, // hack: set same height as text fields
119 value: ''
120 });
121 }
122
fa94a977 123 me.column1.push(
435cce27
DM
124 {
125 xtype: 'displayfield',
126 fieldLabel: '',
127 height: 7,
128 value: ''
129 },
130 {
131 xtype: 'pveIPRefSelector',
132 name: 'source',
133 autoSelect: false,
134 editable: true,
135 base_url: me.list_refs_url,
136 value: '',
137 fieldLabel: gettext('Source')
138
139 },
140 {
141 xtype: 'pveIPRefSelector',
142 name: 'dest',
143 autoSelect: false,
144 editable: true,
145 base_url: me.list_refs_url,
146 value: '',
147 fieldLabel: gettext('Destination')
148 }
fa94a977 149 );
435cce27
DM
150
151
152 me.column2 = [
153 {
154 xtype: 'pvecheckbox',
155 name: 'enable',
156 checked: false,
157 height: 22, // hack: set same height as text fields
158 uncheckedValue: 0,
159 fieldLabel: gettext('Enable')
160 },
161 {
162 xtype: 'pveFWMacroSelector',
163 name: 'macro',
164 value: '',
165 fieldLabel: gettext('Macro'),
166 allowBlank: true,
167 listeners: {
168 change: function(f, value) {
169 if (value === '') {
170 me.down('field[name=proto]').setDisabled(false);
171 me.down('field[name=sport]').setDisabled(false);
172 me.down('field[name=dport]').setDisabled(false);
173 } else {
174 me.down('field[name=proto]').setDisabled(true);
175 me.down('field[name=proto]').setValue('');
176 me.down('field[name=sport]').setDisabled(true);
177 me.down('field[name=sport]').setValue('');
178 me.down('field[name=dport]').setDisabled(true);
179 me.down('field[name=dport]').setValue('');
180 }
181 }
182 }
183 },
184 {
185 xtype: 'pveIPProtocolSelector',
186 name: 'proto',
187 autoSelect: false,
188 editable: true,
189 value: '',
190 fieldLabel: gettext('Protocol')
191 },
192 {
193 xtype: 'displayfield',
194 fieldLabel: '',
195 height: 7,
196 value: ''
197 },
198 {
199 xtype: 'textfield',
200 name: 'sport',
201 value: '',
202 fieldLabel: gettext('Source port')
203 },
204 {
205 xtype: 'textfield',
206 name: 'dport',
207 height: 22, // hack: set same height as text fields
208 value: '',
209 fieldLabel: gettext('Dest. port')
210 }
211 ];
212
213 me.columnB = [
214 {
215 xtype: 'textfield',
216 name: 'comment',
217 value: '',
218 fieldLabel: gettext('Comment')
219 }
220 ];
221
222 me.callParent();
223 }
224});
225
226Ext.define('PVE.FirewallRuleEdit', {
227 extend: 'PVE.window.Edit',
228
229 base_url: undefined,
230 list_refs_url: undefined,
231
232 allow_iface: false,
233
234 initComponent : function() {
235 /*jslint confusion: true */
236 var me = this;
237
238 if (!me.base_url) {
239 throw "no base_url specified";
240 }
241 if (!me.list_refs_url) {
242 throw "no list_refs_url specified";
243 }
244
245 me.create = (me.rule_pos === undefined);
246
247 if (me.create) {
248 me.url = '/api2/extjs' + me.base_url;
249 me.method = 'POST';
250 } else {
251 me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
252 me.method = 'PUT';
253 }
254
255 var ipanel = Ext.create('PVE.FirewallRulePanel', {
256 create: me.create,
257 list_refs_url: me.list_refs_url,
258 allow_iface: me.allow_iface,
259 rule_pos: me.rule_pos
260 });
261
262 Ext.apply(me, {
263 subject: gettext('Rule'),
264 isAdd: true,
265 items: [ ipanel ]
266 });
267
268 me.callParent();
269
270 if (!me.create) {
271 me.load({
272 success: function(response, options) {
273 var values = response.result.data;
274 ipanel.setValues(values);
275 if (values.errors) {
276 var field = me.query('[isFormField][name=modified_marker]')[0];
277 field.setValue(1);
278 Ext.Function.defer(function() {
279 var form = ipanel.up('form').getForm();
280 form.markInvalid(values.errors)
281 }, 100);
282 }
283 }
284 });
285 }
286 }
287});
288
289Ext.define('PVE.FirewallGroupRuleEdit', {
290 extend: 'PVE.window.Edit',
291
292 base_url: undefined,
293
294 allow_iface: false,
295
296 initComponent : function() {
297 /*jslint confusion: true */
298 var me = this;
299
300 me.create = (me.rule_pos === undefined);
301
302 if (me.create) {
303 me.url = '/api2/extjs' + me.base_url;
304 me.method = 'POST';
305 } else {
306 me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
307 me.method = 'PUT';
308 }
309
310 var column1 = [
311 {
312 xtype: 'hiddenfield',
313 name: 'type',
314 value: 'group'
315 },
316 {
317 xtype: 'pveSecurityGroupsSelector',
318 name: 'action',
319 value: '',
320 fieldLabel: gettext('Security Group'),
321 allowBlank: false
322 }
323 ];
324
325 if (me.allow_iface) {
326 column1.push({
327 xtype: 'pvetextfield',
328 name: 'iface',
329 deleteEmpty: !me.create,
330 value: '',
331 fieldLabel: gettext('Interface')
332 });
333 }
334
335 var ipanel = Ext.create('PVE.panel.InputPanel', {
336 create: me.create,
337 column1: column1,
338 column2: [
339 {
340 xtype: 'pvecheckbox',
341 name: 'enable',
342 checked: false,
343 height: 22, // hack: set same height as text fields
344 uncheckedValue: 0,
345 fieldLabel: gettext('Enable')
346 }
347 ],
348 columnB: [
349 {
350 xtype: 'textfield',
351 name: 'comment',
352 value: '',
353 fieldLabel: gettext('Comment')
354 }
355 ]
356 });
357
358 Ext.apply(me, {
359 subject: gettext('Rule'),
360 isAdd: true,
361 items: [ ipanel ]
362 });
363
364 me.callParent();
365
366 if (!me.create) {
367 me.load({
368 success: function(response, options) {
369 var values = response.result.data;
370 ipanel.setValues(values);
371 }
372 });
373 }
374 }
375});
376
377Ext.define('PVE.FirewallRules', {
378 extend: 'Ext.grid.Panel',
379 alias: 'widget.pveFirewallRules',
380
381 base_url: undefined,
382 list_refs_url: undefined,
383
384 addBtn: undefined,
385 removeBtn: undefined,
386 editBtn: undefined,
387 groupBtn: undefined,
388
389 tbar_prefix: undefined,
390
391 allow_groups: true,
392 allow_iface: false,
393
394 setBaseUrl: function(url) {
395 var me = this;
396
397 me.base_url = url;
398
399 if (url === undefined) {
400 me.addBtn.setDisabled(true);
401 if (me.groupBtn) {
402 me.groupBtn.setDisabled(true);
403 }
404 me.store.removeAll();
405 } else {
406 me.addBtn.setDisabled(false);
407 if (me.groupBtn) {
408 me.groupBtn.setDisabled(false);
409 }
410 me.store.setProxy({
411 type: 'pve',
412 url: '/api2/json' + url
413 });
414
415 me.store.load();
416 }
417 },
418
419 moveRule: function(from, to) {
420 var me = this;
421
422 if (!me.base_url) {
423 return;
424 }
425
426 PVE.Utils.API2Request({
427 url: me.base_url + "/" + from,
428 method: 'PUT',
429 params: { moveto: to },
430 waitMsgTarget: me,
431 failure: function(response, options) {
432 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
433 },
434 callback: function() {
435 me.store.load();
436 }
437 });
438 },
439
440 updateRule: function(rule) {
441 var me = this;
442
443 if (!me.base_url) {
444 return;
445 }
446
447 rule.enable = rule.enable ? 1 : 0;
448
449 var pos = rule.pos;
450 delete rule.pos;
451 delete rule.errors;
452
453 PVE.Utils.API2Request({
454 url: me.base_url + '/' + pos.toString(),
455 method: 'PUT',
456 params: rule,
457 waitMsgTarget: me,
458 failure: function(response, options) {
459 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
460 },
461 callback: function() {
462 me.store.load();
463 }
464 });
465 },
466
467 deleteRule: function(rule) {
468 var me = this;
469
470 if (!me.base_url) {
471 return;
472 }
473
474 PVE.Utils.API2Request({
475 url: me.base_url + '/' + rule.pos.toString() +
476 '?digest=' + encodeURIComponent(rule.digest),
477 method: 'DELETE',
478 waitMsgTarget: me,
479 failure: function(response, options) {
480 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
481 },
482 callback: function() {
483 me.store.load();
484 }
485 });
486 },
487
488 initComponent: function() {
489 /*jslint confusion: true */
490 var me = this;
491
492 if (!me.list_refs_url) {
493 throw "no list_refs_url specified";
494 }
495
f3578e26 496 var store = Ext.create('Ext.data.Store',{
435cce27
DM
497 model: 'pve-fw-rule'
498 });
499
500 var reload = function() {
501 store.load();
502 };
503
504 var sm = Ext.create('Ext.selection.RowModel', {});
505
506 var run_editor = function() {
507 var rec = sm.getSelection()[0];
508 if (!rec) {
509 return;
510 }
511 var type = rec.data.type;
512
513 var editor;
514 if (type === 'in' || type === 'out') {
515 editor = 'PVE.FirewallRuleEdit';
516 } else if (type === 'group') {
517 editor = 'PVE.FirewallGroupRuleEdit';
518 } else {
519 return;
520 }
521
522 var win = Ext.create(editor, {
523 digest: rec.data.digest,
524 allow_iface: me.allow_iface,
525 base_url: me.base_url,
526 list_refs_url: me.list_refs_url,
527 rule_pos: rec.data.pos
528 });
529
530 win.show();
531 win.on('destroy', reload);
532 };
533
f3578e26 534 me.editBtn = Ext.create('PVE.button.Button',{
435cce27
DM
535 text: gettext('Edit'),
536 disabled: true,
537 selModel: sm,
538 handler: run_editor
539 });
540
541 me.addBtn = Ext.create('Ext.Button', {
542 text: gettext('Add'),
543 disabled: true,
544 handler: function() {
545 var win = Ext.create('PVE.FirewallRuleEdit', {
546 allow_iface: me.allow_iface,
547 base_url: me.base_url,
548 list_refs_url: me.list_refs_url
549 });
550 win.on('destroy', reload);
551 win.show();
552 }
553 });
554
555 if (me.allow_groups) {
556 me.groupBtn = Ext.create('Ext.Button', {
557 text: gettext('Insert') + ': ' +
558 gettext('Security Group'),
559 disabled: true,
560 handler: function() {
561 var win = Ext.create('PVE.FirewallGroupRuleEdit', {
562 allow_iface: me.allow_iface,
563 base_url: me.base_url
564 });
565 win.on('destroy', reload);
566 win.show();
567 }
568 });
569 }
570
f3578e26 571 me.removeBtn = Ext.create('PVE.button.Button',{
435cce27
DM
572 text: gettext('Remove'),
573 selModel: sm,
574 disabled: true,
575 handler: function() {
576 var rec = sm.getSelection()[0];
577 if (!rec) {
578 return;
579 }
580 me.deleteRule(rec.data);
581 }
582 });
583
584 var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
585 tbar.push(me.addBtn);
586 if (me.groupBtn) {
587 tbar.push(me.groupBtn);
588 }
fa94a977 589 tbar.push(me.removeBtn, me.editBtn);
435cce27
DM
590
591 var render_errors = function(name, value, metaData, record) {
592 var errors = record.data.errors;
593 if (errors && errors[name]) {
594 metaData.tdCls = 'x-form-invalid-field';
595 var html = '<p>' + Ext.htmlEncode(errors[name]) + '</p>';
596 metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' +
597 html.replace(/\"/g,'&quot;') + '"';
598 }
599 return value;
600 };
601
602 var columns = [
603 {
604 // similar to xtype: 'rownumberer',
605 dataIndex: 'pos',
606 resizable: false,
607 width: 23,
608 sortable: false,
609 align: 'right',
610 hideable: false,
611 menuDisabled: true,
612 renderer: function(value, metaData, record, rowIdx, colIdx, store) {
613 metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
614 if (value >= 0) {
615 return value;
616 }
617 return '';
618 }
619 },
620 {
621 xtype: 'checkcolumn',
622 header: gettext('Enable'),
623 dataIndex: 'enable',
624 listeners: {
7a4c3133
EK
625 checkchange: function(column, recordIndex, checked) {
626 var record = me.getStore().getData().items[recordIndex];
435cce27
DM
627 record.commit();
628 var data = {};
7a4c3133 629 Ext.Array.forEach(record.getFields(), function(field) {
435cce27
DM
630 data[field.name] = record.get(field.name);
631 });
632 if (!me.allow_iface || !data.iface) {
633 delete data.iface;
634 }
635 me.updateRule(data);
636 }
637 },
638 width: 50
639 },
640 {
641 header: gettext('Type'),
642 dataIndex: 'type',
643 renderer: function(value, metaData, record) {
644 return render_errors('type', value, metaData, record);
645 },
646 width: 50
647 },
648 {
649 header: gettext('Action'),
650 dataIndex: 'action',
651 renderer: function(value, metaData, record) {
652 return render_errors('action', value, metaData, record);
653 },
654 width: 80
655 },
656 {
657 header: gettext('Macro'),
658 dataIndex: 'macro',
659 renderer: function(value, metaData, record) {
660 return render_errors('macro', value, metaData, record);
661 },
662 width: 80
663 }
664 ];
665
666 if (me.allow_iface) {
667 columns.push({
668 header: gettext('Interface'),
669 dataIndex: 'iface',
670 renderer: function(value, metaData, record) {
671 return render_errors('iface', value, metaData, record);
672 },
673 width: 80
674 });
675 }
676
fa94a977 677 columns.push(
435cce27
DM
678 {
679 header: gettext('Source'),
680 dataIndex: 'source',
681 renderer: function(value, metaData, record) {
682 return render_errors('source', value, metaData, record);
683 },
684 width: 100
685 },
686 {
687 header: gettext('Destination'),
688 dataIndex: 'dest',
689 renderer: function(value, metaData, record) {
690 return render_errors('dest', value, metaData, record);
691 },
692 width: 100
693 },
694 {
695 header: gettext('Protocol'),
696 dataIndex: 'proto',
697 renderer: function(value, metaData, record) {
698 return render_errors('proto', value, metaData, record);
699 },
700 width: 100
701 },
702 {
703 header: gettext('Dest. port'),
704 dataIndex: 'dport',
705 renderer: function(value, metaData, record) {
706 return render_errors('dport', value, metaData, record);
707 },
708 width: 100
709 },
710 {
711 header: gettext('Source port'),
712 dataIndex: 'sport',
713 renderer: function(value, metaData, record) {
714 return render_errors('sport', value, metaData, record);
715 },
716 width: 100
717 },
718 {
719 header: gettext('Comment'),
720 dataIndex: 'comment',
721 flex: 1,
722 renderer: function(value, metaData, record) {
723 return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
724 }
725 }
fa94a977 726 );
435cce27
DM
727
728 Ext.apply(me, {
729 store: store,
730 selModel: sm,
731 tbar: tbar,
732 viewConfig: {
733 plugins: [
734 {
735 ptype: 'gridviewdragdrop',
736 dragGroup: 'FWRuleDDGroup',
737 dropGroup: 'FWRuleDDGroup'
738 }
739 ],
740 listeners: {
741 beforedrop: function(node, data, dropRec, dropPosition) {
742 if (!dropRec) {
743 return false; // empty view
744 }
745 var moveto = dropRec.get('pos');
746 if (dropPosition === 'after') {
747 moveto++;
748 }
749 var pos = data.records[0].get('pos');
750 me.moveRule(pos, moveto);
751 return 0;
752 },
753 itemdblclick: run_editor
754 }
755 },
756 sortableColumns: false,
757 columns: columns
758 });
759
760 me.callParent();
761
762 if (me.base_url) {
763 me.setBaseUrl(me.base_url); // load
764 }
765 }
766}, function() {
767
768 Ext.define('pve-fw-rule', {
769 extend: 'Ext.data.Model',
770 fields: [ { name: 'enable', type: 'boolean' },
771 'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
772 'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
773 idProperty: 'pos'
774 });
775
776});