From: Michael Rasmussen Date: Wed, 16 Jul 2014 00:38:52 +0000 (+0200) Subject: Move root node to Storage X-Git-Url: http://git.datanom.net/omvzfs.git/commitdiff_plain/35244689760c75fa850b4b78402419c5d156df74 Move root node to Storage --- diff --git a/gui/js/omv/module/admin/service/zfs/Overview.js b/gui/js/omv/module/admin/service/zfs/Overview.js deleted file mode 100644 index fe72e89..0000000 --- a/gui/js/omv/module/admin/service/zfs/Overview.js +++ /dev/null @@ -1,503 +0,0 @@ -// require("js/omv/tree/Panel.js") -// require("js/omv/module/admin/service/zfs/TreePanel.js") -// require("js/omv/workspace/window/Grid.js") - -Ext.define("OMV.module.admin.services.zfs.AddObject", { - extend: "OMV.workspace.window.Form", - uses: [ - "OMV.data.Store", - "OMV.data.Model", - "OMV.data.proxy.Rpc", - "OMV.data.reader.RpcArray" - ], - - rpcService: "ZFS", - rpcSetMethod: "addObject", - width: 420, - - getFormItems: function() { - var me = this; - return [{ - xtype: "combo", - name: "type", - fieldLabel: _("Object Type"), - queryMode: "local", - store: [ - [ "filesystem", "Filesystem" ], - [ "snapshot", "Snapshot" ], - [ "volume", "Volume" ] - ], - allowBlank: true, - editable: false, - triggerAction: "all", - value: "filesystem", - listeners: { - scope: me, - change: function(combo, value) { - var sizeField = this.findField("size"); - switch(value) { - case "volume": - sizeField.show(); - sizeField.allowBlank = false; - break; - default: - sizeField.hide(); - sizeField.allowBlank = true; - break; - } - sizeField.validate(); - } - } - },{ - xtype: "textfield", - name: "path", - fieldLabel: _("Prefix"), - allowBlank: false, - readOnly: true - },{ - xtype: "textfield", - name: "name", - fieldLabel: _("Name"), - allowBlank: false, - plugins: [{ - ptype: "fieldinfo", - text: _("Name of the new object. Prefix will prepend the name. Please omit leading /") - }] - },{ - xtype: "textfield", - name: "size", - hidden: true, - fieldLabel: _("Size"), - allowBlank: true, - plugins: [{ - ptype: "fieldinfo", - text: _("Size of the volume e.g. 5mb,100gb,1tb etc") - }] - }]; - } -}); - - - -Ext.define("OMV.module.admin.service.zfs.EditProperties", { - extend: "OMV.workspace.window.Grid", - requires: [ - "OMV.data.Store", - "OMV.data.Model", - "OMV.data.proxy.Rpc" - ], - - rpcService: "ZFS", - rpcSetMethod: "setProperties", - - title: _("Edit properties"), - width: 500, - height: 305, - - getGridConfig: function() { - var me = this; - - var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', { - clicksToEdit: 1, - pluginId: 'rowEditing', - listeners: { - validateedit: function(editor, e, eOpts) { - e.record.set("modified", "true"); - }, - beforeedit: function(editor, e, eOpts) { - if (e.record.get("property") === "mountpoint") { - e.grid.getPlugin('rowEditing').editor.form.findField("value").disable(); - e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); - } else if (e.record.get("newproperty") === "false") { - e.grid.getPlugin('rowEditing').editor.form.findField("value").enable(); - e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); - } else { - e.grid.getPlugin('rowEditing').editor.form.findField("value").enable(); - e.grid.getPlugin('rowEditing').editor.form.findField("property").enable(); - } - } - - } - }); - - var store = Ext.create("OMV.data.Store", { - autoLoad: true, - model: OMV.data.Model.createImplicit({ - fields: [ - { name: "property", type: "string" }, - { name: "value", type: "string" }, - { name: "source", type: "string" }, - { name: "modified", type: "string" }, - { name: "newproperty", type: "string", defaultValue: "false" } - ] - }), - proxy: { - type: "rpc", - rpcData: { - service: "ZFS", - method: "getProperties", - params: { - name: me.name, - type: me.type - } - } - } - }); - - return { - border: false, - stateful: true, - stateId: "8c3dc800-bdbb-11e3-b1b6-0800200c9a66", - selType: 'rowmodel', - plugins: [rowEditing], - store: store, - tbar: [{ - text: "Add property", - icon: "images/add.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - handler: function(view) { - Ext.define('Property', { - extend: 'Ext.data.Model', - fields: [ - "property", - "value", - "source", - "modified", - "newproperty" - ] - }); - var newProperty = Ext.create("Property", { - property: "", - value: "", - source: "local", - modified: "true", - newproperty: "true" - }); - rowEditing.cancelEdit(); - store.insert(0, newProperty); - rowEditing.startEdit(); - } - }], - columns: [{ - text: _("Property"), - sortable: true, - dataIndex: "property", - stateId: "property", - editor: { - xtype: "textfield", - allowBlank: false, - } - },{ - text: _("Value"), - sortable: true, - dataIndex: "value", - stateId: "value", - flex: 1, - readOnly: true, - editor: { - xtype: "textfield", - allowBlank: false, - } - },{ - text: _("Source"), - sortable: true, - dataIndex: "source", - stateId: "source", - },{ - xtype: 'actioncolumn', - header: 'Inherit', - icon: "images/checkmark.png", - tooltip: "Inherit", - handler: function(view, rowIndex, colIndex, item, e, record, row) { - OMV.RpcObserver.request({ - msg : _("Updating property..."), - rpcData : { - service: "ZFS", - method: "inherit", - params: { - name: me.name, - type: me.type, - property: record.get("property") - } - }, - finish : function() { - view.getStore().reload(); - } - }); - }, - isDisabled: function(view, rowIdx, colIdx, item, record) { - var src = record.get("source"); - if(src === "local") { - return false; - } else { - return true; - } - } - },{ - text: _("New"), - dataIndex: "newproperty", - stateId: "newproperty", - sortable: false, - hidden: true - },{ - text: _("Modified"), - sortable: false, - dataIndex: "modified", - stateId: "modified", - hidden: true - }], - }; - }, - - getRpcSetParams: function() { - var me = this; - var properties = []; - var values = me.getValues(); - Ext.Array.each(values, function(value) { - if(value.modified === "false") - return; - properties.push({ - "property": value.property, - "value": value.value, - }); - }); - return { - name: me.name, - type: me.type, - properties: properties - }; - } - -}); - - -Ext.define("OMV.module.admin.services.zfs.CreateShare", { - extend: "OMV.workspace.window.Form", - uses: [ - "OMV.data.Store", - "OMV.data.Model", - "OMV.data.proxy.Rpc", - "OMV.data.reader.RpcArray" - ], - - rpcService: "ZFS", - rpcSetMethod: "createShare", - width: 500, - - getFormItems: function() { - var me = this; - return [{ - xtype: "textfield", - name: "sharename", - fieldLabel: _("Name"), - allowBlank: false, - },{ - xtype: "textfield", - name: "mountpoint", - fieldLabel: _("Path"), - allowBlank: false, - readOnly: true - },{ - xtype: "combo", - name: "mode", - fieldLabel: _("Permissions"), - queryMode: "local", - store: Ext.create("Ext.data.ArrayStore", { - fields: [ "value", "text" ], - data: [ - [ "700", _("Administrator: read/write, Users: no access, Others: no access") ], - [ "750", _("Administrator: read/write, Users: read-only, Others: no access") ], - [ "770", _("Administrator: read/write, Users: read/write, Others: no access") ], - [ "755", _("Administrator: read/write, Users: read-only, Others: read-only") ], - [ "775", _("Administrator: read/write, Users: read/write, Others: read-only") ], - [ "777", _("Everyone: read/write") ] - ] - }), - displayField: "text", - valueField: "value", - allowBlank: false, - editable: false, - showItemTooltip: true, - triggerAction: "all", - value: "775", - plugins: [{ - ptype: "fieldinfo", - text: _("The file mode of the shared folder path.") - }] - },{ - xtype: "textarea", - name: "comment", - fieldLabel: _("Comment"), - allowBlank: true - },{ - xtype: "textarea", - name: "name", - hidden: true - },{ - xtype: "textarea", - name: "type", - hidden: true - }]; - } -}); - - - -Ext.define("OMV.module.admin.service.zfs.Overview", { - extend: "OMV.module.admin.services.zfs.TreePanel", - - rpcService: "ZFS", - rpcGetMethod: "getObjectTree", - requires: [ - "OMV.data.Store", - "OMV.data.Model", - "OMV.data.proxy.Rpc" - ], - - rootVisible: false, - stateful: true, - stateId: "cec54550-bc2a-11e3-a5e2-0800200c9a66", - - columns: [{ - text: _("Name"), - xtype: 'treecolumn', - dataIndex: 'name', - sortable: true, - flex: 2, - stateId: 'name' - },{ - text: _("Type"), - dataIndex: 'type', - sortable: true, - flex: 1, - stateId: 'type' - },{ - text: _("Share"), - xtype: 'actioncolumn', - tooltip: 'Create shared folder', - align: 'center', - icon: 'images/checkmark.png', - handler: function(view, rowIndex, colIndex, item, e, record, row) { - var me = this; - Ext.create("OMV.module.admin.services.zfs.CreateShare", { - title: _("Create shared folder"), - rpcGetMethod: "getSharedParams", - rpcGetParams: { - name: record.get('path'), - type: record.get('type') - } - }).show(); - }, - isDisabled: function(view, rowIdx, colIdx, item, record) { - var src = record.get("type"); - if((src === "Filesystem") && (record.get("shared") === "false")) { - return false; - } else { - return true; - } - } - - - },{ - text: _("Details"), - xtype: 'actioncolumn', - tooltip: 'Details', - align: 'center', - icon: 'images/zfs_mag.png' - },{ - text: _("Shared"), - dataIndex: 'shared', - sortable: false, - stateId: 'shared', - hidden: true - }], - - initComponent: function() { - var me = this; - this.width = 600; - Ext.apply(me, { - store: Ext.create("Ext.data.TreeStore", { - autoLoad: true, - model: OMV.data.Model.createImplicit({ - fields: [ - { name: "name", type: "string" }, - { name: "type", type: "string" }, - { name: "id", type: "string" }, - { name: "path", type: "string" }, - { name: "origin", type: "string", defaultValue: "none" }, - { name: "shared", type: "string", defaultValue: "false" } - ] - }), - proxy: { - type: "rpc", - rpcData: { - service: "ZFS", - method: "getObjectTree", - } - }, - folderSort: true - }) - }); - me.callParent(arguments); - }, - - onAddObjButton: function() { - var me = this; - var sm = me.getSelectionModel(); - var records = sm.getSelection(); - var record = records[0]; - Ext.create("OMV.module.admin.services.zfs.AddObject", { - title: _("Add Object"), - rpcGetMethod: "passParam", - rpcGetParams: { - key: "path", - value: record.get('path') - }, - listeners: { - scope: me, - submit: function() { - this.doReload(); - } - } - }).show(); - }, - - onEditButton: function() { - var me = this; - var sm = me.getSelectionModel(); - var records = sm.getSelection(); - var record = records[0]; - Ext.create("OMV.module.admin.service.zfs.EditProperties", { - name: record.get("path"), - type: record.get("type") - }).show(); - }, - - doDeletion: function(record) { - var me = this; - OMV.Rpc.request({ - scope: me, - callback: me.onDeletion, - rpcData: { - service: "ZFS", - method: "deleteObject", - params: { - name: record.get('path'), - type: record.get('type') - } - } - }); - } - -}); - -OMV.WorkspaceManager.registerPanel({ - id: "overview", - path: "/service/zfs", - text: _("Overview"), - position: 10, - className: "OMV.module.admin.service.zfs.Overview" -}); - - - diff --git a/gui/js/omv/module/admin/service/zfs/TreePanel.js b/gui/js/omv/module/admin/service/zfs/TreePanel.js deleted file mode 100644 index 26a25ce..0000000 --- a/gui/js/omv/module/admin/service/zfs/TreePanel.js +++ /dev/null @@ -1,646 +0,0 @@ -/** - * This file is part of OpenMediaVault. - * - * @license http://www.gnu.org/licenses/gpl.html GPL Version 3 - * @author Volker Theile - * @copyright Copyright (c) 2009-2014 Volker Theile - * - * OpenMediaVault is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * OpenMediaVault is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with OpenMediaVault. If not, see . - */ -// require("js/omv/tree/Panel.js") -// require("js/omv/grid/Panel.js") -// require("js/omv/grid/column/BinaryUnit.js") -// require("js/omv/grid/column/BooleanIcon.js") -// require("js/omv/grid/column/BooleanText.js") -// require("js/omv/grid/column/Empty.js") -// require("js/omv/grid/column/Hyperlink.js") -// require("js/omv/grid/column/UnixTimestamp.js") -// require("js/omv/grid/column/WhiteSpace.js") -// require("js/omv/window/MessageBox.js") - -/** - * @ingroup webgui - * @class OMV.workspace.grid.Panel - * @derived OMV.grid.Panel - * An enhanced grid panel. This grid provides 'Add', 'Edit' and 'Delete' - * buttons in the toolbar by default. The basic delete functionality is also - * implemented, simply overwrite the 'doDeletion' and 'afterDeletion' - * functions to implement fit your requirements. To implement the 'Add' and - * 'Edit' functionality overwrite the 'onAdd' and 'onEdit' callback - * functions. A paging toolbar which is displayed at the bottom of the grid - * can be displayed also. It is also possible to reload the grid - * automatically in a given interval. - * @param hideTopToolbar TRUE to hide the whole toolbar. Defaults to FALSE. - * @param hidePagingToolbar TRUE to hide the paging toolbar at the bottom of - * the grid. Defaults to TRUE. - * @param hideAddButton Hide the 'Add' button in the top toolbar. - * Defaults to FALSE. - * @param hideEditButton Hide the 'Edit' button in the top toolbar. - * Defaults to FALSE. - * @param hideDeleteButton Hide the 'Delete' button in the top toolbar. - * Defaults to FALSE. - * @param hideUpButton Hide the 'Up' button in the top toolbar. - * Defaults to TRUE. - * @param hideDownButton Hide the 'Down' button in the top toolbar. - * Defaults to TRUE. - * @param hideApplyButton Hide the 'Apply' button in the top toolbar. - * Defaults to TRUE. - * @param hideRefreshButton Hide the 'Refresh' button in the top toolbar. - * Defaults to TRUE. - * @param addButtonText The button text. Defaults to 'Add'. - * @param editButtonText The button text. Defaults to 'Edit'. - * @param deleteButtonText The button text. Defaults to 'Delete'. - * @param upButtonText The button text. Defaults to 'Up'. - * @param downButtonText The button text. Defaults to 'Down'. - * @param applyButtonText The button text. Defaults to 'Save'. - * @param refreshButtonText The button text. Defaults to 'Refresh'. - * @param deletionConfirmRequired Set to TRUE to force the user to confirm - * the deletion request. Defaults to TRUE. - * @param deletionWaitMsg The message displayed during the deletion process. - * @param mode The mode how to retrieve the data displayed in the grid panel. - * This can be 'local' or 'remote' which means the data is requested via - * RPC. Defaults to 'remote'. - * @param rememberSelected TRUE to reselect the previous selected rows - * after the grid content has been reloaded/refreshed. Defaults to FALSE. - */ -Ext.define("OMV.module.admin.services.zfs.TreePanel", { - extend: "OMV.tree.Panel", - requires: [ - "OMV.window.MessageBox", - "OMV.grid.column.BinaryUnit", - "OMV.grid.column.BooleanIcon", - "OMV.grid.column.BooleanText", - "OMV.grid.column.Empty", - "OMV.grid.column.Hyperlink", - "OMV.grid.column.UnixTimestamp", - "OMV.grid.column.WhiteSpace" - ], - - border: false, - rowLines: false, - columnLines: true, - selModel: { - allowDeselect: true, - mode: "SINGLE" - }, - - hideTopToolbar: false, - hidePagingToolbar: true, - hideAddButton: false, - hideAddObjButton: false, - hideEditButton: false, - hideDeleteButton: false, - hideUpButton: true, - hideDownButton: true, - hideApplyButton: true, - hideRefreshButton: true, - addButtonText: _("Add Pool"), - addObjButtonText: _("Add Object"), - editButtonText: _("Edit"), - deleteButtonText: _("Delete"), - upButtonText: _("Up"), - downButtonText: _("Down"), - applyButtonText: _("Save"), - refreshButtonText: _("Refresh"), - deletionConfirmRequired: true, - deletionWaitMsg: _("Deleting selected item(s)"), - mode: "remote", - rememberSelected: false, - - initComponent: function() { - var me = this; - // Initialize toolbars. - me.dockedItems = []; - if(!me.hideTopToolbar) { - me.dockedItems.push(me.topToolbar = Ext.widget({ - xtype: "toolbar", - dock: "top", - items: me.getTopToolbarItems(me) - })); - } - if(!me.hidePagingToolbar) { - me.dockedItems.push({ - xtype: "toolbar", - dock: "bottom", - items: [ me.pagingToolbar = Ext.widget({ - xtype: "pagingtoolbar", - store: me.store, - displayInfo: true, - displayMsg: _("Displaying items {0} - {1} of {2}"), - emptyMsg: _("No items to display") - }) ] - }); - } - me.callParent(arguments); - // Register event handler. - // Process double clicks in grid. - me.on("itemdblclick", me.onItemDblClick, me); - // Process selections in grid, e.g. to update the toolbar. - var selModel = me.getSelectionModel(); - selModel.on("selectionchange", me.onSelectionChange, me); - // Remember selection to restore it after the grid has been - // refreshed. - if(me.rememberSelected) { - me.getStore().on("beforeload", function() { - if(!me.rendered || Ext.isEmpty(me.getEl())) - return; - if(!selModel.hasSelection()) - return; - me.previousSelected = selModel.getSelection(); - }); - me.getView().on("refresh", function(view) { - if(Ext.isEmpty(me.previousSelected)) - return; - var select = []; - Ext.Array.each(me.previousSelected, function(r) { - var record = me.getStore().getById(r.getId()); - if(!Ext.isEmpty(record)) - select.push(record); - }); - delete me.previousSelected; - if(select.length > 0) { - selModel.select(select, false, false); - selModel.view.focusNode(select[0]); - } - }); - } - }, - - /** - * Returns the items displayed in the top toolbar. - * @param c This component object. - * @return An array of buttons displayed in the top toolbar. - */ - getTopToolbarItems: function(c) { - var me = this; - return [{ - id: me.getId() + "-add", - xtype: "button", - text: me.addButtonText, - icon: "images/add.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideAddButton, - handler: Ext.Function.bind(me.onAddButton, me, [ me ]), - scope: me - },{ - id: me.getId() + "-addobj", - xtype: "button", - text: me.addObjButtonText, - icon: "images/add.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideAddObjButton, - handler: Ext.Function.bind(me.onAddObjButton, me, [ me ]), - scope: me, - disabled: true - },{ - id: me.getId() + "-edit", - xtype: "button", - text: me.editButtonText, - icon: "images/edit.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideEditButton, - handler: Ext.Function.bind(me.onEditButton, me, [ me ]), - scope: me, - disabled: true - },{ - id: me.getId() + "-delete", - xtype: "button", - text: me.deleteButtonText, - icon: "images/delete.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideDeleteButton, - handler: Ext.Function.bind(me.onDeleteButton, me, [ me ]), - scope: me, - disabled: true - },{ - id: me.getId() + "-up", - xtype: "button", - text: me.upButtonText, - icon: "images/arrow-up.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideUpButton, - handler: Ext.Function.bind(me.onUpButton, me, [ me ]), - scope: me, - disabled: true - },{ - id: me.getId() + "-down", - xtype: "button", - text: me.downButtonText, - icon: "images/arrow-down.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideDownButton, - handler: Ext.Function.bind(me.onDownButton, me, [ me ]), - scope: me, - disabled: true - },{ - id: me.getId() + "-apply", - xtype: "button", - text: me.applyButtonText, - icon: "images/checkmark.png", - hidden: me.hideApplyButton, - handler: Ext.Function.bind(me.onApplyButton, me, [ me ]), - scope: me - },{ - id: me.getId() + "-refresh", - xtype: "button", - text: me.refreshButtonText, - icon: "images/refresh.png", - iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", - hidden: me.hideRefreshButton, - handler: Ext.Function.bind(me.onRefreshButton, me, [ me ]), - scope: me - }] - }, - - /** - * Handler that is called whenever the selection in the grid has - * been changed. The top toolbar buttons will be enabled/disabled - * depending on how much rows has been selected. - * @param model The selection model - */ - onSelectionChange: function(model, records) { - var me = this; - if(me.hideTopToolbar) - return; - var tbarBtnName = [ "addobj", "edit", "delete", "up", "down" ]; - var tbarBtnDisabled = { - "addobj": false, - "edit": false, - "delete": false, - "up": true, - "down": true - }; - // Enable/disable buttons depending on the number of selected rows. - if(records.length <= 0) { - tbarBtnDisabled["addobj"] = true; - tbarBtnDisabled["edit"] = true; - tbarBtnDisabled["delete"] = true; - tbarBtnDisabled["up"] = true; - tbarBtnDisabled["down"] = true; - } else if(records.length == 1) { - tbarBtnDisabled["addobj"] = false; - tbarBtnDisabled["edit"] = false; - tbarBtnDisabled["delete"] = false; - tbarBtnDisabled["up"] = false; - tbarBtnDisabled["down"] = false; - } else { - tbarBtnDisabled["addobj"] = true; - tbarBtnDisabled["edit"] = true; - tbarBtnDisabled["delete"] = false; - tbarBtnDisabled["up"] = false; - tbarBtnDisabled["down"] = false; - } - //Disable 'AddObj' button if selected row is a Poool or a Snapshot - Ext.Array.each(records, function(record) { - if(("Pool" == record.get("type")) || - ("Snapshot" == record.get("type"))) { - tbarBtnDisabled["addobj"] = true; - return false; - } - }); - - // Disable 'Delete' button if a selected node is not a leaf - Ext.Array.each(records, function(record) { - if((false == record.get("leaf"))) { - tbarBtnDisabled["delete"] = true; - return false; - } - }); - - // Update the button controls. - Ext.Array.each(tbarBtnName, function(name) { - var tbarBtnCtrl = me.queryById(me.getId() + "-" + name); - if(!Ext.isEmpty(tbarBtnCtrl)) { - if(true == tbarBtnDisabled[name]) { - tbarBtnCtrl.disable(); - } else { - tbarBtnCtrl.enable(); - } - } - }); - }, - - onItemDblClick: function() { - var me = this; - if(!me.hideTopToolbar && !me.hideEditButton) { - me.onEditButton(me); - } - }, - - /** - * Load the grid content. - */ - doLoad: function() { - var me = this; - if(me.mode === "remote") { - me.store.load(); - } - }, - - /** - * Reload the grid content. - */ - doReload: function() { - var me = this; - if(me.mode === "remote") { - me.store.reload(); - } - }, - - /** - * Handler that is called when the 'Add' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onAddButton: function() { - // Nothing to do here - }, - - /** - * * Handler that is called when the 'AddObj' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onAddObjButton: function() { - // Nothing to do here - }, - - - /** - * Handler that is called when the 'Edit' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onEditButton: function() { - // Nothing to do here - }, - - /** - * Handler that is called when the 'Up' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onUpButton: function() { - var me = this; - var sm = me.getSelectionModel(); - var records = sm.getSelection(); - if(records.length > 0) { - // Find the smallest index of the selected rows. - var ltIndex = me.store.indexOf(records[0]); - Ext.Array.each(records, function(record) { - var index = me.store.indexOf(record); - if(ltIndex > index) - ltIndex = index; - }); - // Calculate the index where to insert the rows. - var index = ltIndex - 1; - if(index < 0) - index = 0; - me.doMoveRows(records, index); - } - }, - - /** - * Handler that is called when the 'Down' button in the top toolbar - * is pressed. - * @param this The grid itself. - */ - onDownButton: function() { - var me = this; - var sm = me.getSelectionModel(); - var records = sm.getSelection(); - if(records.length > 0) { - // Find the smallest index of the selected rows. - var ltIndex = me.store.indexOf(records[0]); - Ext.Array.each(records, function(record) { - var index = me.store.indexOf(record); - if(ltIndex > index) - ltIndex = index; - }); - // Calculate the index where to insert the rows. - var index = ltIndex + records.length; - var count = me.store.getCount() - 1; - if(index > count) - index = count; - me.doMoveRows(records, index); - } - }, - - /** - * Handler that is called when the 'Apply' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onApplyButton: function() { - // Nothing to do here - }, - - /** - * Handler that is called when the 'Refresh' button in the top toolbar - * is pressed. Override this method to customize the default behaviour. - * @param this The grid itself. - */ - onRefreshButton: function() { - this.doReload(); - }, - - /** - * Move the given rows to the given index. - * @param records The records to move. - * @param index The index where to insert the rows to be moved. - */ - doMoveRows: function(records, index) { - var me = this; - if(!Ext.isNumber(index)) - return; - records = Ext.Array.from(records); - me.store.suspendEvents(); - Ext.Array.each(records, function(record) { - me.store.remove(record); - me.store.insert(index, record); - }); - me.store.resumeEvents(); - me.afterMoveRows(records, index); - me.getView().refresh(); - }, - - /** - * Function that is called after the selected rows have been moved. - * Override this method to customize the default behaviour. - * @param records The records that have been move. - * @param index The index where the rows have been inserted. - */ - afterMoveRows: function(records, index) { - var sm = this.getSelectionModel(); - sm.select(records); - }, - - /** - * Handler that is called when the 'Delete' button in the top toolbar - * is pressed. - */ - onDeleteButton: function() { - var me = this; - var sm = me.getSelectionModel(); - var records = sm.getSelection(); - if(me.deletionConfirmRequired === true) { - var msg = _("Do you really want to delete the selected item(s)?"); - OMV.MessageBox.show({ - title: _("Confirmation"), - msg: msg, - buttons: Ext.Msg.YESNO, - fn: function(answer) { - if(answer !== "yes") - return; - me.startDeletion(records); - }, - scope: me, - icon: Ext.Msg.QUESTION - }); - } else { - me.startDeletion(records); - } - }, - - /** - * @private - * Private method that is called when the deletion of the selected records - * has been aggreed. - * @param records The records to delete. - */ - startDeletion: function(records) { - var me = this; - if(records.length <= 0) - return; - // Store selected records in a local variable - me.delActionInfo = { - records: records, - count: records.length - } - // Get first record to be deleted - var record = me.delActionInfo.records.pop(); - // Display progress dialog - OMV.MessageBox.progress("", me.deletionWaitMsg, ""); - me.updateDeletionProgress(); - // Execute deletion function - me.doDeletion(record); - }, - - /** - * The method that is called to delete a selected record. Override this - * method to customize the default behaviour. This is necessary in - * 'remote' mode. - */ - doDeletion: function(record) { - var me = this; - if(me.mode === "local") { - // Remove record from store - me.store.remove(record); - // Continue deletion process - me.onDeletion(null, true, null); - } - }, - - /** - * The method that is called by the 'doDeletion' method. The progress - * bar will be updated and the deletion progress will be continued if - * there are still records to delete. - */ - onDeletion: function(id, success, response) { - var me = this; - if(!success) { - // Remove temporary local variables - delete me.delActionInfo; - // Hide progress dialog - OMV.MessageBox.hide(); - // Display error message - OMV.MessageBox.error(null, response); - } else { - if(me.delActionInfo.records.length > 0) { - var record = me.delActionInfo.records.pop(); - // Update progress dialog - me.updateDeletionProgress(); - // Execute deletion function - me.doDeletion(record); - } else { - // Remove temporary local variables - delete me.delActionInfo; - // Update and hide progress dialog - OMV.MessageBox.updateProgress(1, _("100% completed ...")); - OMV.MessageBox.hide(); - me.afterDeletion(); - } - } - }, - - /** - * Function that is called after the deletion has been successful finished. - */ - afterDeletion: function() { - var me = this; - if(me.mode === "remote") { - me.doReload(); - } - }, - - /** - * @private - * Private helper function to update the progress dialog. - */ - updateDeletionProgress: function() { - var me = this; - // Calculate percentage - var p = (me.delActionInfo.count - me.delActionInfo.records.length) / - me.delActionInfo.count; - // Create message text - var text = Math.round(100 * p) + _("% completed ..."); - // Update progress dialog - OMV.MessageBox.updateProgress(p, text); - }, - - /** - * Convenience function for setting the given toolbar button - * disabled/enabled. - * @param name The name of the toolbar button. - * @param disabled TRUE to disable the button, FALSE to enable. - * @return The button component, otherwise FALSE. - */ - setToolbarButtonDisabled: function(name, disabled) { - var me = this; - var result = false; - var btnCtrl = me.queryById(me.getId() + "-" + name); - if(!Ext.isEmpty(btnCtrl) && btnCtrl.isButton) - result = btnCtrl.setDisabled(disabled); - return result; - }, - - /** - * Helper function to get the top toolbar object. - * @return The paging toolbar object or NULL. - */ - getTopToolbar: function() { - return this.topToolbar; - }, - - /** - * Helper function to get the paging toolbar object. - * @return The paging toolbar object or NULL. - */ - getPagingToolbar: function() { - return this.pagingToolbar; - } -}); - - - diff --git a/gui/js/omv/module/admin/service/zfs/Zfs.js b/gui/js/omv/module/admin/service/zfs/Zfs.js deleted file mode 100644 index 7afb906..0000000 --- a/gui/js/omv/module/admin/service/zfs/Zfs.js +++ /dev/null @@ -1,8 +0,0 @@ -OMV.WorkspaceManager.registerNode({ - id : "zfs", - path : "/storage", - text : _("ZFS"), - icon16 : "images/zfs.png", - iconSvg : "images/zfs.svg" -}); - diff --git a/gui/js/omv/module/admin/storage/zfs/Overview.js b/gui/js/omv/module/admin/storage/zfs/Overview.js new file mode 100644 index 0000000..fe72e89 --- /dev/null +++ b/gui/js/omv/module/admin/storage/zfs/Overview.js @@ -0,0 +1,503 @@ +// require("js/omv/tree/Panel.js") +// require("js/omv/module/admin/service/zfs/TreePanel.js") +// require("js/omv/workspace/window/Grid.js") + +Ext.define("OMV.module.admin.services.zfs.AddObject", { + extend: "OMV.workspace.window.Form", + uses: [ + "OMV.data.Store", + "OMV.data.Model", + "OMV.data.proxy.Rpc", + "OMV.data.reader.RpcArray" + ], + + rpcService: "ZFS", + rpcSetMethod: "addObject", + width: 420, + + getFormItems: function() { + var me = this; + return [{ + xtype: "combo", + name: "type", + fieldLabel: _("Object Type"), + queryMode: "local", + store: [ + [ "filesystem", "Filesystem" ], + [ "snapshot", "Snapshot" ], + [ "volume", "Volume" ] + ], + allowBlank: true, + editable: false, + triggerAction: "all", + value: "filesystem", + listeners: { + scope: me, + change: function(combo, value) { + var sizeField = this.findField("size"); + switch(value) { + case "volume": + sizeField.show(); + sizeField.allowBlank = false; + break; + default: + sizeField.hide(); + sizeField.allowBlank = true; + break; + } + sizeField.validate(); + } + } + },{ + xtype: "textfield", + name: "path", + fieldLabel: _("Prefix"), + allowBlank: false, + readOnly: true + },{ + xtype: "textfield", + name: "name", + fieldLabel: _("Name"), + allowBlank: false, + plugins: [{ + ptype: "fieldinfo", + text: _("Name of the new object. Prefix will prepend the name. Please omit leading /") + }] + },{ + xtype: "textfield", + name: "size", + hidden: true, + fieldLabel: _("Size"), + allowBlank: true, + plugins: [{ + ptype: "fieldinfo", + text: _("Size of the volume e.g. 5mb,100gb,1tb etc") + }] + }]; + } +}); + + + +Ext.define("OMV.module.admin.service.zfs.EditProperties", { + extend: "OMV.workspace.window.Grid", + requires: [ + "OMV.data.Store", + "OMV.data.Model", + "OMV.data.proxy.Rpc" + ], + + rpcService: "ZFS", + rpcSetMethod: "setProperties", + + title: _("Edit properties"), + width: 500, + height: 305, + + getGridConfig: function() { + var me = this; + + var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', { + clicksToEdit: 1, + pluginId: 'rowEditing', + listeners: { + validateedit: function(editor, e, eOpts) { + e.record.set("modified", "true"); + }, + beforeedit: function(editor, e, eOpts) { + if (e.record.get("property") === "mountpoint") { + e.grid.getPlugin('rowEditing').editor.form.findField("value").disable(); + e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); + } else if (e.record.get("newproperty") === "false") { + e.grid.getPlugin('rowEditing').editor.form.findField("value").enable(); + e.grid.getPlugin('rowEditing').editor.form.findField("property").disable(); + } else { + e.grid.getPlugin('rowEditing').editor.form.findField("value").enable(); + e.grid.getPlugin('rowEditing').editor.form.findField("property").enable(); + } + } + + } + }); + + var store = Ext.create("OMV.data.Store", { + autoLoad: true, + model: OMV.data.Model.createImplicit({ + fields: [ + { name: "property", type: "string" }, + { name: "value", type: "string" }, + { name: "source", type: "string" }, + { name: "modified", type: "string" }, + { name: "newproperty", type: "string", defaultValue: "false" } + ] + }), + proxy: { + type: "rpc", + rpcData: { + service: "ZFS", + method: "getProperties", + params: { + name: me.name, + type: me.type + } + } + } + }); + + return { + border: false, + stateful: true, + stateId: "8c3dc800-bdbb-11e3-b1b6-0800200c9a66", + selType: 'rowmodel', + plugins: [rowEditing], + store: store, + tbar: [{ + text: "Add property", + icon: "images/add.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + handler: function(view) { + Ext.define('Property', { + extend: 'Ext.data.Model', + fields: [ + "property", + "value", + "source", + "modified", + "newproperty" + ] + }); + var newProperty = Ext.create("Property", { + property: "", + value: "", + source: "local", + modified: "true", + newproperty: "true" + }); + rowEditing.cancelEdit(); + store.insert(0, newProperty); + rowEditing.startEdit(); + } + }], + columns: [{ + text: _("Property"), + sortable: true, + dataIndex: "property", + stateId: "property", + editor: { + xtype: "textfield", + allowBlank: false, + } + },{ + text: _("Value"), + sortable: true, + dataIndex: "value", + stateId: "value", + flex: 1, + readOnly: true, + editor: { + xtype: "textfield", + allowBlank: false, + } + },{ + text: _("Source"), + sortable: true, + dataIndex: "source", + stateId: "source", + },{ + xtype: 'actioncolumn', + header: 'Inherit', + icon: "images/checkmark.png", + tooltip: "Inherit", + handler: function(view, rowIndex, colIndex, item, e, record, row) { + OMV.RpcObserver.request({ + msg : _("Updating property..."), + rpcData : { + service: "ZFS", + method: "inherit", + params: { + name: me.name, + type: me.type, + property: record.get("property") + } + }, + finish : function() { + view.getStore().reload(); + } + }); + }, + isDisabled: function(view, rowIdx, colIdx, item, record) { + var src = record.get("source"); + if(src === "local") { + return false; + } else { + return true; + } + } + },{ + text: _("New"), + dataIndex: "newproperty", + stateId: "newproperty", + sortable: false, + hidden: true + },{ + text: _("Modified"), + sortable: false, + dataIndex: "modified", + stateId: "modified", + hidden: true + }], + }; + }, + + getRpcSetParams: function() { + var me = this; + var properties = []; + var values = me.getValues(); + Ext.Array.each(values, function(value) { + if(value.modified === "false") + return; + properties.push({ + "property": value.property, + "value": value.value, + }); + }); + return { + name: me.name, + type: me.type, + properties: properties + }; + } + +}); + + +Ext.define("OMV.module.admin.services.zfs.CreateShare", { + extend: "OMV.workspace.window.Form", + uses: [ + "OMV.data.Store", + "OMV.data.Model", + "OMV.data.proxy.Rpc", + "OMV.data.reader.RpcArray" + ], + + rpcService: "ZFS", + rpcSetMethod: "createShare", + width: 500, + + getFormItems: function() { + var me = this; + return [{ + xtype: "textfield", + name: "sharename", + fieldLabel: _("Name"), + allowBlank: false, + },{ + xtype: "textfield", + name: "mountpoint", + fieldLabel: _("Path"), + allowBlank: false, + readOnly: true + },{ + xtype: "combo", + name: "mode", + fieldLabel: _("Permissions"), + queryMode: "local", + store: Ext.create("Ext.data.ArrayStore", { + fields: [ "value", "text" ], + data: [ + [ "700", _("Administrator: read/write, Users: no access, Others: no access") ], + [ "750", _("Administrator: read/write, Users: read-only, Others: no access") ], + [ "770", _("Administrator: read/write, Users: read/write, Others: no access") ], + [ "755", _("Administrator: read/write, Users: read-only, Others: read-only") ], + [ "775", _("Administrator: read/write, Users: read/write, Others: read-only") ], + [ "777", _("Everyone: read/write") ] + ] + }), + displayField: "text", + valueField: "value", + allowBlank: false, + editable: false, + showItemTooltip: true, + triggerAction: "all", + value: "775", + plugins: [{ + ptype: "fieldinfo", + text: _("The file mode of the shared folder path.") + }] + },{ + xtype: "textarea", + name: "comment", + fieldLabel: _("Comment"), + allowBlank: true + },{ + xtype: "textarea", + name: "name", + hidden: true + },{ + xtype: "textarea", + name: "type", + hidden: true + }]; + } +}); + + + +Ext.define("OMV.module.admin.service.zfs.Overview", { + extend: "OMV.module.admin.services.zfs.TreePanel", + + rpcService: "ZFS", + rpcGetMethod: "getObjectTree", + requires: [ + "OMV.data.Store", + "OMV.data.Model", + "OMV.data.proxy.Rpc" + ], + + rootVisible: false, + stateful: true, + stateId: "cec54550-bc2a-11e3-a5e2-0800200c9a66", + + columns: [{ + text: _("Name"), + xtype: 'treecolumn', + dataIndex: 'name', + sortable: true, + flex: 2, + stateId: 'name' + },{ + text: _("Type"), + dataIndex: 'type', + sortable: true, + flex: 1, + stateId: 'type' + },{ + text: _("Share"), + xtype: 'actioncolumn', + tooltip: 'Create shared folder', + align: 'center', + icon: 'images/checkmark.png', + handler: function(view, rowIndex, colIndex, item, e, record, row) { + var me = this; + Ext.create("OMV.module.admin.services.zfs.CreateShare", { + title: _("Create shared folder"), + rpcGetMethod: "getSharedParams", + rpcGetParams: { + name: record.get('path'), + type: record.get('type') + } + }).show(); + }, + isDisabled: function(view, rowIdx, colIdx, item, record) { + var src = record.get("type"); + if((src === "Filesystem") && (record.get("shared") === "false")) { + return false; + } else { + return true; + } + } + + + },{ + text: _("Details"), + xtype: 'actioncolumn', + tooltip: 'Details', + align: 'center', + icon: 'images/zfs_mag.png' + },{ + text: _("Shared"), + dataIndex: 'shared', + sortable: false, + stateId: 'shared', + hidden: true + }], + + initComponent: function() { + var me = this; + this.width = 600; + Ext.apply(me, { + store: Ext.create("Ext.data.TreeStore", { + autoLoad: true, + model: OMV.data.Model.createImplicit({ + fields: [ + { name: "name", type: "string" }, + { name: "type", type: "string" }, + { name: "id", type: "string" }, + { name: "path", type: "string" }, + { name: "origin", type: "string", defaultValue: "none" }, + { name: "shared", type: "string", defaultValue: "false" } + ] + }), + proxy: { + type: "rpc", + rpcData: { + service: "ZFS", + method: "getObjectTree", + } + }, + folderSort: true + }) + }); + me.callParent(arguments); + }, + + onAddObjButton: function() { + var me = this; + var sm = me.getSelectionModel(); + var records = sm.getSelection(); + var record = records[0]; + Ext.create("OMV.module.admin.services.zfs.AddObject", { + title: _("Add Object"), + rpcGetMethod: "passParam", + rpcGetParams: { + key: "path", + value: record.get('path') + }, + listeners: { + scope: me, + submit: function() { + this.doReload(); + } + } + }).show(); + }, + + onEditButton: function() { + var me = this; + var sm = me.getSelectionModel(); + var records = sm.getSelection(); + var record = records[0]; + Ext.create("OMV.module.admin.service.zfs.EditProperties", { + name: record.get("path"), + type: record.get("type") + }).show(); + }, + + doDeletion: function(record) { + var me = this; + OMV.Rpc.request({ + scope: me, + callback: me.onDeletion, + rpcData: { + service: "ZFS", + method: "deleteObject", + params: { + name: record.get('path'), + type: record.get('type') + } + } + }); + } + +}); + +OMV.WorkspaceManager.registerPanel({ + id: "overview", + path: "/service/zfs", + text: _("Overview"), + position: 10, + className: "OMV.module.admin.service.zfs.Overview" +}); + + + diff --git a/gui/js/omv/module/admin/storage/zfs/TreePanel.js b/gui/js/omv/module/admin/storage/zfs/TreePanel.js new file mode 100644 index 0000000..26a25ce --- /dev/null +++ b/gui/js/omv/module/admin/storage/zfs/TreePanel.js @@ -0,0 +1,646 @@ +/** + * This file is part of OpenMediaVault. + * + * @license http://www.gnu.org/licenses/gpl.html GPL Version 3 + * @author Volker Theile + * @copyright Copyright (c) 2009-2014 Volker Theile + * + * OpenMediaVault is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * OpenMediaVault is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenMediaVault. If not, see . + */ +// require("js/omv/tree/Panel.js") +// require("js/omv/grid/Panel.js") +// require("js/omv/grid/column/BinaryUnit.js") +// require("js/omv/grid/column/BooleanIcon.js") +// require("js/omv/grid/column/BooleanText.js") +// require("js/omv/grid/column/Empty.js") +// require("js/omv/grid/column/Hyperlink.js") +// require("js/omv/grid/column/UnixTimestamp.js") +// require("js/omv/grid/column/WhiteSpace.js") +// require("js/omv/window/MessageBox.js") + +/** + * @ingroup webgui + * @class OMV.workspace.grid.Panel + * @derived OMV.grid.Panel + * An enhanced grid panel. This grid provides 'Add', 'Edit' and 'Delete' + * buttons in the toolbar by default. The basic delete functionality is also + * implemented, simply overwrite the 'doDeletion' and 'afterDeletion' + * functions to implement fit your requirements. To implement the 'Add' and + * 'Edit' functionality overwrite the 'onAdd' and 'onEdit' callback + * functions. A paging toolbar which is displayed at the bottom of the grid + * can be displayed also. It is also possible to reload the grid + * automatically in a given interval. + * @param hideTopToolbar TRUE to hide the whole toolbar. Defaults to FALSE. + * @param hidePagingToolbar TRUE to hide the paging toolbar at the bottom of + * the grid. Defaults to TRUE. + * @param hideAddButton Hide the 'Add' button in the top toolbar. + * Defaults to FALSE. + * @param hideEditButton Hide the 'Edit' button in the top toolbar. + * Defaults to FALSE. + * @param hideDeleteButton Hide the 'Delete' button in the top toolbar. + * Defaults to FALSE. + * @param hideUpButton Hide the 'Up' button in the top toolbar. + * Defaults to TRUE. + * @param hideDownButton Hide the 'Down' button in the top toolbar. + * Defaults to TRUE. + * @param hideApplyButton Hide the 'Apply' button in the top toolbar. + * Defaults to TRUE. + * @param hideRefreshButton Hide the 'Refresh' button in the top toolbar. + * Defaults to TRUE. + * @param addButtonText The button text. Defaults to 'Add'. + * @param editButtonText The button text. Defaults to 'Edit'. + * @param deleteButtonText The button text. Defaults to 'Delete'. + * @param upButtonText The button text. Defaults to 'Up'. + * @param downButtonText The button text. Defaults to 'Down'. + * @param applyButtonText The button text. Defaults to 'Save'. + * @param refreshButtonText The button text. Defaults to 'Refresh'. + * @param deletionConfirmRequired Set to TRUE to force the user to confirm + * the deletion request. Defaults to TRUE. + * @param deletionWaitMsg The message displayed during the deletion process. + * @param mode The mode how to retrieve the data displayed in the grid panel. + * This can be 'local' or 'remote' which means the data is requested via + * RPC. Defaults to 'remote'. + * @param rememberSelected TRUE to reselect the previous selected rows + * after the grid content has been reloaded/refreshed. Defaults to FALSE. + */ +Ext.define("OMV.module.admin.services.zfs.TreePanel", { + extend: "OMV.tree.Panel", + requires: [ + "OMV.window.MessageBox", + "OMV.grid.column.BinaryUnit", + "OMV.grid.column.BooleanIcon", + "OMV.grid.column.BooleanText", + "OMV.grid.column.Empty", + "OMV.grid.column.Hyperlink", + "OMV.grid.column.UnixTimestamp", + "OMV.grid.column.WhiteSpace" + ], + + border: false, + rowLines: false, + columnLines: true, + selModel: { + allowDeselect: true, + mode: "SINGLE" + }, + + hideTopToolbar: false, + hidePagingToolbar: true, + hideAddButton: false, + hideAddObjButton: false, + hideEditButton: false, + hideDeleteButton: false, + hideUpButton: true, + hideDownButton: true, + hideApplyButton: true, + hideRefreshButton: true, + addButtonText: _("Add Pool"), + addObjButtonText: _("Add Object"), + editButtonText: _("Edit"), + deleteButtonText: _("Delete"), + upButtonText: _("Up"), + downButtonText: _("Down"), + applyButtonText: _("Save"), + refreshButtonText: _("Refresh"), + deletionConfirmRequired: true, + deletionWaitMsg: _("Deleting selected item(s)"), + mode: "remote", + rememberSelected: false, + + initComponent: function() { + var me = this; + // Initialize toolbars. + me.dockedItems = []; + if(!me.hideTopToolbar) { + me.dockedItems.push(me.topToolbar = Ext.widget({ + xtype: "toolbar", + dock: "top", + items: me.getTopToolbarItems(me) + })); + } + if(!me.hidePagingToolbar) { + me.dockedItems.push({ + xtype: "toolbar", + dock: "bottom", + items: [ me.pagingToolbar = Ext.widget({ + xtype: "pagingtoolbar", + store: me.store, + displayInfo: true, + displayMsg: _("Displaying items {0} - {1} of {2}"), + emptyMsg: _("No items to display") + }) ] + }); + } + me.callParent(arguments); + // Register event handler. + // Process double clicks in grid. + me.on("itemdblclick", me.onItemDblClick, me); + // Process selections in grid, e.g. to update the toolbar. + var selModel = me.getSelectionModel(); + selModel.on("selectionchange", me.onSelectionChange, me); + // Remember selection to restore it after the grid has been + // refreshed. + if(me.rememberSelected) { + me.getStore().on("beforeload", function() { + if(!me.rendered || Ext.isEmpty(me.getEl())) + return; + if(!selModel.hasSelection()) + return; + me.previousSelected = selModel.getSelection(); + }); + me.getView().on("refresh", function(view) { + if(Ext.isEmpty(me.previousSelected)) + return; + var select = []; + Ext.Array.each(me.previousSelected, function(r) { + var record = me.getStore().getById(r.getId()); + if(!Ext.isEmpty(record)) + select.push(record); + }); + delete me.previousSelected; + if(select.length > 0) { + selModel.select(select, false, false); + selModel.view.focusNode(select[0]); + } + }); + } + }, + + /** + * Returns the items displayed in the top toolbar. + * @param c This component object. + * @return An array of buttons displayed in the top toolbar. + */ + getTopToolbarItems: function(c) { + var me = this; + return [{ + id: me.getId() + "-add", + xtype: "button", + text: me.addButtonText, + icon: "images/add.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideAddButton, + handler: Ext.Function.bind(me.onAddButton, me, [ me ]), + scope: me + },{ + id: me.getId() + "-addobj", + xtype: "button", + text: me.addObjButtonText, + icon: "images/add.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideAddObjButton, + handler: Ext.Function.bind(me.onAddObjButton, me, [ me ]), + scope: me, + disabled: true + },{ + id: me.getId() + "-edit", + xtype: "button", + text: me.editButtonText, + icon: "images/edit.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideEditButton, + handler: Ext.Function.bind(me.onEditButton, me, [ me ]), + scope: me, + disabled: true + },{ + id: me.getId() + "-delete", + xtype: "button", + text: me.deleteButtonText, + icon: "images/delete.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideDeleteButton, + handler: Ext.Function.bind(me.onDeleteButton, me, [ me ]), + scope: me, + disabled: true + },{ + id: me.getId() + "-up", + xtype: "button", + text: me.upButtonText, + icon: "images/arrow-up.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideUpButton, + handler: Ext.Function.bind(me.onUpButton, me, [ me ]), + scope: me, + disabled: true + },{ + id: me.getId() + "-down", + xtype: "button", + text: me.downButtonText, + icon: "images/arrow-down.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideDownButton, + handler: Ext.Function.bind(me.onDownButton, me, [ me ]), + scope: me, + disabled: true + },{ + id: me.getId() + "-apply", + xtype: "button", + text: me.applyButtonText, + icon: "images/checkmark.png", + hidden: me.hideApplyButton, + handler: Ext.Function.bind(me.onApplyButton, me, [ me ]), + scope: me + },{ + id: me.getId() + "-refresh", + xtype: "button", + text: me.refreshButtonText, + icon: "images/refresh.png", + iconCls: Ext.baseCSSPrefix + "btn-icon-16x16", + hidden: me.hideRefreshButton, + handler: Ext.Function.bind(me.onRefreshButton, me, [ me ]), + scope: me + }] + }, + + /** + * Handler that is called whenever the selection in the grid has + * been changed. The top toolbar buttons will be enabled/disabled + * depending on how much rows has been selected. + * @param model The selection model + */ + onSelectionChange: function(model, records) { + var me = this; + if(me.hideTopToolbar) + return; + var tbarBtnName = [ "addobj", "edit", "delete", "up", "down" ]; + var tbarBtnDisabled = { + "addobj": false, + "edit": false, + "delete": false, + "up": true, + "down": true + }; + // Enable/disable buttons depending on the number of selected rows. + if(records.length <= 0) { + tbarBtnDisabled["addobj"] = true; + tbarBtnDisabled["edit"] = true; + tbarBtnDisabled["delete"] = true; + tbarBtnDisabled["up"] = true; + tbarBtnDisabled["down"] = true; + } else if(records.length == 1) { + tbarBtnDisabled["addobj"] = false; + tbarBtnDisabled["edit"] = false; + tbarBtnDisabled["delete"] = false; + tbarBtnDisabled["up"] = false; + tbarBtnDisabled["down"] = false; + } else { + tbarBtnDisabled["addobj"] = true; + tbarBtnDisabled["edit"] = true; + tbarBtnDisabled["delete"] = false; + tbarBtnDisabled["up"] = false; + tbarBtnDisabled["down"] = false; + } + //Disable 'AddObj' button if selected row is a Poool or a Snapshot + Ext.Array.each(records, function(record) { + if(("Pool" == record.get("type")) || + ("Snapshot" == record.get("type"))) { + tbarBtnDisabled["addobj"] = true; + return false; + } + }); + + // Disable 'Delete' button if a selected node is not a leaf + Ext.Array.each(records, function(record) { + if((false == record.get("leaf"))) { + tbarBtnDisabled["delete"] = true; + return false; + } + }); + + // Update the button controls. + Ext.Array.each(tbarBtnName, function(name) { + var tbarBtnCtrl = me.queryById(me.getId() + "-" + name); + if(!Ext.isEmpty(tbarBtnCtrl)) { + if(true == tbarBtnDisabled[name]) { + tbarBtnCtrl.disable(); + } else { + tbarBtnCtrl.enable(); + } + } + }); + }, + + onItemDblClick: function() { + var me = this; + if(!me.hideTopToolbar && !me.hideEditButton) { + me.onEditButton(me); + } + }, + + /** + * Load the grid content. + */ + doLoad: function() { + var me = this; + if(me.mode === "remote") { + me.store.load(); + } + }, + + /** + * Reload the grid content. + */ + doReload: function() { + var me = this; + if(me.mode === "remote") { + me.store.reload(); + } + }, + + /** + * Handler that is called when the 'Add' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onAddButton: function() { + // Nothing to do here + }, + + /** + * * Handler that is called when the 'AddObj' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onAddObjButton: function() { + // Nothing to do here + }, + + + /** + * Handler that is called when the 'Edit' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onEditButton: function() { + // Nothing to do here + }, + + /** + * Handler that is called when the 'Up' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onUpButton: function() { + var me = this; + var sm = me.getSelectionModel(); + var records = sm.getSelection(); + if(records.length > 0) { + // Find the smallest index of the selected rows. + var ltIndex = me.store.indexOf(records[0]); + Ext.Array.each(records, function(record) { + var index = me.store.indexOf(record); + if(ltIndex > index) + ltIndex = index; + }); + // Calculate the index where to insert the rows. + var index = ltIndex - 1; + if(index < 0) + index = 0; + me.doMoveRows(records, index); + } + }, + + /** + * Handler that is called when the 'Down' button in the top toolbar + * is pressed. + * @param this The grid itself. + */ + onDownButton: function() { + var me = this; + var sm = me.getSelectionModel(); + var records = sm.getSelection(); + if(records.length > 0) { + // Find the smallest index of the selected rows. + var ltIndex = me.store.indexOf(records[0]); + Ext.Array.each(records, function(record) { + var index = me.store.indexOf(record); + if(ltIndex > index) + ltIndex = index; + }); + // Calculate the index where to insert the rows. + var index = ltIndex + records.length; + var count = me.store.getCount() - 1; + if(index > count) + index = count; + me.doMoveRows(records, index); + } + }, + + /** + * Handler that is called when the 'Apply' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onApplyButton: function() { + // Nothing to do here + }, + + /** + * Handler that is called when the 'Refresh' button in the top toolbar + * is pressed. Override this method to customize the default behaviour. + * @param this The grid itself. + */ + onRefreshButton: function() { + this.doReload(); + }, + + /** + * Move the given rows to the given index. + * @param records The records to move. + * @param index The index where to insert the rows to be moved. + */ + doMoveRows: function(records, index) { + var me = this; + if(!Ext.isNumber(index)) + return; + records = Ext.Array.from(records); + me.store.suspendEvents(); + Ext.Array.each(records, function(record) { + me.store.remove(record); + me.store.insert(index, record); + }); + me.store.resumeEvents(); + me.afterMoveRows(records, index); + me.getView().refresh(); + }, + + /** + * Function that is called after the selected rows have been moved. + * Override this method to customize the default behaviour. + * @param records The records that have been move. + * @param index The index where the rows have been inserted. + */ + afterMoveRows: function(records, index) { + var sm = this.getSelectionModel(); + sm.select(records); + }, + + /** + * Handler that is called when the 'Delete' button in the top toolbar + * is pressed. + */ + onDeleteButton: function() { + var me = this; + var sm = me.getSelectionModel(); + var records = sm.getSelection(); + if(me.deletionConfirmRequired === true) { + var msg = _("Do you really want to delete the selected item(s)?"); + OMV.MessageBox.show({ + title: _("Confirmation"), + msg: msg, + buttons: Ext.Msg.YESNO, + fn: function(answer) { + if(answer !== "yes") + return; + me.startDeletion(records); + }, + scope: me, + icon: Ext.Msg.QUESTION + }); + } else { + me.startDeletion(records); + } + }, + + /** + * @private + * Private method that is called when the deletion of the selected records + * has been aggreed. + * @param records The records to delete. + */ + startDeletion: function(records) { + var me = this; + if(records.length <= 0) + return; + // Store selected records in a local variable + me.delActionInfo = { + records: records, + count: records.length + } + // Get first record to be deleted + var record = me.delActionInfo.records.pop(); + // Display progress dialog + OMV.MessageBox.progress("", me.deletionWaitMsg, ""); + me.updateDeletionProgress(); + // Execute deletion function + me.doDeletion(record); + }, + + /** + * The method that is called to delete a selected record. Override this + * method to customize the default behaviour. This is necessary in + * 'remote' mode. + */ + doDeletion: function(record) { + var me = this; + if(me.mode === "local") { + // Remove record from store + me.store.remove(record); + // Continue deletion process + me.onDeletion(null, true, null); + } + }, + + /** + * The method that is called by the 'doDeletion' method. The progress + * bar will be updated and the deletion progress will be continued if + * there are still records to delete. + */ + onDeletion: function(id, success, response) { + var me = this; + if(!success) { + // Remove temporary local variables + delete me.delActionInfo; + // Hide progress dialog + OMV.MessageBox.hide(); + // Display error message + OMV.MessageBox.error(null, response); + } else { + if(me.delActionInfo.records.length > 0) { + var record = me.delActionInfo.records.pop(); + // Update progress dialog + me.updateDeletionProgress(); + // Execute deletion function + me.doDeletion(record); + } else { + // Remove temporary local variables + delete me.delActionInfo; + // Update and hide progress dialog + OMV.MessageBox.updateProgress(1, _("100% completed ...")); + OMV.MessageBox.hide(); + me.afterDeletion(); + } + } + }, + + /** + * Function that is called after the deletion has been successful finished. + */ + afterDeletion: function() { + var me = this; + if(me.mode === "remote") { + me.doReload(); + } + }, + + /** + * @private + * Private helper function to update the progress dialog. + */ + updateDeletionProgress: function() { + var me = this; + // Calculate percentage + var p = (me.delActionInfo.count - me.delActionInfo.records.length) / + me.delActionInfo.count; + // Create message text + var text = Math.round(100 * p) + _("% completed ..."); + // Update progress dialog + OMV.MessageBox.updateProgress(p, text); + }, + + /** + * Convenience function for setting the given toolbar button + * disabled/enabled. + * @param name The name of the toolbar button. + * @param disabled TRUE to disable the button, FALSE to enable. + * @return The button component, otherwise FALSE. + */ + setToolbarButtonDisabled: function(name, disabled) { + var me = this; + var result = false; + var btnCtrl = me.queryById(me.getId() + "-" + name); + if(!Ext.isEmpty(btnCtrl) && btnCtrl.isButton) + result = btnCtrl.setDisabled(disabled); + return result; + }, + + /** + * Helper function to get the top toolbar object. + * @return The paging toolbar object or NULL. + */ + getTopToolbar: function() { + return this.topToolbar; + }, + + /** + * Helper function to get the paging toolbar object. + * @return The paging toolbar object or NULL. + */ + getPagingToolbar: function() { + return this.pagingToolbar; + } +}); + + + diff --git a/gui/js/omv/module/admin/storage/zfs/Zfs.js b/gui/js/omv/module/admin/storage/zfs/Zfs.js new file mode 100644 index 0000000..7afb906 --- /dev/null +++ b/gui/js/omv/module/admin/storage/zfs/Zfs.js @@ -0,0 +1,8 @@ +OMV.WorkspaceManager.registerNode({ + id : "zfs", + path : "/storage", + text : _("ZFS"), + icon16 : "images/zfs.png", + iconSvg : "images/zfs.svg" +}); +