diff --git a/www/Makefile b/www/Makefile index 76a23806..5a351a2b 100644 --- a/www/Makefile +++ b/www/Makefile @@ -26,6 +26,7 @@ JSSRC= \ dashboard/RunningTasks.js \ dashboard/TaskSummary.js \ Utils.js \ + ZFSList.js \ DirectoryList.js \ LoginView.js \ VersionInfo.js \ diff --git a/www/NavigationTree.js b/www/NavigationTree.js index 16b8c73a..8e75ea35 100644 --- a/www/NavigationTree.js +++ b/www/NavigationTree.js @@ -69,6 +69,12 @@ Ext.define('PBS.store.NavigationStore', { path: 'pbsDirectoryList', leaf: true, }, + { + text: "ZFS", + iconCls: 'fa fa-th-large', + path: 'pbsZFSList', + leaf: true, + }, ] } ] diff --git a/www/ZFSList.js b/www/ZFSList.js new file mode 100644 index 00000000..5b95ae60 --- /dev/null +++ b/www/ZFSList.js @@ -0,0 +1,137 @@ +Ext.define('PBS.admin.ZFSList', { + extend: 'Ext.grid.Panel', + xtype: 'pbsZFSList', + + stateful: true, + stateId: 'grid-node-zfs', + + controller: { + xclass: 'Ext.app.ViewController', + + openCreateWindow: function() { + let me = this; + Ext.create('PBS.window.CreateZFS', { + nodename: me.nodename, + listeners: { + destroy: function() { me.reload(); }, + } + }).show(); + }, + + openDetailWindow: function() { + let me = this; + let view = me.getView(); + let selection = view.getSelection(); + if (!selection || selection.length < 1) return; + + let rec = selection[0]; + let zpool = rec.get('name'); + + Ext.create('Proxmox.window.ZFSDetail', { + zpool, + nodename: view.nodename, + }).show(); + }, + + reload: function() { + let me = this; + let view = me.getView(); + let store = view.getStore(); + store.load(); + store.sort(); + }, + + init: function(view) { + let me = this; + + if (!view.nodename) { + throw "no nodename given"; + } + + let url = `/api2/json/nodes/${view.nodename}/disks/zfs`; + view.getStore().getProxy().setUrl(url) + + Proxmox.Utils.monStoreErrors(view, view.getStore(), true); + + me.reload(); + }, + }, + + columns: [ + { + text: gettext('Name'), + dataIndex: 'name', + flex: 1 + }, + { + header: gettext('Size'), + renderer: Proxmox.Utils.format_size, + dataIndex: 'size' + }, + { + header: gettext('Free'), + renderer: Proxmox.Utils.format_size, + dataIndex: 'free' + }, + { + header: gettext('Allocated'), + renderer: Proxmox.Utils.format_size, + dataIndex: 'alloc' + }, + { + header: gettext('Fragmentation'), + renderer: function(value) { + return value.toString() + '%'; + }, + dataIndex: 'frag' + }, + { + header: gettext('Health'), + renderer: Proxmox.Utils.render_zfs_health, + dataIndex: 'health' + }, + { + header: gettext('Deduplication'), + hidden: true, + renderer: function(value) { + return value.toFixed(2).toString() + 'x'; + }, + dataIndex: 'dedup' + } + ], + + rootVisible: false, + useArrows: true, + + tbar: [ + { + text: gettext('Reload'), + iconCls: 'fa fa-refresh', + handler: 'reload', + }, + { + text: gettext('Create') + ': ZFS', + handler: 'openCreateWindow', + }, + { + text: gettext('Detail'), + xtype: 'proxmoxButton', + disabled: true, + handler: function() { + } + } + ], + + listeners: { + itemdblclick: 'openDetailWindow', + }, + + store: { + fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'], + proxy: { + type: 'proxmox', + }, + sorters: 'name' + }, +}); + diff --git a/www/window/ZFSCreate.js b/www/window/ZFSCreate.js new file mode 100644 index 00000000..21e21a0c --- /dev/null +++ b/www/window/ZFSCreate.js @@ -0,0 +1,94 @@ +Ext.define('PBS.window.CreateZFS', { + extend: 'Proxmox.window.Edit', + xtype: 'pbsCreateZFS', + + subject: 'ZFS', + + showProgress: true, + + onlineHelp: 'chapter_zfs', + + width: 800, + + url: '/nodes/localhost/disks/zfs', + method: 'POST', + items: [ + { + xtype: 'inputpanel', + onGetValues: function(values) { + return values; + }, + column1: [ + { + xtype: 'proxmoxtextfield', + name: 'name', + fieldLabel: gettext('Name'), + allowBlank: false + }, + { + xtype: 'proxmoxcheckbox', + name: 'add-datastore', + fieldLabel: gettext('Add Datastore'), + value: '1' + } + ], + column2: [ + { + xtype: 'proxmoxKVComboBox', + fieldLabel: gettext('RAID Level'), + name: 'raidlevel', + value: 'single', + comboItems: [ + ['single', gettext('Single Disk')], + ['mirror', 'Mirror'], + ['raid10', 'RAID10'], + ['raidz', 'RAIDZ'], + ['raidz2', 'RAIDZ2'], + ['raidz3', 'RAIDZ3'] + ] + }, + { + xtype: 'proxmoxKVComboBox', + fieldLabel: gettext('Compression'), + name: 'compression', + value: 'on', + comboItems: [ + ['on', 'on'], + ['off', 'off'], + ['gzip', 'gzip'], + ['lz4', 'lz4'], + ['lzjb', 'lzjb'], + ['zle', 'zle'] + ] + }, + { + xtype: 'proxmoxintegerfield', + fieldLabel: gettext('ashift'), + minValue: 9, + maxValue: 16, + value: '12', + name: 'ashift' + } + ], + columnB: [ + { + xtype: 'pmxMultiDiskSelector', + name: 'devices', + nodename: 'localhost', + typeParam: 'usage-type', + valueField: 'name', + height: 200, + emptyText: gettext('No Disks unused'), + } + ] + }, + { + xtype: 'displayfield', + padding: '5 0 0 0', + userCls: 'pmx-hint', + value: 'Note: ZFS is not compatible with disks backed by a hardware ' + + 'RAID controller. For details see ' + + 'the reference documentation.', + }, + ], +});