]> git.datanom.net - omvzfs.git/blame - gui/js/omv/module/admin/storage/zfs/TreePanel.js
Dynamically hide/show top buttons based on user selection.
[omvzfs.git] / gui / js / omv / module / admin / storage / zfs / TreePanel.js
CommitLineData
6b3ce31b
MR
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 */
38408c3f 77Ext.define("OMV.module.admin.storage.zfs.TreePanel", {
6b3ce31b
MR
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,
5690c58b
NB
101 hideAddObjButton: true,
102 hideEditButton: true,
103 hideDeleteButton: true,
6b3ce31b
MR
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
6b3ce31b
MR
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
5690c58b
NB
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
6b3ce31b
MR
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 };
5690c58b
NB
284 var tbarBtnHidden = {
285 "addobj": true,
286 "edit": true,
287 "delete": true,
288 "up": true,
289 "down": true
290 };
6b3ce31b
MR
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;
5690c58b
NB
298 tbarBtnHidden["addobj"] = true;
299 tbarBtnHidden["edit"] = true;
300 tbarBtnHidden["delete"] = true;
6b3ce31b
MR
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;
5690c58b
NB
307 tbarBtnHidden["addobj"] = false;
308 tbarBtnHidden["edit"] = false;
309 tbarBtnHidden["delete"] = false;
6b3ce31b
MR
310 } else {
311 tbarBtnDisabled["addobj"] = true;
312 tbarBtnDisabled["edit"] = true;
313 tbarBtnDisabled["delete"] = false;
314 tbarBtnDisabled["up"] = false;
315 tbarBtnDisabled["down"] = false;
5690c58b
NB
316 tbarBtnHidden["addobj"] = true;
317 tbarBtnHidden["edit"] = true;
318 tbarBtnHidden["delete"] = false;
6b3ce31b
MR
319 }
320 //Disable 'AddObj' button if selected row is a Poool or a Snapshot
321 Ext.Array.each(records, function(record) {
322 if(("Pool" == record.get("type")) ||
323 ("Snapshot" == record.get("type"))) {
324 tbarBtnDisabled["addobj"] = true;
5690c58b 325 tbarBtnHidden["addobj"] = true;
6b3ce31b
MR
326 return false;
327 }
328 });
329
330 // Disable 'Delete' button if a selected node is not a leaf
331 Ext.Array.each(records, function(record) {
332 if((false == record.get("leaf"))) {
333 tbarBtnDisabled["delete"] = true;
5690c58b 334 tbarBtnHidden["delete"] = true;
6b3ce31b
MR
335 return false;
336 }
337 });
338
339 // Update the button controls.
340 Ext.Array.each(tbarBtnName, function(name) {
341 var tbarBtnCtrl = me.queryById(me.getId() + "-" + name);
342 if(!Ext.isEmpty(tbarBtnCtrl)) {
343 if(true == tbarBtnDisabled[name]) {
344 tbarBtnCtrl.disable();
345 } else {
346 tbarBtnCtrl.enable();
347 }
5690c58b
NB
348 if(true == tbarBtnHidden[name]) {
349 tbarBtnCtrl.hide();
350 } else {
351 tbarBtnCtrl.show();
352 }
6b3ce31b
MR
353 }
354 });
355 },
356
357 onItemDblClick: function() {
358 var me = this;
359 if(!me.hideTopToolbar && !me.hideEditButton) {
360 me.onEditButton(me);
361 }
362 },
363
364 /**
365 * Load the grid content.
366 */
367 doLoad: function() {
368 var me = this;
369 if(me.mode === "remote") {
370 me.store.load();
371 }
372 },
373
374 /**
375 * Reload the grid content.
376 */
377 doReload: function() {
378 var me = this;
379 if(me.mode === "remote") {
380 me.store.reload();
381 }
382 },
383
384 /**
385 * Handler that is called when the 'Add' button in the top toolbar
386 * is pressed. Override this method to customize the default behaviour.
387 * @param this The grid itself.
388 */
389 onAddButton: function() {
390 // Nothing to do here
391 },
392
393 /**
394 * * Handler that is called when the 'AddObj' button in the top toolbar
395 * is pressed. Override this method to customize the default behaviour.
396 * @param this The grid itself.
397 */
398 onAddObjButton: function() {
399 // Nothing to do here
400 },
401
402
403 /**
404 * Handler that is called when the 'Edit' button in the top toolbar
405 * is pressed. Override this method to customize the default behaviour.
406 * @param this The grid itself.
407 */
408 onEditButton: function() {
409 // Nothing to do here
410 },
411
412 /**
413 * Handler that is called when the 'Up' button in the top toolbar
414 * is pressed. Override this method to customize the default behaviour.
415 * @param this The grid itself.
416 */
417 onUpButton: function() {
418 var me = this;
419 var sm = me.getSelectionModel();
420 var records = sm.getSelection();
421 if(records.length > 0) {
422 // Find the smallest index of the selected rows.
423 var ltIndex = me.store.indexOf(records[0]);
424 Ext.Array.each(records, function(record) {
425 var index = me.store.indexOf(record);
426 if(ltIndex > index)
427 ltIndex = index;
428 });
429 // Calculate the index where to insert the rows.
430 var index = ltIndex - 1;
431 if(index < 0)
432 index = 0;
433 me.doMoveRows(records, index);
434 }
435 },
436
437 /**
438 * Handler that is called when the 'Down' button in the top toolbar
439 * is pressed.
440 * @param this The grid itself.
441 */
442 onDownButton: function() {
443 var me = this;
444 var sm = me.getSelectionModel();
445 var records = sm.getSelection();
446 if(records.length > 0) {
447 // Find the smallest index of the selected rows.
448 var ltIndex = me.store.indexOf(records[0]);
449 Ext.Array.each(records, function(record) {
450 var index = me.store.indexOf(record);
451 if(ltIndex > index)
452 ltIndex = index;
453 });
454 // Calculate the index where to insert the rows.
455 var index = ltIndex + records.length;
456 var count = me.store.getCount() - 1;
457 if(index > count)
458 index = count;
459 me.doMoveRows(records, index);
460 }
461 },
462
463 /**
464 * Handler that is called when the 'Apply' button in the top toolbar
465 * is pressed. Override this method to customize the default behaviour.
466 * @param this The grid itself.
467 */
468 onApplyButton: function() {
469 // Nothing to do here
470 },
471
472 /**
473 * Handler that is called when the 'Refresh' button in the top toolbar
474 * is pressed. Override this method to customize the default behaviour.
475 * @param this The grid itself.
476 */
477 onRefreshButton: function() {
478 this.doReload();
479 },
480
481 /**
482 * Move the given rows to the given index.
483 * @param records The records to move.
484 * @param index The index where to insert the rows to be moved.
485 */
486 doMoveRows: function(records, index) {
487 var me = this;
488 if(!Ext.isNumber(index))
489 return;
490 records = Ext.Array.from(records);
491 me.store.suspendEvents();
492 Ext.Array.each(records, function(record) {
493 me.store.remove(record);
494 me.store.insert(index, record);
495 });
496 me.store.resumeEvents();
497 me.afterMoveRows(records, index);
498 me.getView().refresh();
499 },
500
501 /**
502 * Function that is called after the selected rows have been moved.
503 * Override this method to customize the default behaviour.
504 * @param records The records that have been move.
505 * @param index The index where the rows have been inserted.
506 */
507 afterMoveRows: function(records, index) {
508 var sm = this.getSelectionModel();
509 sm.select(records);
510 },
511
512 /**
513 * Handler that is called when the 'Delete' button in the top toolbar
514 * is pressed.
515 */
516 onDeleteButton: function() {
517 var me = this;
518 var sm = me.getSelectionModel();
519 var records = sm.getSelection();
520 if(me.deletionConfirmRequired === true) {
521 var msg = _("Do you really want to delete the selected item(s)?");
522 OMV.MessageBox.show({
523 title: _("Confirmation"),
524 msg: msg,
525 buttons: Ext.Msg.YESNO,
526 fn: function(answer) {
527 if(answer !== "yes")
528 return;
529 me.startDeletion(records);
530 },
531 scope: me,
532 icon: Ext.Msg.QUESTION
533 });
534 } else {
535 me.startDeletion(records);
536 }
537 },
538
539 /**
540 * @private
541 * Private method that is called when the deletion of the selected records
542 * has been aggreed.
543 * @param records The records to delete.
544 */
545 startDeletion: function(records) {
546 var me = this;
547 if(records.length <= 0)
548 return;
549 // Store selected records in a local variable
550 me.delActionInfo = {
551 records: records,
552 count: records.length
553 }
554 // Get first record to be deleted
555 var record = me.delActionInfo.records.pop();
556 // Display progress dialog
557 OMV.MessageBox.progress("", me.deletionWaitMsg, "");
558 me.updateDeletionProgress();
559 // Execute deletion function
560 me.doDeletion(record);
561 },
562
563 /**
564 * The method that is called to delete a selected record. Override this
565 * method to customize the default behaviour. This is necessary in
566 * 'remote' mode.
567 */
568 doDeletion: function(record) {
569 var me = this;
570 if(me.mode === "local") {
571 // Remove record from store
572 me.store.remove(record);
573 // Continue deletion process
574 me.onDeletion(null, true, null);
575 }
576 },
577
578 /**
579 * The method that is called by the 'doDeletion' method. The progress
580 * bar will be updated and the deletion progress will be continued if
581 * there are still records to delete.
582 */
583 onDeletion: function(id, success, response) {
584 var me = this;
585 if(!success) {
586 // Remove temporary local variables
587 delete me.delActionInfo;
588 // Hide progress dialog
589 OMV.MessageBox.hide();
590 // Display error message
591 OMV.MessageBox.error(null, response);
592 } else {
593 if(me.delActionInfo.records.length > 0) {
594 var record = me.delActionInfo.records.pop();
595 // Update progress dialog
596 me.updateDeletionProgress();
597 // Execute deletion function
598 me.doDeletion(record);
599 } else {
600 // Remove temporary local variables
601 delete me.delActionInfo;
602 // Update and hide progress dialog
603 OMV.MessageBox.updateProgress(1, _("100% completed ..."));
604 OMV.MessageBox.hide();
605 me.afterDeletion();
606 }
607 }
608 },
609
610 /**
611 * Function that is called after the deletion has been successful finished.
612 */
613 afterDeletion: function() {
614 var me = this;
615 if(me.mode === "remote") {
616 me.doReload();
617 }
618 },
619
620 /**
621 * @private
622 * Private helper function to update the progress dialog.
623 */
624 updateDeletionProgress: function() {
625 var me = this;
626 // Calculate percentage
627 var p = (me.delActionInfo.count - me.delActionInfo.records.length) /
628 me.delActionInfo.count;
629 // Create message text
630 var text = Math.round(100 * p) + _("% completed ...");
631 // Update progress dialog
632 OMV.MessageBox.updateProgress(p, text);
633 },
634
635 /**
636 * Convenience function for setting the given toolbar button
637 * disabled/enabled.
638 * @param name The name of the toolbar button.
639 * @param disabled TRUE to disable the button, FALSE to enable.
640 * @return The button component, otherwise FALSE.
641 */
642 setToolbarButtonDisabled: function(name, disabled) {
643 var me = this;
644 var result = false;
645 var btnCtrl = me.queryById(me.getId() + "-" + name);
646 if(!Ext.isEmpty(btnCtrl) && btnCtrl.isButton)
647 result = btnCtrl.setDisabled(disabled);
648 return result;
649 },
650
651 /**
652 * Helper function to get the top toolbar object.
653 * @return The paging toolbar object or NULL.
654 */
655 getTopToolbar: function() {
656 return this.topToolbar;
657 },
658
659 /**
660 * Helper function to get the paging toolbar object.
661 * @return The paging toolbar object or NULL.
662 */
663 getPagingToolbar: function() {
664 return this.pagingToolbar;
665 }
666});
667
668
669
This page took 0.119542 seconds and 5 git commands to generate.