From dd4d4f0014e0258d89ef52c8ff62c55bf4218a37 Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Thu, 18 Dec 2008 17:22:01 +0000 Subject: [PATCH] ebl Rewrite bresto for ExtJS 2.2, fix lots of bug git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@8185 91ce42f0-d328-0410-95d8-f526ca767f89 --- gui/bweb/html/bresto.html | 47 +- gui/bweb/html/bresto.js | 1347 +++++++++++++++++++------------------ gui/bweb/technotes-3.0 | 3 + 3 files changed, 693 insertions(+), 704 deletions(-) diff --git a/gui/bweb/html/bresto.html b/gui/bweb/html/bresto.html index b4f3cc588f..950bb98964 100644 --- a/gui/bweb/html/bresto.html +++ b/gui/bweb/html/bresto.html @@ -1,35 +1,14 @@ - - - - Bweb - restore - - - - - - - - - - - - -
-
-
-
-
-
-
-
-
- - - - + + Bacula Web Restore interface + + + + + + + +
+
+ + diff --git a/gui/bweb/html/bresto.js b/gui/bweb/html/bresto.js index 0b10b9c730..3b9e3baae1 100644 --- a/gui/bweb/html/bresto.js +++ b/gui/bweb/html/bresto.js @@ -1,8 +1,7 @@ - // Bweb - A Bacula web interface // Bacula® - The Network Backup Solution // -// Copyright (C) 2000-2006 Free Software Foundation Europe e.V. +// Copyright (C) 2000-2008 Free Software Foundation Europe e.V. // // The main author of Bweb is Eric Bollengier. // The main author of Bacula is Kern Sibbald, with contributions from @@ -31,21 +30,20 @@ // render if vol is online/offline function rd_vol_is_online(val) { - return ''; + return ''; } // TODO: fichier ou rep function rd_file_or_dir(val) { if (val == 'F') { - return ''; + return ''; } else { - return ''; + return ''; } } Ext.namespace('Ext.brestore'); - Ext.brestore.jobid=0; // selected jobid Ext.brestore.jobdate=''; // selected date Ext.brestore.client=''; // selected client @@ -53,12 +51,11 @@ Ext.brestore.rclient=''; // selected client for resto Ext.brestore.storage=''; // selected storage for resto Ext.brestore.path=''; // current path (without user location) Ext.brestore.root_path=''; // user location - +Ext.brestore.media_store; // media store Ext.brestore.option_vosb = false; Ext.brestore.option_vafv = false; Ext.brestore.dlglaunch; -Ext.BLANK_IMAGE_URL = '/bweb/ext/resources/images/aero/s.gif'; // 1.1 - +Ext.brestore.use_filerelocation=false; function get_node_path(node) { var temp=''; @@ -74,7 +71,6 @@ function get_node_path(node) return Ext.brestore.root_path + temp; } - function init_params(baseParams) { baseParams['client']= Ext.brestore.client; @@ -87,22 +83,42 @@ function init_params(baseParams) return baseParams; } +function captureEvents(observable) { + Ext.util.Observable.capture( + observable, + function(eventName) { + console.info(eventName); + }, + this + ); +} -function ext_init() -{ -//////////////////////////////////////////////////////////////: - var Tree = Ext.tree; +//////////////////////////////////////////////////////////////// + +Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif'; +Ext.onReady(function(){ + if (!Ext.version || Ext.version < 2.2) { + alert("You must upgrade your extjs version to 2.2"); + return; + } + + Ext.QuickTips.init(); + + // Init tree for directory selection var tree_loader = new Ext.tree.TreeLoader({ baseParams:{}, dataUrl:'/cgi-bin/bweb/bresto.pl' }); - var tree = new Ext.tree.TreePanel('div-tree', { + var tree = new Ext.tree.TreePanel({ animate:true, loader: tree_loader, enableDD:true, enableDragDrop: true, - containerScroll: true + containerScroll: true, + title: 'Directories', + width: 250, + minSize: 100 }); // set the root node @@ -112,13 +128,9 @@ function ext_init() id:'source' }); tree.setRootNode(root); - Ext.brestore.tree = root; - - // render the tree - tree.render(); -// root.expand(); + Ext.brestore.tree = root; // shortcut - click_cb = function(node, event) { + var click_cb = function(node, event) { Ext.brestore.path = get_node_path(node); where_field.setValue(Ext.brestore.path); file_store.removeAll(); @@ -126,16 +138,16 @@ function ext_init() file_store.load({params:init_params({action: 'list_files', path:Ext.brestore.path, node:node.id}) - }); + }); return true; }; + tree.on('click', click_cb); tree.on('beforeload', function(e) { file_store.removeAll(); return true; }); - tree.on('load', function(n,e) { if (!n.firstChild) { click_cb(n, e); @@ -143,156 +155,177 @@ function ext_init() return true; }); -//////////////////////////////////////////////////////////////// - - var file_store = new Ext.data.Store({ + //////////////////////////////////////////////////////////////// + + var file_store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ url: '/cgi-bin/bweb/bresto.pl', method: 'GET', params:{} }), - - reader: new Ext.data.ArrayReader({ - }, Ext.data.Record.create([ - {name: 'fileid' }, - {name: 'filenameid'}, - {name: 'pathid' }, - {name: 'jobid' }, - {name: 'name' }, - {name: 'size', type: 'int' }, - {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'} + + reader: new Ext.data.ArrayReader({}, + Ext.data.Record.create([ + {name: 'fileid' }, + {name: 'filenameid'}, + {name: 'pathid' }, + {name: 'jobid' }, + {name: 'name' }, + {name: 'size', type: 'int' }, + {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'} ])) - }); - - var cm = new Ext.grid.ColumnModel([{ - id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 }) - header: 'File', - dataIndex: 'name', - width: 200, - css: 'white-space:normal;' - },{ - header: "Size", - dataIndex: 'size', - renderer: human_size, - width: 50 - },{ - header: "Date", - dataIndex: 'mtime', - renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), - width: 100 - },{ - dataIndex: 'pathid', - hidden: true - },{ - dataIndex: 'filenameid', - hidden: true - },{ - dataIndex: 'fileid', - hidden: true - },{ - dataIndex: 'jobid', - hidden: true - } - ]); + }); + Ext.brestore.file_store=file_store; + var cm = new Ext.grid.ColumnModel([{ + id: 'cm-id', // id assigned so we can apply custom css + // (e.g. .x-grid-col-topic b { color:#333 }) + header: 'File', + dataIndex: 'name', + width: 200, + css: 'white-space:normal;' + },{ + header: "Size", + dataIndex: 'size', + renderer: human_size, + width: 60 + },{ + header: "Date", + dataIndex: 'mtime', + renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), + width: 100 + },{ + dataIndex: 'pathid', + hidden: true + },{ + dataIndex: 'filenameid', + hidden: true + },{ + dataIndex: 'fileid', + hidden: true + },{ + dataIndex: 'jobid', + hidden: true + }]); // by default columns are sortable - cm.defaultSortable = true; - // create the grid - var files_grid = new Ext.grid.Grid('div-files', { - ds: file_store, - cm: cm, - ddGroup : 'TreeDD', - enableDrag: true, + cm.defaultSortable = true; + + var file_grid = new Ext.grid.GridPanel({ + id: 'div-files', + store: file_store, + colModel: cm, + ddGroup: 'TreeDD', enableDragDrop: true, selModel: new Ext.grid.RowSelectionModel(), - loadMask: true, + loadMask: true, autoSizeColumns: true, - enableColLock:false - + autoShow: true, + autoHeight: true, + title: 'Directory content', + cmargins: '5 0 0 0' }); + Ext.brestore.file_grid=file_grid; +// captureEvents(file_grid); +// captureEvents(file_store); // when we reload the view, // we clear the file version box file_store.on('beforeload', function(e) { file_versions_store.removeAll(); return true; }); + + file_store.on('loadexception', function(obj, options, response, e){ + console.info('store loadexception, arguments:', arguments); + console.info('error = ', e); + }); + + file_store.on('load', function(store, records, options){ + //store is loaded, now you can work with it's records, etc. + console.info('store load, arguments:', arguments); + console.info('Store count = ', store.getCount()); + }); // TODO: selection only when using dblclick - files_grid.selModel.on('rowselect', function(e,i,r) { + file_grid.selModel.on('rowselect', function(e,i,r) { if (r.json[4] == '.') { - return true; - } + return true; + } Ext.brestore.filename = r.json[4]; - file_versions_store.load({params:init_params({action: 'list_versions', - vafv: Ext.brestore.option_vafv, - pathid: r.json[2], - filenameid: r.json[1] - }) - }); + file_versions_store.load({ + params:init_params({action: 'list_versions', + vafv: Ext.brestore.option_vafv, + pathid: r.json[2], + filenameid: r.json[1] + }) + }); return true; }); -//////////////////////////////////////////////////////////////: + //////////////////////////////////////////////////////////////// - var file_selection_store = new Ext.data.Store({ + var file_selection_store = new Ext.data.Store({ proxy: new Ext.data.MemoryProxy(), + + reader: new Ext.data.ArrayReader({}, + Ext.data.Record.create([ + {name: 'jobid' }, + {name: 'fileid' }, + {name: 'filenameid'}, + {name: 'pathid' }, + {name: 'name' }, + {name: 'size', type: 'int' }, + {name: 'mtime'}//, type: 'date', dateFormat: 'Y-m-d h:i:s'} + ])) + }); - reader: new Ext.data.ArrayReader({ - }, Ext.data.Record.create([ - {name: 'jobid' }, - {name: 'fileid' }, - {name: 'filenameid'}, - {name: 'pathid' }, - {name: 'name' }, - {name: 'size', type: 'int' }, - {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'} - ])) - }); - - var file_selection_cm = new Ext.grid.ColumnModel([{ - id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 }) - header: "Name", - dataIndex: 'name', - width: 250 + var file_selection_cm = new Ext.grid.ColumnModel([ + { + id: 'file-selection-id', + header: "Name", + dataIndex: 'name', + width: 250 },{ - header: "JobId", - width: 50, - dataIndex: 'jobid' + header: "JobId", + width: 50, + dataIndex: 'jobid' },{ - header: "Size", - dataIndex: 'size', - renderer: human_size, - width: 50 + header: "Size", + dataIndex: 'size', + renderer: human_size, + width: 50 },{ - header: "Date", - dataIndex: 'mtime', - renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), - width: 100 + header: "Date", + dataIndex: 'mtime', +// renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), + width: 100 },{ - dataIndex: 'pathid', - header: 'PathId', - hidden: true + header: 'PathId', + dataIndex: 'pathid', + hidden: true },{ - dataIndex: 'filenameid', - hidden: true + header: 'Filenameid', + dataIndex: 'filenameid', + hidden: true },{ - dataIndex: 'fileid', - header: 'FileId', - hidden: true + header: 'FileId', + dataIndex: 'fileid', + hidden: true } - ]); - + ]); // create the grid - var file_selection_grid = new Ext.grid.Grid('div-file-selection', { - cm: file_selection_cm, - ds: file_selection_store, + var file_selection_grid = new Ext.grid.GridPanel({ + colModel: file_selection_cm, + store: file_selection_store, ddGroup : 'TreeDD', - enableDrag: false, - enableDrop: true, + enableDragDrop: false, selModel: new Ext.grid.RowSelectionModel(), loadMask: true, - enableColLock:false + height: 200, +// autoHeight: true, + minSize: 75, + maxSize: 250, + cmargins: '5 0 0 0' }); var file_selection_record = Ext.data.Record.create( @@ -303,168 +336,113 @@ function ext_init() {name: 'size'}, {name: 'mtime'} ); -// data.selections[0].json[] -// data.node.id -// http://extjs.com/forum/showthread.php?t=12582&highlight=drag+drop - var ddrow = new Ext.dd.DropTarget(file_selection_grid.container, { - ddGroup : 'TreeDD', - copy:false, - notifyDrop : function(dd, e, data){ - var r; - if (data.selections) { - if (data.grid.id == 'div-files') { - for(var i=0;i 0) { - for(var i = 0, len = m.length; i < len; i++){ - file_selection_store.remove(m[i]); - } + for(var i = 0, len = m.length; i < len; i++){ + file_selection_store.remove(m[i]); + } } - } - }; - file_selection_grid.on('keypress', func1); -/////////////////////////////////////////////////////// + } + }; + file_selection_grid.on('keypress', func1); + + //////////////////////////////////////////////////////////////// - var file_versions_store = new Ext.data.Store({ + var file_versions_store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ url: '/cgi-bin/bweb/bresto.pl', method: 'GET', params:{offset:0, limit:50 } }), + + reader: new Ext.data.ArrayReader({}, + Ext.data.Record.create([ + {name: 'fileid' }, + {name: 'filenameid'}, + {name: 'pathid' }, + {name: 'jobid' }, + {name: 'volume' }, + {name: 'inchanger' }, + {name: 'md5' }, + {name: 'size', type: 'int' }, + {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'} + ])) + }); - reader: new Ext.data.ArrayReader({ - }, Ext.data.Record.create([ - {name: 'fileid' }, - {name: 'filenameid'}, - {name: 'pathid' }, - {name: 'jobid' }, - {name: 'volume' }, - {name: 'inchanger' }, - {name: 'md5' }, - {name: 'size', type: 'int' }, - {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'} - ])) - }); - - var file_versions_cm = new Ext.grid.ColumnModel([{ - id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 }) - dataIndex: 'name', - hidden: true - },{ - header: "InChanger", - dataIndex: 'inchanger', - width: 60, - renderer: rd_vol_is_online - },{ - header: "Volume", - dataIndex: 'volume' - },{ - header: "JobId", - width: 50, - dataIndex: 'jobid' - },{ - header: "Size", - dataIndex: 'size', - renderer: human_size, - width: 50 - },{ - header: "Date", - dataIndex: 'mtime', - renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), - width: 100 - },{ - header: "MD5", - dataIndex: 'md5', - width: 160 - },{ - header: "pathid", - dataIndex: 'pathid', - hidden: true - },{ - header: "filenameid", - dataIndex: 'filenameid', - hidden: true - },{ - header: "fileid", - dataIndex: 'fileid', - hidden: true - } - ]); + var file_versions_cm = new Ext.grid.ColumnModel([{ + id: 'file-version-id', + dataIndex: 'name', + hidden: true + },{ + header: "InChanger", + dataIndex: 'inchanger', + width: 60, + renderer: rd_vol_is_online + },{ + header: "Volume", + dataIndex: 'volume', + width: 128 + },{ + header: "JobId", + width: 50, + dataIndex: 'jobid' + },{ + header: "Size", + dataIndex: 'size', + renderer: human_size, + width: 50 + },{ + header: "Date", + dataIndex: 'mtime', + renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'), + width: 100 + },{ + header: "CheckSum", + dataIndex: 'md5', + width: 160 + },{ + header: "pathid", + dataIndex: 'pathid', + hidden: true + },{ + header: "filenameid", + dataIndex: 'filenameid', + hidden: true + },{ + header: "fileid", + dataIndex: 'fileid', + hidden: true + }]); // by default columns are sortable - file_versions_cm.defaultSortable = true; + file_versions_cm.defaultSortable = true; // create the grid - var file_versions_grid = new Ext.grid.Grid('div-file-versions', { - ds: file_versions_store, - cm: file_versions_cm, + var file_versions_grid = new Ext.grid.GridPanel({ + id: 'div-file-versions', + store: file_versions_store, + colModel: file_versions_cm, ddGroup : 'TreeDD', - enableDrag: true, - enableDrop: false, + enableDragDrop: true, selModel: new Ext.grid.RowSelectionModel(), loadMask: true, - enableColLock:false - + autoHeight: true, + autoScroll: true, + title: 'File version', + cmargins: '5 0 0 0' }); file_versions_grid.on('rowdblclick', function(e) { alert(e) ; file_versions_store.removeAll(); return true; }); -//////////////////////////////////////////////////////////////: + //////////////////////////////////////////////////////////////// var client_store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ @@ -472,10 +450,10 @@ function ext_init() method: 'GET', params:{action:'list_client'} }), - + reader: new Ext.data.ArrayReader({ }, Ext.data.Record.create([ - {name: 'name' } + {name: 'name' } ])) }); @@ -509,7 +487,7 @@ function ext_init() return true; }); -//////////////////////////////////////////////////////////////: + //////////////////////////////////////////////////////////////: var job_store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ @@ -527,17 +505,17 @@ function ext_init() }); var job_combo = new Ext.form.ComboBox({ - fieldLabel: 'Jobs', - store: job_store, - displayField:'jobname', - typeAhead: true, - mode: 'local', - triggerAction: 'all', - emptyText:'Select a job...', - selectOnFocus:true, - loadMask: true, - forceSelection: true, - width:350 + store: job_store, + fieldLabel: 'Jobs', + displayField: 'jobname', + mode: 'local', + triggerAction: 'all', + emptyText: 'Select a job...', + typeAhead: true, + selectOnFocus: true, + loadMask: true, + forceSelection: true, + width: 350 }); job_combo.on('select', function(e,c) { @@ -549,7 +527,12 @@ function ext_init() root.reload(); }); -//////////////////////////////////////////////////////////////// + var where_field = new Ext.form.TextField({ + fieldLabel: 'Location', + name: 'where', + width:275, + allowBlank:false + }); function sel_option(item, check) { @@ -578,95 +561,204 @@ function ext_init() }) ] }); -////////////////////////////////////////////////////////////////: - // create the primary toolbar - var tb2 = new Ext.Toolbar('div-tb-sel'); - - var where_field = new Ext.form.TextField({ - fieldLabel: 'Location', - name: 'where', - width:175, - allowBlank:false - }); + var tb = new Ext.Toolbar({ + items: [ + client_combo, + job_combo, + '-', + { + text: 'Change location', + cls:'x-btn-text-icon', + handler: function() { + var where = where_field.getValue(); + if (!where) { + Ext.MessageBox.show({ + title: 'Bad parameter', + msg: 'Location is empty!', + buttons: Ext.MessageBox.OK, + icon: Ext.MessageBox.ERROR + }); + return; + } + Ext.brestore.root_path=where; + root.setText(where); + tree_loader.baseParams = init_params({ + action:'list_dirs', path: where + }); + root.reload(); + } + }, + where_field, + { + text:'Options', + iconCls: 'bmenu', // <-- icon + menu: menu // assign menu by instance + }, + '->', // Fill + { // TODO: put this button on south panel + icon: '/bweb/mR.png', // icons can also be specified inline + cls: 'x-btn-text-icon', + tooltip: 'Run restore', + text: 'Run restore', + handler: function() { + if (!file_selection_store.data.items.length) { + Ext.MessageBox.show({ + title: 'Empty selection', + msg: 'Your object selection list is empty!', + buttons: Ext.MessageBox.OK, + icon: Ext.MessageBox.ERROR + }); + } else { + display_run_job(); + } + } + }]}); + tb.render('tb-div'); - var tb = new Ext.Toolbar('div-toolbar', [ - client_combo, - job_combo, - '-', - { - id: 'tb_home', -// icon: '/bweb/up.gif', - text: 'Change location', - cls:'x-btn-text-icon', - handler: function() { - var where = where_field.getValue(); - Ext.brestore.root_path=where; - root.setText(where); - tree_loader.baseParams = init_params({ action:'list_dirs', path: where }); - root.reload(); - } - }, - where_field, - '-', - { - cls: 'x-btn-text-icon bmenu', // icon and text class - text:'Options', - menu: menu // assign menu by instance + //////////////////////////////////////////////////////////////// + + // Define Main interface + var MainView = new Ext.Viewport({ + id:'mainview-panel', + title: 'Bacula Web Restore', + layout:'border', + bodyBorder: false, + renderTo: Ext.getBody(), + defaults: { + collapsible: false, + split: true, + animFloat: false, + autoHide: false, + autoScroll: true, + useSplitTips: true }, - { - icon: '/bweb/mR.png', // icons can also be specified inline - cls: 'x-btn-icon', - title: 'restore', - handler: function() { - if (Ext.brestore.dlglaunch) { - Ext.brestore.dlglaunch.show(); - return 0; + tbar: tb, + items: [ + { + title: 'Directories', + region: 'west', + width: 250, + minSize: 100, + items: tree + }, { + title: 'Directory content', + region: 'center', + minSize: 100, + items: file_grid + }, { + title: 'File version', + region: 'east', + width: 550, + minSize: 100, + items: file_versions_grid + + }, { + title: 'Restore selection', + region: 'south', + height: 200, + autoScroll: false, + items: file_selection_grid + } + ]}); + client_store.load({params:{action: 'list_client'}}); + + // data.selections[0].json[] + // data.node.id + // http://extjs.com/forum/showthread.php?t=12582&highlight=drag+drop + + var horror_show1 = file_selection_grid.getView().el.dom; + var ddrow = new Ext.dd.DropTarget(horror_show1, { + ddGroup : 'TreeDD', + copy:false, + notifyDrop : function(dd, e, data){ + var r; + if (data.selections) { + if (data.grid.id == 'div-files') { + for(var i=0;i