]> git.datanom.net - omvzfs.git/blob - gui/js/omv/module/admin/storage/zfs/TreePanel.js
Hide filesystems with same name as pool.
[omvzfs.git] / gui / js / omv / module / admin / storage / zfs / TreePanel.js
1 /**
2 * This file is part of OpenMediaVault.
3 *
4 * @license http://www.gnu.org/licenses/gpl.html GPL Version 3
5 * @author Volker Theile <volker.theile@openmediavault.org>
6 * @copyright Copyright (c) 2009-2014 Volker Theile
7 *
8 * OpenMediaVault is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * any later version.
12 *
13 * OpenMediaVault is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with OpenMediaVault. If not, see <http://www.gnu.org/licenses/>.
20 */
21 // require("js/omv/tree/Panel.js")
22 // require("js/omv/grid/Panel.js")
23 // require("js/omv/grid/column/BinaryUnit.js")
24 // require("js/omv/grid/column/BooleanIcon.js")
25 // require("js/omv/grid/column/BooleanText.js")
26 // require("js/omv/grid/column/Empty.js")
27 // require("js/omv/grid/column/Hyperlink.js")
28 // require("js/omv/grid/column/UnixTimestamp.js")
29 // require("js/omv/grid/column/WhiteSpace.js")
30 // require("js/omv/window/MessageBox.js")
31
32 /**
33 * @ingroup webgui
34 * @class OMV.workspace.grid.Panel
35 * @derived OMV.grid.Panel
36 * An enhanced grid panel. This grid provides 'Add', 'Edit' and 'Delete'
37 * buttons in the toolbar by default. The basic delete functionality is also
38 * implemented, simply overwrite the 'doDeletion' and 'afterDeletion'
39 * functions to implement fit your requirements. To implement the 'Add' and
40 * 'Edit' functionality overwrite the 'onAdd' and 'onEdit' callback
41 * functions. A paging toolbar which is displayed at the bottom of the grid
42 * can be displayed also. It is also possible to reload the grid
43 * automatically in a given interval.
44 * @param hideTopToolbar TRUE to hide the whole toolbar. Defaults to FALSE.
45 * @param hidePagingToolbar TRUE to hide the paging toolbar at the bottom of
46 * the grid. Defaults to TRUE.
47 * @param hideAddButton Hide the 'Add' button in the top toolbar.
48 * Defaults to FALSE.
49 * @param hideEditButton Hide the 'Edit' button in the top toolbar.
50 * Defaults to FALSE.
51 * @param hideDeleteButton Hide the 'Delete' button in the top toolbar.
52 * Defaults to FALSE.
53 * @param hideUpButton Hide the 'Up' button in the top toolbar.
54 * Defaults to TRUE.
55 * @param hideDownButton Hide the 'Down' button in the top toolbar.
56 * Defaults to TRUE.
57 * @param hideApplyButton Hide the 'Apply' button in the top toolbar.
58 * Defaults to TRUE.
59 * @param hideRefreshButton Hide the 'Refresh' button in the top toolbar.
60 * Defaults to TRUE.
61 * @param addButtonText The button text. Defaults to 'Add'.
62 * @param editButtonText The button text. Defaults to 'Edit'.
63 * @param deleteButtonText The button text. Defaults to 'Delete'.
64 * @param upButtonText The button text. Defaults to 'Up'.
65 * @param downButtonText The button text. Defaults to 'Down'.
66 * @param applyButtonText The button text. Defaults to 'Save'.
67 * @param refreshButtonText The button text. Defaults to 'Refresh'.
68 * @param deletionConfirmRequired Set to TRUE to force the user to confirm
69 * the deletion request. Defaults to TRUE.
70 * @param deletionWaitMsg The message displayed during the deletion process.
71 * @param mode The mode how to retrieve the data displayed in the grid panel.
72 * This can be 'local' or 'remote' which means the data is requested via
73 * RPC. Defaults to 'remote'.
74 * @param rememberSelected TRUE to reselect the previous selected rows
75 * after the grid content has been reloaded/refreshed. Defaults to FALSE.
76 */
77 Ext.define("OMV.module.admin.storage.zfs.TreePanel", {
78 extend: "OMV.tree.Panel",
79 requires: [
80 "OMV.window.MessageBox",
81 "OMV.grid.column.BinaryUnit",
82 "OMV.grid.column.BooleanIcon",
83 "OMV.grid.column.BooleanText",
84 "OMV.grid.column.Empty",
85 "OMV.grid.column.Hyperlink",
86 "OMV.grid.column.UnixTimestamp",
87 "OMV.grid.column.WhiteSpace"
88 ],
89
90 border: false,
91 rowLines: false,
92 columnLines: true,
93 selModel: {
94 allowDeselect: true,
95 mode: "SINGLE"
96 },
97
98 hideTopToolbar: false,
99 hidePagingToolbar: true,
100 hideAddButton: false,
101 hideAddObjButton: true,
102 hideEditButton: true,
103 hideDeleteButton: true,
104 hideUpButton: true,
105 hideDownButton: true,
106 hideApplyButton: true,
107 hideRefreshButton: true,
108 addButtonText: _("Add Pool"),
109 addObjButtonText: _("Add Object"),
110 editButtonText: _("Edit"),
111 deleteButtonText: _("Delete"),
112 upButtonText: _("Up"),
113 downButtonText: _("Down"),
114 applyButtonText: _("Save"),
115 refreshButtonText: _("Refresh"),
116 deletionConfirmRequired: true,
117 deletionWaitMsg: _("Deleting selected item(s)"),
118 mode: "remote",
119 rememberSelected: false,
120
121 initComponent: function() {
122 var me = this;
123 // Initialize toolbars.
124 me.dockedItems = [];
125 if(!me.hideTopToolbar) {
126 me.dockedItems.push(me.topToolbar = Ext.widget({
127 xtype: "toolbar",
128 dock: "top",
129 items: me.getTopToolbarItems(me)
130 }));
131 }
132 if(!me.hidePagingToolbar) {
133 me.dockedItems.push({
134 xtype: "toolbar",
135 dock: "bottom",
136 items: [ me.pagingToolbar = Ext.widget({
137 xtype: "pagingtoolbar",
138 store: me.store,
139 displayInfo: true,
140 displayMsg: _("Displaying items {0} - {1} of {2}"),
141 emptyMsg: _("No items to display")
142 }) ]
143 });
144 }
145 me.callParent(arguments);
146 // Register event handler.
147 // Process double clicks in grid.
148 me.on("itemdblclick", me.onItemDblClick, me);
149 // Process selections in grid, e.g. to update the toolbar.
150 var selModel = me.getSelectionModel();
151 selModel.on("selectionchange", me.onSelectionChange, me);
152 // Remember selection to restore it after the grid has been
153 // refreshed.
154 if(me.rememberSelected) {
155 me.getStore().on("beforeload", function() {
156 if(!me.rendered || Ext.isEmpty(me.getEl()))
157 return;
158 if(!selModel.hasSelection())
159 return;
160 me.previousSelected = selModel.getSelection();
161 });
162 me.getView().on("refresh", function(view) {
163 if(Ext.isEmpty(me.previousSelected))
164 return;
165 var select = [];
166 Ext.Array.each(me.previousSelected, function(r) {
167 var record = me.getStore().getById(r.getId());
168 if(!Ext.isEmpty(record))
169 select.push(record);
170 });
171 delete me.previousSelected;
172 if(select.length > 0) {
173 selModel.select(select, false, false);
174 selModel.view.focusNode(select[0]);
175 }
176 });
177 }
178 },
179
180 /**
181 * Returns the items displayed in the top toolbar.
182 * @param c This component object.
183 * @return An array of buttons displayed in the top toolbar.
184 */
185 getTopToolbarItems: function(c) {
186 var me = this;
187 return [{
188 id: me.getId() + "-add",
189 xtype: "button",
190 text: me.addButtonText,
191 icon: "images/add.png",
192 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
193 hidden: me.hideAddButton,
194 handler: Ext.Function.bind(me.onAddButton, me, [ me ]),
195 scope: me
196 },{
197 id: me.getId() + "-edit",
198 xtype: "button",
199 text: me.editButtonText,
200 icon: "images/edit.png",
201 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
202 hidden: me.hideEditButton,
203 handler: Ext.Function.bind(me.onEditButton, me, [ me ]),
204 scope: me,
205 disabled: true
206 },{
207 id: me.getId() + "-addobj",
208 xtype: "button",
209 text: me.addObjButtonText,
210 icon: "images/add.png",
211 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
212 hidden: me.hideAddObjButton,
213 handler: Ext.Function.bind(me.onAddObjButton, me, [ me ]),
214 scope: me,
215 disabled: true
216 },{
217 id: me.getId() + "-delete",
218 xtype: "button",
219 text: me.deleteButtonText,
220 icon: "images/delete.png",
221 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
222 hidden: me.hideDeleteButton,
223 handler: Ext.Function.bind(me.onDeleteButton, me, [ me ]),
224 scope: me,
225 disabled: true
226 },{
227 id: me.getId() + "-up",
228 xtype: "button",
229 text: me.upButtonText,
230 icon: "images/arrow-up.png",
231 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
232 hidden: me.hideUpButton,
233 handler: Ext.Function.bind(me.onUpButton, me, [ me ]),
234 scope: me,
235 disabled: true
236 },{
237 id: me.getId() + "-down",
238 xtype: "button",
239 text: me.downButtonText,
240 icon: "images/arrow-down.png",
241 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
242 hidden: me.hideDownButton,
243 handler: Ext.Function.bind(me.onDownButton, me, [ me ]),
244 scope: me,
245 disabled: true
246 },{
247 id: me.getId() + "-apply",
248 xtype: "button",
249 text: me.applyButtonText,
250 icon: "images/checkmark.png",
251 hidden: me.hideApplyButton,
252 handler: Ext.Function.bind(me.onApplyButton, me, [ me ]),
253 scope: me
254 },{
255 id: me.getId() + "-refresh",
256 xtype: "button",
257 text: me.refreshButtonText,
258 icon: "images/refresh.png",
259 iconCls: Ext.baseCSSPrefix + "btn-icon-16x16",
260 hidden: me.hideRefreshButton,
261 handler: Ext.Function.bind(me.onRefreshButton, me, [ me ]),
262 scope: me
263 }]
264 },
265
266 /**
267 * Handler that is called whenever the selection in the grid has
268 * been changed. The top toolbar buttons will be enabled/disabled
269 * depending on how much rows has been selected.
270 * @param model The selection model
271 */
272 onSelectionChange: function(model, records) {
273 var me = this;
274 if(me.hideTopToolbar)
275 return;
276 var tbarBtnName = [ "addobj", "edit", "delete", "up", "down" ];
277 var tbarBtnDisabled = {
278 "addobj": false,
279 "edit": false,
280 "delete": false,
281 "up": true,
282 "down": true
283 };
284 var tbarBtnHidden = {
285 "addobj": true,
286 "edit": true,
287 "delete": true,
288 "up": true,
289 "down": true
290 };
291 // Enable/disable buttons depending on the number of selected rows.
292 if(records.length <= 0) {
293 tbarBtnDisabled["addobj"] = true;
294 tbarBtnDisabled["edit"] = true;
295 tbarBtnDisabled["delete"] = true;
296 tbarBtnDisabled["up"] = true;
297 tbarBtnDisabled["down"] = true;
298 tbarBtnHidden["addobj"] = true;
299 tbarBtnHidden["edit"] = true;
300 tbarBtnHidden["delete"] = true;
301 } else if(records.length == 1) {
302 tbarBtnDisabled["addobj"] = false;
303 tbarBtnDisabled["edit"] = false;
304 tbarBtnDisabled["delete"] = false;
305 tbarBtnDisabled["up"] = false;
306 tbarBtnDisabled["down"] = false;
307 tbarBtnHidden["addobj"] = false;
308 tbarBtnHidden["edit"] = false;
309 tbarBtnHidden["delete"] = false;
310 } else {
311 tbarBtnDisabled["addobj"] = true;
312 tbarBtnDisabled["edit"] = true;
313 tbarBtnDisabled["delete"] = false;
314 tbarBtnDisabled["up"] = false;
315 tbarBtnDisabled["down"] = false;
316 tbarBtnHidden["addobj"] = true;
317 tbarBtnHidden["edit"] = true;
318 tbarBtnHidden["delete"] = false;
319 }
320 //Disable 'AddObj' button if selected row is a Snapshot
321 Ext.Array.each(records, function(record) {
322 if("Snapshot" == record.get("type")) {
323 tbarBtnDisabled["addobj"] = true;
324 tbarBtnHidden["addobj"] = true;
325 return false;
326 }
327 });
328
329 // Disable 'Delete' button if a selected node is not a leaf
330 Ext.Array.each(records, function(record) {
331 if((false == record.get("leaf"))) {
332 tbarBtnDisabled["delete"] = true;
333 tbarBtnHidden["delete"] = true;
334 return false;
335 }
336 });
337
338 // Update the button controls.
339 Ext.Array.each(tbarBtnName, function(name) {
340 var tbarBtnCtrl = me.queryById(me.getId() + "-" + name);
341 if(!Ext.isEmpty(tbarBtnCtrl)) {
342 if(true == tbarBtnDisabled[name]) {
343 tbarBtnCtrl.disable();
344 } else {
345 tbarBtnCtrl.enable();
346 }
347 if(true == tbarBtnHidden[name]) {
348 tbarBtnCtrl.hide();
349 } else {
350 tbarBtnCtrl.show();
351 }
352 }
353 });
354 },
355
356 onItemDblClick: function() {
357 var me = this;
358 if(!me.hideTopToolbar && !me.hideEditButton) {
359 me.onEditButton(me);
360 }
361 },
362
363 /**
364 * Load the grid content.
365 */
366 doLoad: function() {
367 var me = this;
368 if(me.mode === "remote") {
369 me.store.load();
370 }
371 },
372
373 /**
374 * Reload the grid content.
375 */
376 doReload: function() {
377 var me = this;
378 if(me.mode === "remote") {
379 me.store.reload();
380 }
381 },
382
383 /**
384 * Handler that is called when the 'Add' button in the top toolbar
385 * is pressed. Override this method to customize the default behaviour.
386 * @param this The grid itself.
387 */
388 onAddButton: function() {
389 // Nothing to do here
390 },
391
392 /**
393 * * Handler that is called when the 'AddObj' button in the top toolbar
394 * is pressed. Override this method to customize the default behaviour.
395 * @param this The grid itself.
396 */
397 onAddObjButton: function() {
398 // Nothing to do here
399 },
400
401
402 /**
403 * Handler that is called when the 'Edit' button in the top toolbar
404 * is pressed. Override this method to customize the default behaviour.
405 * @param this The grid itself.
406 */
407 onEditButton: function() {
408 // Nothing to do here
409 },
410
411 /**
412 * Handler that is called when the 'Up' button in the top toolbar
413 * is pressed. Override this method to customize the default behaviour.
414 * @param this The grid itself.
415 */
416 onUpButton: function() {
417 var me = this;
418 var sm = me.getSelectionModel();
419 var records = sm.getSelection();
420 if(records.length > 0) {
421 // Find the smallest index of the selected rows.
422 var ltIndex = me.store.indexOf(records[0]);
423 Ext.Array.each(records, function(record) {
424 var index = me.store.indexOf(record);
425 if(ltIndex > index)
426 ltIndex = index;
427 });
428 // Calculate the index where to insert the rows.
429 var index = ltIndex - 1;
430 if(index < 0)
431 index = 0;
432 me.doMoveRows(records, index);
433 }
434 },
435
436 /**
437 * Handler that is called when the 'Down' button in the top toolbar
438 * is pressed.
439 * @param this The grid itself.
440 */
441 onDownButton: function() {
442 var me = this;
443 var sm = me.getSelectionModel();
444 var records = sm.getSelection();
445 if(records.length > 0) {
446 // Find the smallest index of the selected rows.
447 var ltIndex = me.store.indexOf(records[0]);
448 Ext.Array.each(records, function(record) {
449 var index = me.store.indexOf(record);
450 if(ltIndex > index)
451 ltIndex = index;
452 });
453 // Calculate the index where to insert the rows.
454 var index = ltIndex + records.length;
455 var count = me.store.getCount() - 1;
456 if(index > count)
457 index = count;
458 me.doMoveRows(records, index);
459 }
460 },
461
462 /**
463 * Handler that is called when the 'Apply' button in the top toolbar
464 * is pressed. Override this method to customize the default behaviour.
465 * @param this The grid itself.
466 */
467 onApplyButton: function() {
468 // Nothing to do here
469 },
470
471 /**
472 * Handler that is called when the 'Refresh' button in the top toolbar
473 * is pressed. Override this method to customize the default behaviour.
474 * @param this The grid itself.
475 */
476 onRefreshButton: function() {
477 this.doReload();
478 },
479
480 /**
481 * Move the given rows to the given index.
482 * @param records The records to move.
483 * @param index The index where to insert the rows to be moved.
484 */
485 doMoveRows: function(records, index) {
486 var me = this;
487 if(!Ext.isNumber(index))
488 return;
489 records = Ext.Array.from(records);
490 me.store.suspendEvents();
491 Ext.Array.each(records, function(record) {
492 me.store.remove(record);
493 me.store.insert(index, record);
494 });
495 me.store.resumeEvents();
496 me.afterMoveRows(records, index);
497 me.getView().refresh();
498 },
499
500 /**
501 * Function that is called after the selected rows have been moved.
502 * Override this method to customize the default behaviour.
503 * @param records The records that have been move.
504 * @param index The index where the rows have been inserted.
505 */
506 afterMoveRows: function(records, index) {
507 var sm = this.getSelectionModel();
508 sm.select(records);
509 },
510
511 /**
512 * Handler that is called when the 'Delete' button in the top toolbar
513 * is pressed.
514 */
515 onDeleteButton: function() {
516 var me = this;
517 var sm = me.getSelectionModel();
518 var records = sm.getSelection();
519 if(me.deletionConfirmRequired === true) {
520 var msg = _("Do you really want to delete the selected item(s)?");
521 OMV.MessageBox.show({
522 title: _("Confirmation"),
523 msg: msg,
524 buttons: Ext.Msg.YESNO,
525 fn: function(answer) {
526 if(answer !== "yes")
527 return;
528 me.startDeletion(records);
529 },
530 scope: me,
531 icon: Ext.Msg.QUESTION
532 });
533 } else {
534 me.startDeletion(records);
535 }
536 },
537
538 /**
539 * @private
540 * Private method that is called when the deletion of the selected records
541 * has been aggreed.
542 * @param records The records to delete.
543 */
544 startDeletion: function(records) {
545 var me = this;
546 if(records.length <= 0)
547 return;
548 // Store selected records in a local variable
549 me.delActionInfo = {
550 records: records,
551 count: records.length
552 }
553 // Get first record to be deleted
554 var record = me.delActionInfo.records.pop();
555 // Display progress dialog
556 OMV.MessageBox.progress("", me.deletionWaitMsg, "");
557 me.updateDeletionProgress();
558 // Execute deletion function
559 me.doDeletion(record);
560 },
561
562 /**
563 * The method that is called to delete a selected record. Override this
564 * method to customize the default behaviour. This is necessary in
565 * 'remote' mode.
566 */
567 doDeletion: function(record) {
568 var me = this;
569 if(me.mode === "local") {
570 // Remove record from store
571 me.store.remove(record);
572 // Continue deletion process
573 me.onDeletion(null, true, null);
574 }
575 },
576
577 /**
578 * The method that is called by the 'doDeletion' method. The progress
579 * bar will be updated and the deletion progress will be continued if
580 * there are still records to delete.
581 */
582 onDeletion: function(id, success, response) {
583 var me = this;
584 if(!success) {
585 // Remove temporary local variables
586 delete me.delActionInfo;
587 // Hide progress dialog
588 OMV.MessageBox.hide();
589 // Display error message
590 OMV.MessageBox.error(null, response);
591 } else {
592 if(me.delActionInfo.records.length > 0) {
593 var record = me.delActionInfo.records.pop();
594 // Update progress dialog
595 me.updateDeletionProgress();
596 // Execute deletion function
597 me.doDeletion(record);
598 } else {
599 // Remove temporary local variables
600 delete me.delActionInfo;
601 // Update and hide progress dialog
602 OMV.MessageBox.updateProgress(1, _("100% completed ..."));
603 OMV.MessageBox.hide();
604 me.afterDeletion();
605 }
606 }
607 },
608
609 /**
610 * Function that is called after the deletion has been successful finished.
611 */
612 afterDeletion: function() {
613 var me = this;
614 if(me.mode === "remote") {
615 me.doReload();
616 }
617 },
618
619 /**
620 * @private
621 * Private helper function to update the progress dialog.
622 */
623 updateDeletionProgress: function() {
624 var me = this;
625 // Calculate percentage
626 var p = (me.delActionInfo.count - me.delActionInfo.records.length) /
627 me.delActionInfo.count;
628 // Create message text
629 var text = Math.round(100 * p) + _("% completed ...");
630 // Update progress dialog
631 OMV.MessageBox.updateProgress(p, text);
632 },
633
634 /**
635 * Convenience function for setting the given toolbar button
636 * disabled/enabled.
637 * @param name The name of the toolbar button.
638 * @param disabled TRUE to disable the button, FALSE to enable.
639 * @return The button component, otherwise FALSE.
640 */
641 setToolbarButtonDisabled: function(name, disabled) {
642 var me = this;
643 var result = false;
644 var btnCtrl = me.queryById(me.getId() + "-" + name);
645 if(!Ext.isEmpty(btnCtrl) && btnCtrl.isButton)
646 result = btnCtrl.setDisabled(disabled);
647 return result;
648 },
649
650 /**
651 * Helper function to get the top toolbar object.
652 * @return The paging toolbar object or NULL.
653 */
654 getTopToolbar: function() {
655 return this.topToolbar;
656 },
657
658 /**
659 * Helper function to get the paging toolbar object.
660 * @return The paging toolbar object or NULL.
661 */
662 getPagingToolbar: function() {
663 return this.pagingToolbar;
664 }
665 });
666
667
668
This page took 0.136979 seconds and 6 git commands to generate.