]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/panel/IPSet.js
ui: firewall: refactor privilege checks and prevent double click
[pve-manager.git] / www / manager6 / panel / IPSet.js
CommitLineData
1774f148
DC
1Ext.define('pve-fw-ipsets', {
2 extend: 'Ext.data.Model',
8058410f 3 fields: ['name', 'comment', 'digest'],
f6710aac 4 idProperty: 'name',
1774f148
DC
5});
6
03ab9fba
DM
7Ext.define('PVE.IPSetList', {
8 extend: 'Ext.grid.Panel',
9 alias: 'widget.pveIPSetList',
10
123e1c80
DC
11 stateful: true,
12 stateId: 'grid-firewall-ipsetlist',
13
03ab9fba
DM
14 ipset_panel: undefined,
15
16 base_url: undefined,
17
18 addBtn: undefined,
19 removeBtn: undefined,
20 editBtn: undefined,
21
22 initComponent: function() {
03ab9fba
DM
23 var me = this;
24
202298c1 25 if (typeof me.ipset_panel === 'undefined') {
03ab9fba
DM
26 throw "no rule panel specified";
27 }
28
202298c1 29 if (typeof me.ipset_panel === 'undefined') {
03ab9fba
DM
30 throw "no base_url specified";
31 }
32
33 var store = new Ext.data.Store({
1774f148 34 model: 'pve-fw-ipsets',
03ab9fba 35 proxy: {
56a353b9 36 type: 'proxmox',
f6710aac 37 url: "/api2/json" + me.base_url,
03ab9fba 38 },
03ab9fba
DM
39 sorters: {
40 property: 'name',
392e3cf1 41 direction: 'ASC',
f6710aac 42 },
03ab9fba
DM
43 });
44
2e37e779 45 var caps = Ext.state.Manager.get('GuiCap');
1056e10c 46 let canEdit = !!caps.vms['VM.Config.Network'] || !!caps.dc['Sys.Modify'] || !!caps.nodes['Sys.Modify'];
2e37e779 47
03ab9fba
DM
48 var sm = Ext.create('Ext.selection.RowModel', {});
49
50 var reload = function() {
51 var oldrec = sm.getSelection()[0];
52 store.load(function(records, operation, success) {
53 if (oldrec) {
8267aa63 54 var rec = store.findRecord('name', oldrec.data.name, 0, false, true, true);
03ab9fba
DM
55 if (rec) {
56 sm.select(rec);
57 }
58 }
59 });
60 };
61
62 var run_editor = function() {
63 var rec = sm.getSelection()[0];
1056e10c 64 if (!rec || !canEdit) {
03ab9fba
DM
65 return;
66 }
9fccc702 67 var win = Ext.create('Proxmox.window.Edit', {
03ab9fba
DM
68 subject: "IPSet '" + rec.data.name + "'",
69 url: me.base_url,
70 method: 'POST',
71 digest: rec.data.digest,
72 items: [
73 {
74 xtype: 'hiddenfield',
75 name: 'rename',
f6710aac 76 value: rec.data.name,
03ab9fba
DM
77 },
78 {
79 xtype: 'textfield',
80 name: 'name',
81 value: rec.data.name,
82 fieldLabel: gettext('Name'),
f6710aac 83 allowBlank: false,
03ab9fba
DM
84 },
85 {
86 xtype: 'textfield',
87 name: 'comment',
88 value: rec.data.comment,
f6710aac
TL
89 fieldLabel: gettext('Comment'),
90 },
91 ],
03ab9fba
DM
92 });
93 win.show();
94 win.on('destroy', reload);
95 };
96
5720fafa 97 me.editBtn = new Proxmox.button.Button({
03ab9fba
DM
98 text: gettext('Edit'),
99 disabled: true,
1056e10c 100 enableFn: rec => canEdit,
03ab9fba 101 selModel: sm,
f6710aac 102 handler: run_editor,
03ab9fba
DM
103 });
104
5720fafa 105 me.addBtn = new Proxmox.button.Button({
03ab9fba
DM
106 text: gettext('Create'),
107 handler: function() {
108 sm.deselectAll();
9fccc702 109 var win = Ext.create('Proxmox.window.Edit', {
03ab9fba
DM
110 subject: 'IPSet',
111 url: me.base_url,
112 method: 'POST',
113 items: [
114 {
115 xtype: 'textfield',
116 name: 'name',
117 value: '',
118 fieldLabel: gettext('Name'),
f6710aac 119 allowBlank: false,
03ab9fba
DM
120 },
121 {
122 xtype: 'textfield',
123 name: 'comment',
124 value: '',
f6710aac
TL
125 fieldLabel: gettext('Comment'),
126 },
127 ],
03ab9fba
DM
128 });
129 win.show();
130 win.on('destroy', reload);
f6710aac 131 },
03ab9fba
DM
132 });
133
3b1ca3ff 134 me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
1056e10c 135 enableFn: rec => canEdit,
03ab9fba 136 selModel: sm,
3b1ca3ff 137 baseurl: me.base_url + '/',
f6710aac 138 callback: reload,
03ab9fba
DM
139 });
140
141 Ext.apply(me, {
142 store: store,
8058410f 143 tbar: ['<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn],
03ab9fba
DM
144 selModel: sm,
145 columns: [
123e1c80 146 { header: 'IPSet', dataIndex: 'name', width: '100' },
f6710aac 147 { header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 },
03ab9fba
DM
148 ],
149 listeners: {
150 itemdblclick: run_editor,
202298c1 151 select: function(_, rec) {
03ab9fba
DM
152 var url = me.base_url + '/' + rec.data.name;
153 me.ipset_panel.setBaseUrl(url);
154 },
155 deselect: function() {
156 me.ipset_panel.setBaseUrl(undefined);
157 },
f6710aac
TL
158 show: reload,
159 },
03ab9fba
DM
160 });
161
1056e10c 162 if (!canEdit) {
2e37e779
AD
163 me.addBtn.setDisabled(true);
164 }
165
03ab9fba
DM
166 me.callParent();
167
168 store.load();
f6710aac 169 },
03ab9fba
DM
170});
171
172Ext.define('PVE.IPSetCidrEdit', {
9fccc702 173 extend: 'Proxmox.window.Edit',
03ab9fba
DM
174
175 cidr: undefined,
176
8058410f 177 initComponent: function() {
03ab9fba
DM
178 var me = this;
179
53e3ea84 180 me.isCreate = me.cidr === undefined;
03ab9fba
DM
181
182
d5e771ce 183 if (me.isCreate) {
03ab9fba
DM
184 me.url = '/api2/extjs' + me.base_url;
185 me.method = 'POST';
186 } else {
187 me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
188 me.method = 'PUT';
189 }
190
191 var column1 = [];
192
d5e771ce 193 if (me.isCreate) {
03ab9fba
DM
194 if (!me.list_refs_url) {
195 throw "no alias_base_url specified";
196 }
197
198 column1.push({
199 xtype: 'pveIPRefSelector',
200 name: 'cidr',
201 ref_type: 'alias',
202 autoSelect: false,
203 editable: true,
204 base_url: me.list_refs_url,
205 value: '',
f6710aac 206 fieldLabel: gettext('IP/CIDR'),
03ab9fba
DM
207 });
208 } else {
209 column1.push({
210 xtype: 'displayfield',
211 name: 'cidr',
03ab9fba 212 value: '',
f6710aac 213 fieldLabel: gettext('IP/CIDR'),
03ab9fba
DM
214 });
215 }
216
ef4ef788 217 var ipanel = Ext.create('Proxmox.panel.InputPanel', {
d5e771ce 218 isCreate: me.isCreate,
03ab9fba
DM
219 column1: column1,
220 column2: [
221 {
896c0d50 222 xtype: 'proxmoxcheckbox',
03ab9fba
DM
223 name: 'nomatch',
224 checked: false,
03ab9fba 225 uncheckedValue: 0,
f6710aac
TL
226 fieldLabel: 'nomatch',
227 },
03ab9fba
DM
228 ],
229 columnB: [
230 {
231 xtype: 'textfield',
232 name: 'comment',
233 value: '',
f6710aac
TL
234 fieldLabel: gettext('Comment'),
235 },
236 ],
03ab9fba
DM
237 });
238
239 Ext.apply(me, {
240 subject: gettext('IP/CIDR'),
8058410f 241 items: [ipanel],
03ab9fba
DM
242 });
243
244 me.callParent();
245
d5e771ce 246 if (!me.isCreate) {
03ab9fba 247 me.load({
8058410f 248 success: function(response, options) {
03ab9fba
DM
249 var values = response.result.data;
250 ipanel.setValues(values);
f6710aac 251 },
03ab9fba
DM
252 });
253 }
f6710aac 254 },
03ab9fba
DM
255});
256
257Ext.define('PVE.IPSetGrid', {
258 extend: 'Ext.grid.Panel',
259 alias: 'widget.pveIPSetGrid',
260
123e1c80
DC
261 stateful: true,
262 stateId: 'grid-firewall-ipsets',
263
03ab9fba
DM
264 base_url: undefined,
265 list_refs_url: undefined,
266
267 addBtn: undefined,
268 removeBtn: undefined,
269 editBtn: undefined,
270
271 setBaseUrl: function(url) {
272 var me = this;
273
274 me.base_url = url;
275
276 if (url === undefined) {
277 me.addBtn.setDisabled(true);
278 me.store.removeAll();
279 } else {
1056e10c 280 if (me.canEdit) {
2e37e779
AD
281 me.addBtn.setDisabled(false);
282 }
3b1ca3ff 283 me.removeBtn.baseurl = url + '/';
03ab9fba 284 me.store.setProxy({
56a353b9 285 type: 'proxmox',
f6710aac 286 url: '/api2/json' + url,
03ab9fba
DM
287 });
288
289 me.store.load();
290 }
291 },
292
293 initComponent: function() {
03ab9fba
DM
294 var me = this;
295
296 if (!me.list_refs_url) {
297 throw "no1 list_refs_url specified";
298 }
299
300 var store = new Ext.data.Store({
f6710aac 301 model: 'pve-ipset',
03ab9fba
DM
302 });
303
304 var reload = function() {
305 store.load();
306 };
307
308 var sm = Ext.create('Ext.selection.RowModel', {});
309
2e37e779 310 me.caps = Ext.state.Manager.get('GuiCap');
1056e10c 311 me.canEdit = !!me.caps.vms['VM.Config.Network'] || !!me.caps.dc['Sys.Modify'] || !!me.caps.nodes['Sys.Modify'];
2e37e779 312
03ab9fba
DM
313 var run_editor = function() {
314 var rec = sm.getSelection()[0];
1056e10c 315 if (!rec || !me.canEdit) {
03ab9fba
DM
316 return;
317 }
318 var win = Ext.create('PVE.IPSetCidrEdit', {
319 base_url: me.base_url,
f6710aac 320 cidr: rec.data.cidr,
03ab9fba
DM
321 });
322 win.show();
323 win.on('destroy', reload);
324 };
325
5720fafa 326 me.editBtn = new Proxmox.button.Button({
03ab9fba
DM
327 text: gettext('Edit'),
328 disabled: true,
1056e10c 329 enableFn: rec => me.canEdit,
03ab9fba 330 selModel: sm,
f6710aac 331 handler: run_editor,
03ab9fba
DM
332 });
333
5720fafa 334 me.addBtn = new Proxmox.button.Button({
03ab9fba
DM
335 text: gettext('Add'),
336 disabled: true,
1056e10c 337 enableFn: rec => me.canEdit,
03ab9fba
DM
338 handler: function() {
339 if (!me.base_url) {
340 return;
341 }
342 var win = Ext.create('PVE.IPSetCidrEdit', {
343 base_url: me.base_url,
f6710aac 344 list_refs_url: me.list_refs_url,
03ab9fba
DM
345 });
346 win.show();
347 win.on('destroy', reload);
f6710aac 348 },
03ab9fba
DM
349 });
350
3b1ca3ff 351 me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
2e37e779 352 disabled: true,
1056e10c 353 enableFn: rec => me.canEdit,
03ab9fba 354 selModel: sm,
3b1ca3ff 355 baseurl: me.base_url + '/',
f6710aac 356 callback: reload,
03ab9fba
DM
357 });
358
359 var render_errors = function(value, metaData, record) {
360 var errors = record.data.errors;
361 if (errors) {
362 var msg = errors.cidr || errors.nomatch;
363 if (msg) {
3ab7e0ec 364 metaData.tdCls = 'proxmox-invalid-row';
8058410f 365 var html = '<p>' + Ext.htmlEncode(msg) + '</p>';
2a4971d8 366 metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' +
202298c1 367 html.replace(/"/g, '&quot;') + '"';
03ab9fba
DM
368 }
369 }
370 return value;
371 };
372
373 Ext.apply(me, {
8058410f 374 tbar: ['<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn],
03ab9fba
DM
375 store: store,
376 selModel: sm,
377 listeners: {
f6710aac 378 itemdblclick: run_editor,
03ab9fba
DM
379 },
380 columns: [
381 {
f6710aac 382 xtype: 'rownumberer',
03ab9fba
DM
383 },
384 {
385 header: gettext('IP/CIDR'),
386 dataIndex: 'cidr',
387 width: 150,
388 renderer: function(value, metaData, record) {
389 value = render_errors(value, metaData, record);
390 if (record.data.nomatch) {
391 return '<b>! </b>' + value;
392 }
393 return value;
f6710aac 394 },
03ab9fba
DM
395 },
396 {
397 header: gettext('Comment'),
398 dataIndex: 'comment',
399 flex: 1,
400 renderer: function(value) {
401 return Ext.util.Format.htmlEncode(value);
f6710aac
TL
402 },
403 },
404 ],
03ab9fba
DM
405 });
406
407 me.callParent();
408
409 if (me.base_url) {
410 me.setBaseUrl(me.base_url); // load
411 }
f6710aac 412 },
03ab9fba 413}, function() {
03ab9fba
DM
414 Ext.define('pve-ipset', {
415 extend: 'Ext.data.Model',
8058410f
TL
416 fields: [{ name: 'nomatch', type: 'boolean' },
417 'cidr', 'comment', 'errors'],
f6710aac 418 idProperty: 'cidr',
03ab9fba 419 });
03ab9fba
DM
420});
421
422Ext.define('PVE.IPSet', {
423 extend: 'Ext.panel.Panel',
424 alias: 'widget.pveIPSet',
425
426 title: 'IPSet',
427
ba93a9c6
DC
428 onlineHelp: 'pve_firewall_ip_sets',
429
03ab9fba
DM
430 list_refs_url: undefined,
431
432 initComponent: function() {
433 var me = this;
434
435 if (!me.list_refs_url) {
436 throw "no list_refs_url specified";
437 }
438
439 var ipset_panel = Ext.createWidget('pveIPSetGrid', {
440 region: 'center',
441 list_refs_url: me.list_refs_url,
f6710aac 442 border: false,
03ab9fba
DM
443 });
444
445 var ipset_list = Ext.createWidget('pveIPSetList', {
446 region: 'west',
447 ipset_panel: ipset_panel,
448 base_url: me.base_url,
123e1c80 449 width: '50%',
03ab9fba 450 border: false,
f6710aac 451 split: true,
03ab9fba
DM
452 });
453
454 Ext.apply(me, {
455 layout: 'border',
8058410f 456 items: [ipset_list, ipset_panel],
03ab9fba
DM
457 listeners: {
458 show: function() {
459 ipset_list.fireEvent('show', ipset_list);
f6710aac
TL
460 },
461 },
03ab9fba
DM
462 });
463
464 me.callParent();
f6710aac 465 },
03ab9fba 466});