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',
132 tree.on('beforeload', function(e) {
133 file_store.removeAll();
138 ////////////////////////////////////////////////////////////////
140 var file_store = new Ext.data.Store({
141 proxy: new Ext.data.HttpProxy({
142 url: '/cgi-bin/bweb/bresto.pl',
147 reader: new Ext.data.ArrayReader({
148 }, Ext.data.Record.create([
150 {name: 'filenameid'},
154 {name: 'size', type: 'int' },
155 {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
159 var cm = new Ext.grid.ColumnModel([{
160 id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
164 css: 'white-space:normal;'
168 renderer: human_size,
173 renderer: Ext.util.Format.dateRenderer('Y-d-m h:i:s'),
179 dataIndex: 'filenameid',
190 // by default columns are sortable
191 cm.defaultSortable = true;
193 var files_grid = new Ext.grid.Grid('div-files', {
198 enableDragDrop: true,
199 selModel: new Ext.grid.RowSelectionModel(),
201 autoSizeColumns: true,
205 // when we reload the view,
206 // we clear the file version box
207 file_store.on('beforeload', function(e) {
208 file_versions_store.removeAll();
212 // TODO: selection only when using dblclick
213 files_grid.selModel.on('rowselect', function(e,i,r) {
214 Ext.brestore.filename = r.json[4];
215 file_versions_store.load({params:init_params({action: 'list_versions',
216 vafv: Ext.brestore.option_vafv,
218 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;
357 file_selection_grid.render();
359 ///////////////////////////////////////////////////////
361 var file_versions_store = new Ext.data.Store({
362 proxy: new Ext.data.HttpProxy({
363 url: '/cgi-bin/bweb/bresto.pl',
365 params:{offset:0, limit:50 }
368 reader: new Ext.data.ArrayReader({
369 }, Ext.data.Record.create([
371 {name: 'filenameid'},
375 {name: 'inchanger' },
377 {name: 'size', type: 'int' },
378 {name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
382 var file_versions_cm = new Ext.grid.ColumnModel([{
383 id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
388 dataIndex: 'inchanger',
390 renderer: rd_vol_is_online
401 renderer: human_size,
406 renderer: Ext.util.Format.dateRenderer('Y-d-m h:i:s'),
417 header: "filenameid",
418 dataIndex: 'filenameid',
427 // by default columns are sortable
428 file_versions_cm.defaultSortable = true;
431 var file_versions_grid = new Ext.grid.Grid('div-file-versions', {
432 ds: file_versions_store,
433 cm: file_versions_cm,
437 selModel: new Ext.grid.RowSelectionModel(),
443 file_versions_grid.on('rowdblclick', function(e) {
444 alert(e) ; file_versions_store.removeAll(); return true;
446 file_versions_grid.render();
448 //////////////////////////////////////////////////////////////:
451 var client_store = new Ext.data.Store({
452 proxy: new Ext.data.HttpProxy({
453 url: '/cgi-bin/bweb/bresto.pl',
455 params:{action:'list_client'}
458 reader: new Ext.data.ArrayReader({
459 }, Ext.data.Record.create([
464 var client_combo = new Ext.form.ComboBox({
465 fieldLabel: 'Clients',
470 triggerAction: 'all',
471 emptyText:'Select a client...',
473 forceSelection: true,
477 client_combo.on('valid', function(e) {
478 Ext.brestore.client = e.getValue();
479 Ext.brestore.jobid=0;
480 Ext.brestore.jobdate = '';
481 Ext.brestore.root_path='';
482 job_combo.clearValue();
483 file_store.removeAll();
484 file_versions_store.removeAll();
485 root.collapse(false, false);
486 while(root.firstChild){
487 root.removeChild(root.firstChild);
489 job_store.load( {params:{action: 'list_job',
490 client:Ext.brestore.client}});
494 //////////////////////////////////////////////////////////////:
496 var job_store = new Ext.data.Store({
497 proxy: new Ext.data.HttpProxy({
498 url: '/cgi-bin/bweb/bresto.pl',
500 params:{offset:0, limit:50 }
503 reader: new Ext.data.ArrayReader({
504 }, Ext.data.Record.create([
511 var job_combo = new Ext.form.ComboBox({
514 displayField:'jobname',
517 triggerAction: 'all',
518 emptyText:'Select a job...',
520 forceSelection: true,
524 job_combo.on('select', function(e,c) {
525 Ext.brestore.jobid = c.json[0];
526 Ext.brestore.jobdate = c.json[1];
527 Ext.brestore.root_path='';
528 root.setText("Root");
529 tree_loader.baseParams = init_params({init:1, action: 'list_dirs'});
533 ////////////////////////////////////////////////////////////////
535 function sel_option(item, check)
537 if (item.id == 'id_vosb') {
538 Ext.brestore.option_vosb = check;
540 if (item.id == 'id_vafv') {
541 Ext.brestore.option_vafv = check;
545 var menu = new Ext.menu.Menu({
548 new Ext.menu.CheckItem({
550 text: 'View only selected backup',
551 checked: Ext.brestore.option_vosb,
552 checkHandler: sel_option
554 new Ext.menu.CheckItem({
556 text: 'View all file versions',
557 checked: Ext.brestore.option_vafv,
558 checkHandler: sel_option
562 ////////////////////////////////////////////////////////////////:
564 // create the primary toolbar
565 var tb2 = new Ext.Toolbar('div-tb-sel');
567 var where_field = new Ext.form.TextField({
568 fieldLabel: 'Location',
574 var tb = new Ext.Toolbar('div-toolbar', [
580 // icon: '/bweb/up.gif',
581 text: 'Change location',
582 cls:'x-btn-text-icon',
583 handler: function() {
584 var where = where_field.getValue();
585 Ext.brestore.root_path=where;
587 tree_loader.baseParams = init_params({ action:'list_dirs', path: where });
594 cls: 'x-btn-text-icon bmenu', // icon and text class
596 menu: menu // assign menu by instance
599 icon: '/bweb/mR.png', // icons can also be specified inline
602 handler: function() {
603 if (Ext.brestore.dlglaunch) {
604 Ext.brestore.dlglaunch.show();
607 Ext.brestore.dlglaunch = new Ext.LayoutDialog("div-resto-dlg", {
621 // collapsible: true,
626 // tabPosition: 'top',
628 // alwaysShowTabs: true
632 var fs = new Ext.form.Form({
637 // var resto_store = new Ext.data.Store({
638 // proxy: new Ext.data.HttpProxy({
639 // url: '/cgi-bin/bweb/bresto.pl',
641 // params:{action:'list_resto'}
644 // reader: new Ext.data.ArrayReader({
645 // }, Ext.data.Record.create([
650 var rclient_combo = new Ext.form.ComboBox({
651 value: Ext.brestore.client,
652 fieldLabel: 'client',
658 triggerAction: 'all',
659 emptyText:'Select a client...',
663 var where_text = new Ext.form.TextField({
666 value: '/tmp/bacula-restore',
669 var storage_store = new Ext.data.Store({
670 proxy: new Ext.data.HttpProxy({
671 url: '/cgi-bin/bweb/bresto.pl',
673 params:{action:'list_storage'}
676 reader: new Ext.data.ArrayReader({
677 }, Ext.data.Record.create([
681 var storage_combo = new Ext.form.ComboBox({
682 fieldLabel: 'storage',
683 hiddenName:'storage',
684 store: storage_store,
688 triggerAction: 'all',
689 emptyText:'Select a storage...',
693 ////////////////////////////////////////////////////////////////
694 var media_store = new Ext.data.Store({
695 proxy: new Ext.data.HttpProxy({
696 url: '/cgi-bin/bweb/bresto.pl',
698 params:{offset:0, limit:50 }
701 reader: new Ext.data.ArrayReader({
702 }, Ext.data.Record.create([
703 {name: 'volumename'},
709 var media_cm = new Ext.grid.ColumnModel([{
711 dataIndex: 'inchanger',
713 renderer: rd_vol_is_online
717 dataIndex: 'volumename',
723 var media_grid = new Ext.grid.Grid('div-media', {
735 var items = file_selection_store.data.items;
736 var tab_fileid=new Array();
737 var tab_jobid=new Array();
738 for(var i=0;i<items.length;i++) {
739 if (items[i].data['fileid']) {
740 tab_fileid.push(items[i].data['fileid']);
742 tab_jobid.push(items[i].data['jobid']);
744 var res = tab_fileid.join(",");
745 var res2 = tab_jobid.join(",");
747 media_store.baseParams = init_params({action: 'get_media', jobid: res2, fileid: res});
748 media_store.reload();
750 ////////////////////////////////////////////////////////////////
752 {legend:'Media needed'},
756 {legend:'Restore job'},
757 new Ext.form.ComboBox({
758 fieldLabel: 'Replace',
759 hiddenName:'replace',
760 store: new Ext.data.SimpleStore({
762 data : [['always'],['never'],['if newer']]
764 displayField:'replace',
767 triggerAction: 'all',
773 // new Ext.form.ComboBox({
774 // fieldLabel: 'job',
776 // store: resto_store,
777 // displayField:'name',
780 // triggerAction: 'all',
781 // emptyText:'Select a job...',
782 // selectOnFocus:true,
790 storage_store.load({params:{action: 'list_storage'}});
791 // resto_store.load({params:{action: 'list_resto'}});
792 fs.render('div-resto-form');
794 // var f = new Ext.form.BasicForm('div-resto-form', {url: '/bweb/test', method: 'GET',
795 // baseParams: {init: 1}
799 var launch_restore = function() {
800 var items = file_selection_store.data.items;
801 var tab_fileid=new Array();
802 var tab_dirid=new Array();
803 var tab_jobid=new Array();
804 for(var i=0;i<items.length;i++) {
805 if (items[i].data['fileid']) {
806 tab_fileid.push(items[i].data['fileid']);
808 tab_dirid.push(items[i].data['pathid']);
810 tab_jobid.push(items[i].data['jobid']);
812 var res = ';fileid=' + tab_fileid.join(";fileid=");
813 var res2 = ';dirid=' + tab_dirid.join(";dirid=");
814 var res3 = ';jobid=' + tab_jobid.join(";jobid=");
816 var res4 = ';client=' + rclient_combo.getValue() + ';storage=' + storage_combo.getValue() + ';where=' + where_text.getValue();
818 window.location='/cgi-bin/bweb/bresto.pl?action=restore' + res + res2 + res3 + res4;
819 } // end launch_restore
821 var dialog = Ext.brestore.dlglaunch;
822 dialog.addKeyListener(27, dialog.hide, dialog);
823 dialog.addButton('Submit', launch_restore);
824 dialog.addButton('Close', dialog.hide, dialog);
826 var layout = dialog.getLayout();
827 layout.beginUpdate();
828 layout.add('center', new Ext.ContentPanel('div-resto-form', {
829 autoCreate:true, title: 'Third Tab', closable:true, background:true}));
837 ////////////////////////////////////////////////////////////////
839 var layout = new Ext.BorderLayout(document.body, {
844 split: true, initialSize: 300
847 split: true, initialSize: 550
850 split: true, initialSize: 300
858 layout.beginUpdate();
859 layout.add('north', new Ext.ContentPanel('div-toolbar', {
860 fitToFrame: true, autoCreate:true,closable: false
862 layout.add('south', new Ext.ContentPanel('div-file-selection', {
863 toolbar: tb2,resizeEl:'div-file-selection',
864 fitToFrame: true, autoCreate:true,closable: false
866 layout.add('east', new Ext.ContentPanel('div-file-versions', {
867 fitToFrame: true, autoCreate:true,closable: false
869 layout.add('west', new Ext.ContentPanel('div-tree', {
870 autoScroll:true, fitToFrame: true,
871 autoCreate:true,closable: false
873 layout.add('center', new Ext.ContentPanel('div-files', {
874 autoScroll:true,autoCreate:true,fitToFrame: true
879 ////////////////////////////////////////////////////////////////
882 client_store.load({params:{action: 'list_client'}});
883 // file_store.load({params:{offset:0, limit:50}});
884 // file_versions_store.load({params:{offset:0, limit:50}});
885 // file_selection_store.load();
888 Ext.onReady( ext_init );