]>
Commit | Line | Data |
---|---|---|
435cce27 DM |
1 | Ext.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 | ||
48 | Ext.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 | ||
223 | Ext.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 | ||
286 | Ext.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 | ||
373 | Ext.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,'"') + '"'; | |
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 | }); |