2 // Bweb - A Bacula web interface
3 // Bacula® - The Network Backup Solution
5 // Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
7 // The main author of Bweb is Eric Bollengier.
8 // The main author of Bacula is Kern Sibbald, with contributions from
9 // many others, a complete list can be found in the file AUTHORS.
11 // This program is Free Software; you can redistribute it and/or
12 // modify it under the terms of version two of the GNU General Public
13 // License as published by the Free Software Foundation plus additions
14 // that are listed in the file LICENSE.
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 // Bacula® is a registered trademark of John Walker.
27 // The licensor of Bacula is the Free Software Foundation Europe
28 // (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
29 // Switzerland, email:ftf@fsfeurope.org.
31 // render if vol is online/offline
32 function rd_vol_is_online(val)
34 return '<img src="/bweb/inflag' + val + '.png">';
37 // TODO: fichier ou rep
38 function rd_file_or_dir(val)
41 return '<img src="/bweb/A.png">';
43 return '<img src="/bweb/R.png">';
47 Ext.namespace('Ext.brestore');
49 Ext.brestore.jobid=0; // selected jobid
50 Ext.brestore.jobdate=''; // selected date
51 Ext.brestore.client=''; // selected client
52 Ext.brestore.rclient=''; // selected client for resto
53 Ext.brestore.storage=''; // selected storage for resto
54 Ext.brestore.path=''; // current path (without user location)
55 Ext.brestore.root_path=''; // user location
57 Ext.brestore.option_vosb = false;
58 Ext.brestore.option_vafv = false;
59 Ext.brestore.dlglaunch;
60 Ext.BLANK_IMAGE_URL = '/bweb/ext/resources/images/aero/s.gif'; // 1.1
62 function get_node_path(node)
65 for (var p = node; p; p = p.parentNode) {
70 temp = p.text + '/' + temp;
74 return Ext.brestore.root_path + temp;
78 function init_params(baseParams)
80 baseParams['client']= Ext.brestore.client;
82 if (Ext.brestore.option_vosb) {
83 baseParams['jobid'] = Ext.brestore.jobid;
85 baseParams['date'] = Ext.brestore.jobdate;
93 //////////////////////////////////////////////////////////////:
95 var tree_loader = new Ext.tree.TreeLoader({
97 dataUrl:'/cgi-bin/bweb/bresto.pl'
100 var tree = new Ext.tree.TreePanel('div-tree', {
104 enableDragDrop: true,
105 containerScroll: true
109 var root = new Ext.tree.AsyncTreeNode({
110 text: 'Select a client then a job',
114 tree.setRootNode(root);
115 Ext.brestore.tree = root;
121 tree.on('click', function(node, event) {
122 Ext.brestore.path = get_node_path(node);
123 where_field.setValue(Ext.brestore.path);
124 file_store.removeAll();
125 file_versions_store.removeAll();
126 file_store.load({params:init_params({action: 'list_files',
127 path:Ext.brestore.path,
133 tree.on('beforeload', function(e) {
134 file_store.removeAll();
139 ////////////////////////////////////////////////////////////////
141 var file_store = new Ext.data.Store({
142 proxy: new Ext.data.HttpProxy({
143 url: '/cgi-bin/bweb/bresto.pl',
148 reader: new Ext.data.ArrayReader({
149 }, Ext.data.Record.create([
151 {name: 'filenameid'},
155 {name: 'size', type: 'int' },
156 {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
160 var cm = new Ext.grid.ColumnModel([{
161 id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
165 css: 'white-space:normal;'
169 renderer: human_size,
174 renderer: Ext.util.Format.dateRenderer('Y-d-m h:i:s'),
180 dataIndex: 'filenameid',
191 // by default columns are sortable
192 cm.defaultSortable = true;
194 var files_grid = new Ext.grid.Grid('div-files', {
199 enableDragDrop: true,
200 selModel: new Ext.grid.RowSelectionModel(),
202 autoSizeColumns: true,
206 // when we reload the view,
207 // we clear the file version box
208 file_store.on('beforeload', function(e) {
209 file_versions_store.removeAll();
213 // TODO: selection only when using dblclick
214 files_grid.selModel.on('rowselect', function(e,i,r) {
215 Ext.brestore.filename = r.json[4];
216 file_versions_store.load({params:init_params({action: 'list_versions',
217 vafv: Ext.brestore.option_vafv,
219 filenameid: r.json[1]
225 //////////////////////////////////////////////////////////////:
227 var file_selection_store = new Ext.data.Store({
228 proxy: new Ext.data.MemoryProxy(),
230 reader: new Ext.data.ArrayReader({
231 }, Ext.data.Record.create([
234 {name: 'filenameid'},
237 {name: 'size', type: 'int' },
238 {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
242 var file_selection_cm = new Ext.grid.ColumnModel([{
243 id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
254 renderer: human_size,
259 renderer: Ext.util.Format.dateRenderer('Y-d-m h:i'),
266 dataIndex: 'filenameid',
277 var file_selection_grid = new Ext.grid.Grid('div-file-selection', {
278 cm: file_selection_cm,
279 ds: file_selection_store,
283 selModel: new Ext.grid.RowSelectionModel(),
288 var file_selection_record = Ext.data.Record.create(
291 {name: 'filenameid'},
296 // data.selections[0].json[]
298 // http://extjs.com/forum/showthread.php?t=12582&highlight=drag+drop
299 var ddrow = new Ext.dd.DropTarget(file_selection_grid.container, {
302 notifyDrop : function(dd, e, data){
304 if (data.selections) {
305 if (data.grid.id == 'div-files') {
306 for(var i=0;i<data.selections.length;i++) {
307 r = new file_selection_record({
308 jobid: data.selections[0].json[3],
309 fileid: data.selections[i].json[0],
310 filenameid:data.selections[i].json[1],
311 pathid: data.selections[i].json[2],
312 name: Ext.brestore.path + data.selections[i].json[4],
313 size: data.selections[i].json[5],
314 mtime: data.selections[i].json[6]
316 file_selection_store.add(r)
320 if (data.grid.id == 'div-file-versions') {
321 r = new file_selection_record({
322 jobid: data.selections[0].json[3],
323 fileid: data.selections[0].json[0],
324 filenameid:data.selections[0].json[1],
325 pathid: data.selections[0].json[2],
326 name: Ext.brestore.path + Ext.brestore.filename,
327 size: data.selections[0].json[7],
328 mtime: data.selections[0].json[8]
330 file_selection_store.add(r)
335 var path= get_node_path(data.node);
336 r = new file_selection_record({
337 jobid: data.node.attributes.jobid,
340 pathid: data.node.id,
345 file_selection_store.add(r)
351 file_selection_grid.on('enddrag', function(dd,e) {
352 alert(e) ; return true;
354 file_selection_grid.on('notifyDrop', function(dd,e) {
355 alert(e) ; return true;
358 ///////////////////////////////////////////////////////
360 var file_versions_store = new Ext.data.Store({
361 proxy: new Ext.data.HttpProxy({
362 url: '/cgi-bin/bweb/bresto.pl',
364 params:{offset:0, limit:50 }
367 reader: new Ext.data.ArrayReader({
368 }, Ext.data.Record.create([
370 {name: 'filenameid'},
374 {name: 'inchanger' },
376 {name: 'size', type: 'int' },
377 {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
381 var file_versions_cm = new Ext.grid.ColumnModel([{
382 id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
387 dataIndex: 'inchanger',
389 renderer: rd_vol_is_online
400 renderer: human_size,
405 renderer: Ext.util.Format.dateRenderer('Y-d-m h:i:s'),
416 header: "filenameid",
417 dataIndex: 'filenameid',
426 // by default columns are sortable
427 file_versions_cm.defaultSortable = true;
430 var file_versions_grid = new Ext.grid.Grid('div-file-versions', {
431 ds: file_versions_store,
432 cm: file_versions_cm,
436 selModel: new Ext.grid.RowSelectionModel(),
442 file_versions_grid.on('rowdblclick', function(e) {
443 alert(e) ; file_versions_store.removeAll(); return true;
446 //////////////////////////////////////////////////////////////:
449 var client_store = new Ext.data.Store({
450 proxy: new Ext.data.HttpProxy({
451 url: '/cgi-bin/bweb/bresto.pl',
453 params:{action:'list_client'}
456 reader: new Ext.data.ArrayReader({
457 }, Ext.data.Record.create([
462 var client_combo = new Ext.form.ComboBox({
463 fieldLabel: 'Clients',
468 triggerAction: 'all',
469 emptyText:'Select a client...',
471 forceSelection: true,
475 client_combo.on('valid', function(e) {
476 Ext.brestore.client = e.getValue();
477 Ext.brestore.jobid=0;
478 Ext.brestore.jobdate = '';
479 Ext.brestore.root_path='';
480 job_combo.clearValue();
481 file_store.removeAll();
482 file_versions_store.removeAll();
483 root.collapse(false, false);
484 while(root.firstChild){
485 root.removeChild(root.firstChild);
487 job_store.load( {params:{action: 'list_job',
488 client:Ext.brestore.client}});
492 //////////////////////////////////////////////////////////////:
494 var job_store = new Ext.data.Store({
495 proxy: new Ext.data.HttpProxy({
496 url: '/cgi-bin/bweb/bresto.pl',
498 params:{offset:0, limit:50 }
501 reader: new Ext.data.ArrayReader({
502 }, Ext.data.Record.create([
509 var job_combo = new Ext.form.ComboBox({
512 displayField:'jobname',
515 triggerAction: 'all',
516 emptyText:'Select a job...',
518 forceSelection: true,
522 job_combo.on('select', function(e,c) {
523 Ext.brestore.jobid = c.json[0];
524 Ext.brestore.jobdate = c.json[1];
525 Ext.brestore.root_path='';
526 root.setText("Root");
527 tree_loader.baseParams = init_params({init:1, action: 'list_dirs'});
531 ////////////////////////////////////////////////////////////////
533 function sel_option(item, check)
535 if (item.id == 'id_vosb') {
536 Ext.brestore.option_vosb = check;
538 if (item.id == 'id_vafv') {
539 Ext.brestore.option_vafv = check;
543 var menu = new Ext.menu.Menu({
546 new Ext.menu.CheckItem({
548 text: 'View only selected backup',
549 checked: Ext.brestore.option_vosb,
550 checkHandler: sel_option
552 new Ext.menu.CheckItem({
554 text: 'View all file versions',
555 checked: Ext.brestore.option_vafv,
556 checkHandler: sel_option
560 ////////////////////////////////////////////////////////////////:
562 // create the primary toolbar
563 var tb2 = new Ext.Toolbar('div-tb-sel');
565 var where_field = new Ext.form.TextField({
566 fieldLabel: 'Location',
572 var tb = new Ext.Toolbar('div-toolbar', [
578 // icon: '/bweb/up.gif',
579 text: 'Change location',
580 cls:'x-btn-text-icon',
581 handler: function() {
582 var where = where_field.getValue();
583 Ext.brestore.root_path=where;
585 tree_loader.baseParams = init_params({ action:'list_dirs', path: where });
592 cls: 'x-btn-text-icon bmenu', // icon and text class
594 menu: menu // assign menu by instance
597 icon: '/bweb/mR.png', // icons can also be specified inline
600 handler: function() {
601 if (Ext.brestore.dlglaunch) {
602 Ext.brestore.dlglaunch.show();
605 Ext.brestore.dlglaunch = new Ext.LayoutDialog("div-resto-dlg", {
619 // collapsible: true,
624 // tabPosition: 'top',
626 // alwaysShowTabs: true
630 var fs = new Ext.form.Form({
635 // var resto_store = new Ext.data.Store({
636 // proxy: new Ext.data.HttpProxy({
637 // url: '/cgi-bin/bweb/bresto.pl',
639 // params:{action:'list_resto'}
642 // reader: new Ext.data.ArrayReader({
643 // }, Ext.data.Record.create([
648 var rclient_combo = new Ext.form.ComboBox({
649 value: Ext.brestore.client,
650 fieldLabel: 'client',
656 triggerAction: 'all',
657 emptyText:'Select a client...',
661 var where_text = new Ext.form.TextField({
664 value: '/tmp/bacula-restore',
667 var storage_store = new Ext.data.Store({
668 proxy: new Ext.data.HttpProxy({
669 url: '/cgi-bin/bweb/bresto.pl',
671 params:{action:'list_storage'}
674 reader: new Ext.data.ArrayReader({
675 }, Ext.data.Record.create([
679 var storage_combo = new Ext.form.ComboBox({
680 fieldLabel: 'storage',
681 hiddenName:'storage',
682 store: storage_store,
686 triggerAction: 'all',
687 emptyText:'Select a storage...',
691 ////////////////////////////////////////////////////////////////
692 var media_store = new Ext.data.Store({
693 proxy: new Ext.data.HttpProxy({
694 url: '/cgi-bin/bweb/bresto.pl',
696 params:{offset:0, limit:50 }
699 reader: new Ext.data.ArrayReader({
700 }, Ext.data.Record.create([
701 {name: 'volumename'},
707 var media_cm = new Ext.grid.ColumnModel([{
709 dataIndex: 'inchanger',
711 renderer: rd_vol_is_online
715 dataIndex: 'volumename',
721 var media_grid = new Ext.grid.Grid('div-media', {
733 var items = file_selection_store.data.items;
734 var tab_fileid=new Array();
735 var tab_jobid=new Array();
736 for(var i=0;i<items.length;i++) {
737 if (items[i].data['fileid']) {
738 tab_fileid.push(items[i].data['fileid']);
740 tab_jobid.push(items[i].data['jobid']);
742 var res = tab_fileid.join(",");
743 var res2 = tab_jobid.join(",");
745 media_store.baseParams = init_params({action: 'get_media', jobid: res2, fileid: res});
746 media_store.reload();
748 ////////////////////////////////////////////////////////////////
750 {legend:'Media needed'},
754 {legend:'Restore job'},
755 new Ext.form.ComboBox({
756 fieldLabel: 'Replace',
757 hiddenName:'replace',
758 store: new Ext.data.SimpleStore({
760 data : [['always'],['never'],['if newer']]
762 displayField:'replace',
765 triggerAction: 'all',
771 // new Ext.form.ComboBox({
772 // fieldLabel: 'job',
774 // store: resto_store,
775 // displayField:'name',
778 // triggerAction: 'all',
779 // emptyText:'Select a job...',
780 // selectOnFocus:true,
788 storage_store.load({params:{action: 'list_storage'}});
789 // resto_store.load({params:{action: 'list_resto'}});
790 fs.render('div-resto-form');
792 // var f = new Ext.form.BasicForm('div-resto-form', {url: '/bweb/test', method: 'GET',
793 // baseParams: {init: 1}
797 var launch_restore = function() {
798 var items = file_selection_store.data.items;
799 var tab_fileid=new Array();
800 var tab_dirid=new Array();
801 var tab_jobid=new Array();
802 for(var i=0;i<items.length;i++) {
803 if (items[i].data['fileid']) {
804 tab_fileid.push(items[i].data['fileid']);
806 tab_dirid.push(items[i].data['pathid']);
808 tab_jobid.push(items[i].data['jobid']);
810 var res = ';fileid=' + tab_fileid.join(";fileid=");
811 var res2 = ';dirid=' + tab_dirid.join(";dirid=");
812 var res3 = ';jobid=' + tab_jobid.join(";jobid=");
814 var res4 = ';client=' + rclient_combo.getValue() + ';storage=' + storage_combo.getValue() + ';where=' + where_text.getValue();
816 window.location='/cgi-bin/bweb/bresto.pl?action=restore' + res + res2 + res3 + res4;
817 } // end launch_restore
819 var dialog = Ext.brestore.dlglaunch;
820 dialog.addKeyListener(27, dialog.hide, dialog);
821 dialog.addButton('Submit', launch_restore);
822 dialog.addButton('Close', dialog.hide, dialog);
824 var layout = dialog.getLayout();
825 layout.beginUpdate();
826 layout.add('center', new Ext.ContentPanel('div-resto-form', {
827 autoCreate:true, title: 'Third Tab', closable:true, background:true}));
835 ////////////////////////////////////////////////////////////////
837 var layout = new Ext.BorderLayout(document.body, {
842 split: true, initialSize: 300
845 split: true, initialSize: 550
848 split: true, initialSize: 300
856 layout.beginUpdate();
857 layout.add('north', new Ext.ContentPanel('div-toolbar', {
858 fitToFrame: true, autoCreate:true,closable: false
860 layout.add('south', new Ext.ContentPanel('div-file-selection', {
861 toolbar: tb2,resizeEl:'div-file-selection',
862 fitToFrame: true, autoCreate:true,closable: false
864 layout.add('east', new Ext.ContentPanel('div-file-versions', {
865 fitToFrame: true, autoCreate:true,closable: false
867 layout.add('west', new Ext.ContentPanel('div-tree', {
868 autoScroll:true, fitToFrame: true,
869 autoCreate:true,closable: false
871 layout.add('center', new Ext.ContentPanel('div-files', {
872 autoScroll:true,autoCreate:true,fitToFrame: true
877 ////////////////////////////////////////////////////////////////
880 client_store.load({params:{action: 'list_client'}});
881 // file_store.load({params:{offset:0, limit:50}});
882 // file_versions_store.load({params:{offset:0, limit:50}});
883 // file_selection_store.load();
885 file_selection_grid.render();
886 file_versions_grid.render();
889 Ext.onReady( ext_init );