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