]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/node/ZFS.js
partially fix #2285: ui: disk create: allow selecting partitions
[pve-manager.git] / www / manager6 / node / ZFS.js
CommitLineData
fee716d3
DC
1Ext.define('PVE.node.CreateZFS', {
2 extend: 'Proxmox.window.Edit',
3 xtype: 'pveCreateZFS',
4
dc90ab40 5 onlineHelp: 'chapter_zfs',
fee716d3
DC
6 subject: 'ZFS',
7
8 showProgress: true,
dc90ab40 9 isCreate: true,
7d2e6f5b
SI
10 width: 800,
11
8058410f 12 initComponent: function() {
dc90ab40 13 let me = this;
fee716d3
DC
14
15 if (!me.nodename) {
16 throw "no node name specified";
17 }
18
fee716d3 19 Ext.apply(me, {
dc90ab40 20 url: `/nodes/${me.nodename}/disks/zfs`,
fee716d3
DC
21 method: 'POST',
22 items: [
23 {
24 xtype: 'inputpanel',
fee716d3 25 column1: [
fee716d3
DC
26 {
27 xtype: 'proxmoxtextfield',
28 name: 'name',
29 fieldLabel: gettext('Name'),
f6710aac 30 allowBlank: false,
fee716d3
DC
31 },
32 {
33 xtype: 'proxmoxcheckbox',
34 name: 'add_storage',
35 fieldLabel: gettext('Add Storage'),
f6710aac
TL
36 value: '1',
37 },
fee716d3
DC
38 ],
39 column2: [
40 {
41 xtype: 'proxmoxKVComboBox',
42 fieldLabel: gettext('RAID Level'),
43 name: 'raidlevel',
f04e415b 44 value: 'single',
fee716d3 45 comboItems: [
f04e415b 46 ['single', gettext('Single Disk')],
fee716d3
DC
47 ['mirror', 'Mirror'],
48 ['raid10', 'RAID10'],
49 ['raidz', 'RAIDZ'],
50 ['raidz2', 'RAIDZ2'],
f6710aac
TL
51 ['raidz3', 'RAIDZ3'],
52 ],
fee716d3
DC
53 },
54 {
55 xtype: 'proxmoxKVComboBox',
56 fieldLabel: gettext('Compression'),
57 name: 'compression',
58 value: 'on',
59 comboItems: [
60 ['on', 'on'],
61 ['off', 'off'],
62 ['gzip', 'gzip'],
63 ['lz4', 'lz4'],
64 ['lzjb', 'lzjb'],
f6710aac 65 ['zle', 'zle'],
fc2ff3e8 66 ['zstd', 'zstd'],
f6710aac 67 ],
fee716d3
DC
68 },
69 {
70 xtype: 'proxmoxintegerfield',
71 fieldLabel: gettext('ashift'),
72 minValue: 9,
73 maxValue: 16,
74 value: '12',
f6710aac
TL
75 name: 'ashift',
76 },
fee716d3
DC
77 ],
78 columnB: [
79 {
87f16008
FE
80 xtype: 'pmxMultiDiskSelector',
81 name: 'devices',
82 nodename: me.nodename,
83 diskType: 'unused',
6c356c92 84 includePartitions: true,
fee716d3
DC
85 height: 200,
86 emptyText: gettext('No Disks unused'),
87 itemId: 'disklist',
f6710aac
TL
88 },
89 ],
deca45c1
TL
90 },
91 {
92 xtype: 'displayfield',
93 padding: '5 0 0 0',
f71b7c28 94 userCls: 'pmx-hint',
deca45c1 95 value: 'Note: ZFS is not compatible with disks backed by a hardware ' +
dc90ab40
TL
96 'RAID controller. For details see <a target="_blank" href="' +
97 Proxmox.Utils.get_help_link('chapter_zfs') + '">the reference documentation</a>.',
f6710aac
TL
98 },
99 ],
fee716d3
DC
100 });
101
102 me.callParent();
f6710aac 103 },
fee716d3
DC
104});
105
e98bcf01 106Ext.define('PVE.node.ZFSDevices', {
fee716d3 107 extend: 'Ext.tree.Panel',
e98bcf01 108 xtype: 'pveZFSDevices',
dc90ab40 109
fee716d3
DC
110 stateful: true,
111 stateId: 'grid-node-zfsstatus',
112 columns: [
113 {
114 xtype: 'treecolumn',
115 text: gettext('Name'),
116 dataIndex: 'name',
f6710aac 117 flex: 1,
fee716d3
DC
118 },
119 {
120 text: gettext('Health'),
121 renderer: PVE.Utils.render_zfs_health,
f6710aac 122 dataIndex: 'state',
fee716d3 123 },
eb43c6f4 124 {
d52134b7 125 text: 'READ',
f6710aac 126 dataIndex: 'read',
eb43c6f4
TM
127 },
128 {
d52134b7 129 text: 'WRITE',
f6710aac 130 dataIndex: 'write',
eb43c6f4
TM
131 },
132 {
d52134b7 133 text: 'CKSUM',
f6710aac 134 dataIndex: 'cksum',
eb43c6f4 135 },
fee716d3
DC
136 {
137 text: gettext('Message'),
f6710aac
TL
138 dataIndex: 'msg',
139 },
fee716d3
DC
140 ],
141
fee716d3 142 reload: function() {
dc90ab40
TL
143 let me = this;
144 let sm = me.getSelectionModel();
fee716d3 145 Proxmox.Utils.API2Request({
dc90ab40 146 url: `/nodes/${me.nodename}/disks/zfs/${me.zpool}`,
fee716d3
DC
147 waitMsgTarget: me,
148 method: 'GET',
dc90ab40 149 failure: (response, opts) => Proxmox.Utils.setErrorMask(me, response.htmlStatus),
fee716d3
DC
150 success: function(response, opts) {
151 sm.deselectAll();
152 me.setRootNode(response.result.data);
153 me.expandAll();
f6710aac 154 },
fee716d3
DC
155 });
156 },
157
dc90ab40
TL
158 rootVisible: true,
159 selModel: 'treemodel',
160 fields: [
161 'name',
162 'status',
163 {
164 type: 'string',
165 name: 'iconCls',
166 calculate: data => data.leaf ? `fa x-fa-tree fa-hdd-o` : undefined,
167 },
168 ],
169
fee716d3 170 initComponent: function() {
dc90ab40 171 let me = this;
fee716d3
DC
172
173 if (!me.nodename) {
174 throw "no node name specified";
175 }
fee716d3
DC
176 if (!me.zpool) {
177 throw "no zpool specified";
178 }
179
fee716d3
DC
180 me.callParent();
181
182 me.reload();
f6710aac 183 },
fee716d3
DC
184});
185
e98bcf01
TM
186Ext.define('PVE.node.ZFSStatus', {
187 extend: 'Proxmox.grid.ObjectGrid',
188 xtype: 'pveZFSStatus',
189 layout: 'fit',
190 border: false,
191
192 initComponent: function() {
dc90ab40 193 let me = this;
e98bcf01
TM
194
195 if (!me.nodename) {
196 throw "no node name specified";
197 }
e98bcf01
TM
198 if (!me.zpool) {
199 throw "no zpool specified";
200 }
201
dc90ab40 202 me.url = `/api2/extjs/nodes/${me.nodename}/disks/zfs/${me.zpool}`;
e98bcf01
TM
203
204 me.rows = {
205 scan: {
f6710aac 206 header: gettext('Scan'),
face18ee 207 defaultValue: gettext('No Data'),
e98bcf01
TM
208 },
209 status: {
f6710aac 210 header: gettext('Status'),
e98bcf01
TM
211 },
212 action: {
f6710aac 213 header: gettext('Action'),
e98bcf01
TM
214 },
215 errors: {
f6710aac
TL
216 header: gettext('Errors'),
217 },
e98bcf01
TM
218 };
219
220 me.callParent();
221 me.reload();
f6710aac 222 },
e98bcf01
TM
223});
224
fee716d3
DC
225Ext.define('PVE.node.ZFSList', {
226 extend: 'Ext.grid.Panel',
227 xtype: 'pveZFSList',
228
14066c09
FE
229 viewModel: {
230 data: {
231 pool: '',
232 },
233 },
234
235 controller: {
236 xclass: 'Ext.app.ViewController',
237
238 destroyPool: function() {
239 let me = this;
240 let vm = me.getViewModel();
241 let view = me.getView();
242
243 const pool = vm.get('pool');
244
245 if (!view.nodename) {
246 throw "no node name specified";
247 }
248
249 if (!pool) {
250 throw "no pool specified";
251 }
252
bccfb43f 253 Ext.create('PVE.window.SafeDestroyStorage', {
14066c09
FE
254 url: `/nodes/${view.nodename}/disks/zfs/${pool}`,
255 item: { id: pool },
14066c09
FE
256 taskName: 'zfsremove',
257 taskDone: () => { view.reload(); },
258 }).show();
259 },
260 },
261
fee716d3
DC
262 stateful: true,
263 stateId: 'grid-node-zfs',
264 columns: [
265 {
266 text: gettext('Name'),
267 dataIndex: 'name',
f6710aac 268 flex: 1,
fee716d3
DC
269 },
270 {
271 header: gettext('Size'),
272 renderer: Proxmox.Utils.format_size,
f6710aac 273 dataIndex: 'size',
fee716d3
DC
274 },
275 {
276 header: gettext('Free'),
277 renderer: Proxmox.Utils.format_size,
f6710aac 278 dataIndex: 'free',
fee716d3
DC
279 },
280 {
281 header: gettext('Allocated'),
282 renderer: Proxmox.Utils.format_size,
f6710aac 283 dataIndex: 'alloc',
fee716d3
DC
284 },
285 {
286 header: gettext('Fragmentation'),
287 renderer: function(value) {
288 return value.toString() + '%';
289 },
f6710aac 290 dataIndex: 'frag',
fee716d3
DC
291 },
292 {
293 header: gettext('Health'),
294 renderer: PVE.Utils.render_zfs_health,
f6710aac 295 dataIndex: 'health',
fee716d3
DC
296 },
297 {
298 header: gettext('Deduplication'),
299 hidden: true,
300 renderer: function(value) {
301 return value.toFixed(2).toString() + 'x';
302 },
f6710aac
TL
303 dataIndex: 'dedup',
304 },
fee716d3
DC
305 ],
306
307 rootVisible: false,
308 useArrows: true,
309
310 tbar: [
311 {
312 text: gettext('Reload'),
313 iconCls: 'fa fa-refresh',
314 handler: function() {
dc90ab40 315 this.up('panel').reload();
f6710aac 316 },
fee716d3
DC
317 },
318 {
319 text: gettext('Create') + ': ZFS',
320 handler: function() {
dc90ab40
TL
321 let view = this.up('panel');
322 Ext.create('PVE.node.CreateZFS', {
323 nodename: view.nodename,
324 listeners: {
325 destroy: () => view.reload(),
326 },
327 autoShow: true,
328 });
f6710aac 329 },
fee716d3
DC
330 },
331 {
332 text: gettext('Detail'),
333 itemId: 'detailbtn',
334 disabled: true,
335 handler: function() {
dc90ab40
TL
336 let view = this.up('panel');
337 let selection = view.getSelection();
338 if (selection.length) {
339 view.show_detail(selection[0].get('name'));
fee716d3 340 }
f6710aac
TL
341 },
342 },
14066c09
FE
343 '->',
344 {
345 xtype: 'tbtext',
346 data: {
347 pool: undefined,
348 },
349 bind: {
350 data: {
351 pool: "{pool}",
352 },
353 },
354 tpl: [
355 '<tpl if="pool">',
356 'Pool {pool}:',
357 '<tpl else>',
358 Ext.String.format(gettext('No {0} selected'), 'pool'),
359 '</tpl>',
360 ],
361 },
362 {
363 text: gettext('More'),
364 iconCls: 'fa fa-bars',
365 disabled: true,
366 bind: {
367 disabled: '{!pool}',
368 },
369 menu: [
370 {
371 text: gettext('Destroy'),
372 itemId: 'remove',
373 iconCls: 'fa fa-fw fa-trash-o',
374 handler: 'destroyPool',
375 disabled: true,
376 bind: {
377 disabled: '{!pool}',
378 },
379 },
380 ],
381 },
fee716d3
DC
382 ],
383
384 show_detail: function(zpool) {
dc90ab40 385 let me = this;
8cfe2088 386
dc90ab40 387 let detailsgrid = Ext.create('PVE.node.ZFSStatus', {
37e228da 388 layout: 'fit',
8cfe2088 389 nodename: me.nodename,
37e228da 390 flex: 0,
f6710aac 391 zpool: zpool,
8cfe2088 392 });
dc90ab40 393 let devicetree = Ext.create('PVE.node.ZFSDevices', {
37e228da 394 title: gettext('Devices'),
8cfe2088 395 nodename: me.nodename,
37e228da 396 flex: 1,
f6710aac 397 zpool: zpool,
8cfe2088
TM
398 });
399
dc90ab40 400 Ext.create('Ext.window.Window', {
fee716d3
DC
401 modal: true,
402 width: 800,
dc90ab40 403 height: 600,
fee716d3
DC
404 resizable: true,
405 layout: 'fit',
406 title: gettext('Status') + ': ' + zpool,
dc90ab40
TL
407 items: [
408 {
409 xtype: 'panel',
410 region: 'center',
411 layout: {
412 type: 'vbox',
413 align: 'stretch',
f6710aac 414 },
dc90ab40
TL
415 items: [
416 detailsgrid,
417 devicetree,
418 ],
419 tbar: [
420 {
421 text: gettext('Reload'),
422 iconCls: 'fa fa-refresh',
423 handler: function() {
424 devicetree.reload();
425 detailsgrid.reload();
426 },
427 },
428 ],
429 },
430 ],
431 autoShow: true,
432 });
fee716d3
DC
433 },
434
435 set_button_status: function() {
436 var me = this;
fee716d3
DC
437 },
438
439 reload: function() {
440 var me = this;
441 me.store.load();
442 me.store.sort();
443 },
444
445 listeners: {
446 activate: function() {
dc90ab40 447 this.reload();
fee716d3 448 },
14066c09
FE
449 selectionchange: function(model, selected) {
450 let me = this;
451 let vm = me.getViewModel();
452
453 me.down('#detailbtn').setDisabled(selected.length === 0);
454 vm.set('pool', selected[0]?.data.name || '');
fee716d3
DC
455 },
456 itemdblclick: function(grid, record) {
dc90ab40 457 this.show_detail(record.get('name'));
f6710aac 458 },
fee716d3
DC
459 },
460
461 initComponent: function() {
dc90ab40 462 let me = this;
fee716d3
DC
463
464 me.nodename = me.pveSelNode.data.node;
465 if (!me.nodename) {
466 throw "no node name specified";
467 }
468
469 Ext.apply(me, {
470 store: {
471 fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
472 proxy: {
473 type: 'proxmox',
dc90ab40 474 url: `/api2/json/nodes/${me.nodename}/disks/zfs`,
fee716d3 475 },
f6710aac
TL
476 sorters: 'name',
477 },
fee716d3
DC
478 });
479
480 me.callParent();
481
482 Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
483 me.reload();
f6710aac 484 },
fee716d3
DC
485});
486