]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/html/bresto.js
bweb: update location title
[bacula/bacula] / gui / bweb / html / bresto.js
1 //   Bweb - A Bacula web interface
2 //   Bacula® - The Network Backup Solution
3 //
4 //   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5 //
6 //   The main author of Bweb is Eric Bollengier.
7 //   The main author of Bacula is Kern Sibbald, with contributions from
8 //   many others, a complete list can be found in the file AUTHORS.
9 //
10 //   This program is Free Software; you can redistribute it and/or
11 //   modify it under the terms of version two of the GNU General Public
12 //   License as published by the Free Software Foundation plus additions
13 //   that are listed in the file LICENSE.
14 //
15 //   This program is distributed in the hope that it will be useful, but
16 //   WITHOUT ANY WARRANTY; without even the implied warranty of
17 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 //   General Public License for more details.
19 //
20 //   You should have received a copy of the GNU General Public License
21 //   along with this program; if not, write to the Free Software
22 //   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 //   02110-1301, USA.
24 //
25 //   Bacula® is a registered trademark of Kern Sibbald.
26 //   The licensor of Bacula is the Free Software Foundation Europe
27 //   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
28 //   Switzerland, email:ftf@fsfeurope.org.
29
30 // render if vol is online/offline
31 function rd_vol_is_online(val)
32 {
33    return '<img src="inflag' + val + '.png">';
34 }
35
36 // TODO: fichier ou rep
37 function rd_file_or_dir(val)
38 {
39    if (val > 0) {
40       return '<img src="file_f.png">';
41    } else {
42       return '<img src="file_d.png">';
43    }
44 }
45
46 function push_path()
47 {
48     Ext.brestore.path_stack.push(Ext.brestore.path);
49     Ext.brestore.pathid_stack.push(Ext.brestore.pathid);
50     Ext.ComponentMgr.get('prevbp').enable();
51 }
52 function pop_path()
53 {
54     var pathid = Ext.brestore.pathid_stack.pop();
55     var path = Ext.brestore.path_stack.pop();
56     if (!pathid) {
57         Ext.ComponentMgr.get('prevbp').disable();
58         return false;
59     }
60     Ext.ComponentMgr.get('wherefield').setValue(path);
61
62     Ext.brestore.pathid = pathid;
63     Ext.brestore.path = path;
64     return true;
65 }
66
67 function dirname(path) {
68     var a = path.match( /(^.*\/).+\// );
69     if (a) {
70         return a[1];
71     }
72     return path;
73 }
74
75 Ext.namespace('Ext.brestore');
76 Ext.brestore.jobid=0;            // selected jobid
77 Ext.brestore.jobdate='';         // selected date
78 Ext.brestore.client='';          // selected client
79 Ext.brestore.rclient='';         // selected client for resto
80 Ext.brestore.storage='';         // selected storage for resto
81 Ext.brestore.path='';            // current path (without user location)
82 Ext.brestore.pathid=0;           // current pathid
83 Ext.brestore.root_path='';       // user location
84 Ext.brestore.media_store;        // media store 
85 Ext.brestore.option_vosb = false;
86 Ext.brestore.option_vafv = false;
87 Ext.brestore.option_vcopies = false;
88 Ext.brestore.dlglaunch;
89 Ext.brestore.fpattern;
90 Ext.brestore.use_filerelocation=false;
91 Ext.brestore.limit = 500;
92 Ext.brestore.offset = 0;
93 Ext.brestore.force_reload = 0;
94 Ext.brestore.path_stack = Array();
95 Ext.brestore.pathid_stack = Array();
96
97 function get_node_path(node)
98 {
99    var temp='';
100    for (var p = node; p; p = p.parentNode) {
101        if (p.parentNode) {
102           if (p.text == '/') {
103              temp = p.text + temp;
104           } else {
105           temp = p.text + '/' + temp;
106           }
107        }
108    }
109    return Ext.brestore.root_path + temp;
110 }
111
112 function init_params(baseParams)
113 {
114     baseParams['client']= Ext.brestore.client;
115     
116     if (Ext.brestore.option_vosb) {         
117         baseParams['jobid'] = Ext.brestore.jobid;
118     } else {
119         baseParams['date'] = Ext.brestore.jobdate;
120     }
121     baseParams['offset'] = Ext.brestore.offset;
122     baseParams['limit'] = Ext.brestore.limit;
123     if (Ext.brestore.fpattern) {
124         if (RegExp(Ext.brestore.fpattern)) {
125             baseParams['pattern'] = Ext.brestore.fpattern;
126         }
127     }
128     return baseParams;
129 }
130
131 function captureEvents(observable) {
132     Ext.util.Observable.capture(
133         observable,
134         function(eventName) {
135             console.info(eventName);
136         },
137         this
138     );          
139 }
140
141 ////////////////////////////////////////////////////////////////
142
143 Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif';
144 Ext.onReady(function(){
145     if (!Ext.version || Ext.version < 2.2) {
146         alert("You must upgrade your extjs version to 2.2");
147         return;
148     }
149
150     Ext.QuickTips.init();
151
152     // Init tree for directory selection
153     var tree_loader = new Ext.tree.TreeLoader({
154             baseParams:{}, 
155             dataUrl:'/cgi-bin/bweb/bresto.pl'
156         });
157
158     var tree = new Ext.tree.TreePanel({
159         animate:true, 
160         loader: tree_loader,
161         enableDD:true,
162         enableDragDrop: true,
163         containerScroll: true,
164         title: 'Directories',
165         minSize: 100      
166     });
167
168     // set the root node
169     var root = new Ext.tree.AsyncTreeNode({
170         text: 'Select a client then a job',
171         draggable:false,
172         id:'source'
173     });
174     tree.setRootNode(root);
175     Ext.brestore.tree = root;   // shortcut
176
177     var click_cb = function(node, event) { 
178         push_path();
179
180         Ext.brestore.path = get_node_path(node);
181         Ext.brestore.pathid = node.id;
182         Ext.brestore.offset=0;
183         Ext.brestore.fpattern = Ext.get('txt-file-pattern').getValue();
184         where_field.setValue(Ext.brestore.path);
185         update_limits();       
186         file_store.load({params:init_params({action: 'list_files_dirs',
187                                              path:Ext.brestore.path,
188                                              node:node.id})
189                         });
190         return true;
191     };
192  
193     tree.on('click', click_cb);
194
195     tree.on('beforeload', function(e,b) {
196 //      console.info(b);
197 //      file_store.removeAll();
198         return true;
199     });
200     tree.on('load', function(n,e) {
201         if (!n.firstChild) {
202            click_cb(n, e);
203         }
204         return true;
205     });
206
207     ////////////////////////////////////////////////////////////////
208     
209     var file_store = new Ext.data.Store({
210         proxy: new Ext.data.HttpProxy({
211             url: '/cgi-bin/bweb/bresto.pl',
212             method: 'GET',
213             params:{}
214         }),
215         
216         reader: new Ext.data.ArrayReader({},
217          Ext.data.Record.create([
218           {name: 'fileid'    },
219           {name: 'filenameid'},
220           {name: 'pathid'    },
221           {name: 'jobid'     },
222           {name: 'name'      },
223           {name: 'size',     type: 'int'  },
224           {name: 'mtime',    type: 'date', dateFormat: 'Y-m-d h:i:s'},
225           {name: 'type'}
226         ]))
227     });
228     
229     Ext.brestore.file_store=file_store;
230     var cm = new Ext.grid.ColumnModel([{
231         id:        'type',
232         header:    'Type',
233         dataIndex: 'filenameid',
234         width:     30,
235         css:       'white-space:normal;',
236         renderer:   rd_file_or_dir
237     },{
238         id:        'cm-id', // id assigned so we can apply custom css 
239                            // (e.g. .x-grid-col-topic b { color:#333 })
240         header:    'File',
241         dataIndex: 'name',
242         width:     200,
243         css:       'white-space:normal;'
244     },{
245         header:    "Size",
246         dataIndex: 'size',
247         renderer:  human_size,
248         width:     60
249     },{
250         header:    "Date",
251         dataIndex: 'mtime',
252         renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'),
253         width:     100
254     },{
255         header:    "PathId",
256         dataIndex: 'pathid',
257         hidden: true
258     },{
259         header:    "FilenameId",
260         dataIndex: 'filenameid',
261         hidden: true
262     },{
263         header:    "FileId",
264         dataIndex: 'fileid',
265         hidden: true
266     },{
267         header:    "JobId",
268         dataIndex: 'jobid',
269         hidden: true
270     }]);
271
272     // by default columns are sortable
273     cm.defaultSortable = true;
274
275     // reset limits
276     function update_limits() {
277         Ext.get('txt-file-offset').dom.value = Ext.brestore.offset;
278         Ext.get('txt-file-limit').dom.value = Ext.brestore.offset + Ext.brestore.limit;
279     }
280
281     // get limits from user input
282     function update_user_limits() {
283         var off = parseInt(Ext.get('txt-file-offset').getValue());
284         var lim = parseInt(Ext.get('txt-file-limit').getValue());
285         if (off >= 0 && lim >= 0 && off < lim) {
286             Ext.brestore.offset = off;
287             Ext.brestore.limit = lim - off;
288         } else {
289             update_limits();
290         }
291         Ext.brestore.fpattern = Ext.get('txt-file-pattern').getValue();
292     }
293
294     var file_paging_next = new Ext.Toolbar.Button({
295         id: 'bp-file-next',
296         icon: 'ext/resources/images/default/grid/page-next.gif',
297         cls: '.x-btn-icon',
298         tooltip: 'Next',
299         handler: function(a,b,c) {
300             update_user_limits();
301             if (file_store.getCount() >= Ext.brestore.limit) {
302                 Ext.brestore.offset += Ext.brestore.limit;
303                 file_store.removeAll();
304                 file_versions_store.removeAll();
305                 file_store.load({params:init_params({action: 'list_files_dirs',
306                                                      path:Ext.brestore.path,
307                                                      node:Ext.brestore.pathid})
308                                 });
309             }
310         }
311     });
312     var file_paging_prev = new Ext.Toolbar.Button({
313         id: 'bp-file-prev',
314         icon: 'ext/resources/images/default/grid/page-prev.gif',
315         cls: '.x-btn-icon',
316         tooltip: 'Last',
317         handler: function() {
318             update_user_limits();
319             if (Ext.brestore.offset > 0) {
320                 Ext.brestore.offset -= Ext.brestore.limit;
321                 if (Ext.brestore.offset < 0) {
322                     Ext.brestore.offset=0;
323                 }
324                 file_store.removeAll();
325                 file_versions_store.removeAll();
326                 file_store.load({params:init_params({action: 'list_files_dirs',
327                                                      path:Ext.brestore.path,
328                                                      node:Ext.brestore.pathid})
329                                 });                        
330             }
331         }
332     });
333     var file_paging_pattern = new Ext.form.TextField({
334         enableKeyEvents: true,           
335         id: 'txt-file-pattern',
336         text: 'pattern...'
337     });
338     file_paging_pattern.on('keyup', function(a, e) {
339         if (e.getKey() == e. ENTER) {
340             var re;
341             var pattern = file_paging_pattern.getValue();
342             if (pattern) {
343                 re = new RegExp(pattern, "i");                
344             }
345             if (re) {
346                 file_store.filter('name', re);
347             } else {
348                 file_store.clearFilter(false);
349             }
350         }
351     });
352     var file_paging = new Ext.Toolbar({
353         items: [file_paging_prev, {
354             id: 'txt-file-offset',
355             xtype: 'numberfield',
356             width: 60,
357             value: Ext.brestore.offset
358         }, {
359             xtype: 'tbtext',
360             text: '-'
361         }, {
362             id: 'txt-file-limit',
363             xtype: 'numberfield',
364             width: 60,
365             value: Ext.brestore.limit          
366         }, file_paging_next, '->', file_paging_pattern, {
367             id: 'bp-file-match',
368             icon: 'ext/resources/images/default/grid/refresh.gif',
369             cls: '.x-btn-icon',
370             tooltip: 'Refresh',
371             handler: function(a,b,c) {
372                 update_user_limits();
373                 file_store.removeAll();
374                 file_versions_store.removeAll();
375                 file_store.load({params:init_params({action: 'list_files_dirs',
376                                                      path:Ext.brestore.path,
377                                                      node:Ext.brestore.pathid})
378                                 });
379             }
380         }]
381     });
382     var file_grid = new Ext.grid.GridPanel({
383         id: 'div-files',
384         store: file_store,
385         colModel: cm,
386         ddGroup: 'TreeDD',
387         enableDragDrop: true,
388         selModel: new Ext.grid.RowSelectionModel(),
389         loadMask: true,
390         autoSizeColumns: true,
391         autoShow: true,
392         autoHeight: true,
393         title: 'Directory content',
394         cmargins: '5 0 0 0'
395     });
396     Ext.brestore.file_grid=file_grid;
397     // when we reload the view,
398     // we clear the file version box
399     file_store.on('beforeload', function(e) {
400         file_store.removeAll();
401         file_versions_store.removeAll();
402         return true;
403     });
404
405     // If we have more than limit elements, we can
406     // display the next button
407     file_store.on('load', function(e,o) {
408         update_limits();
409         if (e.getCount() >= Ext.brestore.limit) {
410             file_paging_next.enable();
411         } else {
412             file_paging_next.disable();
413         }
414
415         if (Ext.brestore.offset) {
416             file_paging_prev.enable();
417         } else {
418             file_paging_prev.disable();
419         }
420
421     });
422     
423 /*
424  *   file_store.on('loadexception', function(obj, options, response, e){
425  *         console.info('store loadexception, arguments:', arguments);
426  *         console.info('error = ', e);
427  *   });
428  *
429  *   file_store.on('load', function(store, records, options){
430  *         //store is loaded, now you can work with it's records, etc.
431  *         console.info('store load, arguments:', arguments);
432  *         console.info('Store count = ', store.getCount());
433  *   });
434  */
435     file_grid.on('celldblclick', function(e) {
436         var r = e.selModel.getSelected();
437
438         if (r.json[1] == 0) {   // select a directory
439            push_path();
440
441            if (r.json[4] == '..') {
442               Ext.brestore.path = dirname(Ext.brestore.path);
443            } else if (r.json[4] == '/') {
444               Ext.brestore.path = '/';
445            } else if (r.json[4] != '.') {
446               Ext.brestore.path = Ext.brestore.path + r.json[4] + '/';
447            }
448            Ext.brestore.pathid = r.json[2];
449            Ext.brestore.filename = '';
450            Ext.brestore.offset=0;
451            Ext.brestore.fpattern = Ext.get('txt-file-pattern').getValue();
452            where_field.setValue(Ext.brestore.path);
453            update_limits();
454            file_store.load({params:init_params({action: 'list_files_dirs',
455                           path:Ext.brestore.path,
456                           node:Ext.brestore.pathid})
457                     });
458         }
459         return true;
460     });
461     // TODO: selection only when using dblclick
462     file_grid.selModel.on('rowselect', function(e,i,r) { 
463         if (r.json[1] == 0) {   // select a directory
464            return true;
465         }
466
467         Ext.brestore.filename = r.json[4];
468         file_versions_store.load({
469             params:init_params({action: 'list_versions',
470                                 vafv:   Ext.brestore.option_vafv,
471                                 vcopies: Ext.brestore.option_vcopies,
472                                 pathid: r.json[2],
473                                 filenameid: r.json[1]
474                                })
475         });
476         return true;
477     });
478
479     ////////////////////////////////////////////////////////////////
480
481     var file_selection_store = new Ext.data.Store({
482         proxy: new Ext.data.MemoryProxy(),
483         
484         reader: new Ext.data.ArrayReader({},
485           Ext.data.Record.create([
486               {name: 'jobid'     },
487               {name: 'fileid'    },
488               {name: 'filenameid'},
489               {name: 'pathid'    },
490               {name: 'name'      },
491               {name: 'size',     type: 'int'  },
492               {name: 'mtime'}//,    type: 'date', dateFormat: 'Y-m-d h:i:s'}
493           ]))
494     });
495
496     var file_selection_cm = new Ext.grid.ColumnModel([
497         {
498             id:        'file-selection-id', 
499             header:    "Name",
500             dataIndex: 'name',
501             width:     250
502         },{
503             header:    "JobId",
504             width:     50,
505             dataIndex: 'jobid'
506         },{
507             header:    "Size",
508             dataIndex: 'size',
509             renderer:  human_size,
510             width:     50
511         },{
512             header:    "Date",
513             dataIndex: 'mtime',
514 //            renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'),
515             width:     120
516         },{
517             header: 'PathId',
518             dataIndex: 'pathid',
519             hidden: true
520         },{
521             header: 'Filenameid',
522             dataIndex: 'filenameid',
523             hidden: true
524         },{
525             header: 'FileId',
526             dataIndex: 'fileid',
527             hidden: true
528         }
529     ]);
530
531     // create the grid
532     var file_selection_grid = new Ext.grid.GridPanel({
533         colModel: file_selection_cm,
534         store: file_selection_store,
535         ddGroup : 'TreeDD',
536         enableDragDrop: false,
537         selModel: new Ext.grid.RowSelectionModel(),
538         loadMask: true,
539         height: 200,
540 //        autoHeight: true,
541         minSize: 75,
542         maxSize: 250,
543         cmargins: '5 0 0 0'
544     });
545
546     var file_selection_record = Ext.data.Record.create(
547       {name: 'jobid'},
548       {name: 'fileid'},
549       {name: 'filenameid'},
550       {name: 'pathid'},
551       {name: 'size'},
552       {name: 'mtime'}
553     );
554 //    captureEvents(file_selection_grid);
555 //    captureEvents(file_selection_store);
556
557     func1 = function(e,b,c) { 
558         if (e.browserEvent.keyCode == 46) {
559             var m = file_selection_grid.getSelections();
560             if(m.length > 0) {
561                 for(var i = 0, len = m.length; i < len; i++){                    
562                     file_selection_store.remove(m[i]); 
563                 }
564             }
565         }
566     };
567     file_selection_grid.on('keypress', func1);
568     
569     ////////////////////////////////////////////////////////////////
570
571     var file_versions_store = new Ext.data.Store({
572         proxy: new Ext.data.HttpProxy({
573             url: '/cgi-bin/bweb/bresto.pl',
574             method: 'GET',
575             params:{offset:0, limit:50 }
576         }),
577         
578         reader: new Ext.data.ArrayReader({},
579            Ext.data.Record.create([
580                {name: 'fileid'    },
581                {name: 'filenameid'},
582                {name: 'pathid'    },
583                {name: 'jobid'     },
584                {name: 'volume'    },
585                {name: 'inchanger' },
586                {name: 'md5'       },
587                {name: 'size',     type: 'int'  },
588                {name: 'mtime',    type: 'date', dateFormat: 'Y-m-d h:i:s'}
589            ]))
590     });
591
592     var file_versions_cm = new Ext.grid.ColumnModel([{
593         id:        'file-version-id',
594         dataIndex: 'name',
595         hidden: true
596     },{
597         header:    "InChanger",
598         dataIndex: 'inchanger',
599         width:     60,
600         renderer:  rd_vol_is_online
601     },{
602         header:    "Volume",
603         dataIndex: 'volume',
604         width:     128
605     },{
606         header:    "JobId",
607         width:     50,
608         dataIndex: 'jobid'
609     },{
610         header:    "Size",
611         dataIndex: 'size',
612         renderer:  human_size,
613         width:     50
614     },{
615         header:    "Date",
616         dataIndex: 'mtime',
617         renderer: Ext.util.Format.dateRenderer('Y-m-d h:i'),
618         width:     100
619     },{
620         header:    "CheckSum",
621         dataIndex: 'md5',
622         width:     160
623     },{
624         header:    "pathid",
625         dataIndex: 'pathid',
626         hidden: true
627     },{
628         header:    "filenameid",
629         dataIndex: 'filenameid',
630         hidden: true
631     },{
632         header:    "fileid",
633         dataIndex: 'fileid',
634         hidden: true
635     }]);
636
637     // by default columns are sortable
638     file_versions_cm.defaultSortable = true;
639
640     // create the grid
641     var file_versions_grid = new Ext.grid.GridPanel({
642         id: 'div-file-versions',
643         store: file_versions_store,
644         colModel: file_versions_cm,
645         ddGroup : 'TreeDD',
646         enableDragDrop: true,
647         selModel: new Ext.grid.RowSelectionModel(),
648         loadMask: true,
649         autoHeight: true,
650         autoScroll: true,
651         title: 'File version',
652         cmargins: '5 0 0 0'
653     });
654
655     file_versions_grid.on('rowdblclick', function(e) { 
656         alert(e) ; file_versions_store.removeAll(); return true;
657     });
658
659
660     ////////////////////////////////////////////////////////////////
661
662     var client_store = new Ext.data.Store({
663         proxy: new Ext.data.HttpProxy({
664             url: '/cgi-bin/bweb/bresto.pl',
665             method: 'GET',
666             params:{action:'list_client'}
667         }),
668         
669         reader: new Ext.data.ArrayReader({
670         }, Ext.data.Record.create([
671             {name: 'name' }
672         ]))
673     });
674
675     var client_combo = new Ext.form.ComboBox({
676         fieldLabel: 'Clients',
677         store: client_store,
678         displayField:'name',
679         typeAhead: true,
680         mode: 'local',
681         triggerAction: 'all',
682         emptyText:'Select a client...',
683         selectOnFocus:true,
684         forceSelection: true,
685         width:135
686     });
687
688     var replace_store = new Ext.data.SimpleStore({
689         fields: ['value', 'text'],
690         data : [['never', 'Never'],['always', 'Always']]
691     });
692
693     var replace_combo = new Ext.form.ComboBox({
694         fieldLabel: 'Replace',
695         store: replace_store,
696         displayField:'text',
697         typeAhead: true,
698         mode: 'local',
699         triggerAction: 'all',
700         emptyText:'Replace mode...',
701         selectOnFocus:true,
702         forceSelection: true,
703         width:135
704     });
705
706     client_combo.on('valid', function(e) { 
707         Ext.brestore.client = e.getValue();
708         Ext.brestore.jobid=0;
709         Ext.brestore.jobdate = '';
710         Ext.brestore.root_path='';
711         Ext.brestore.offset=0;
712         job_combo.clearValue();
713         file_store.removeAll();
714         file_versions_store.removeAll();
715         root.collapse(false, false);
716         while(root.firstChild){
717             root.removeChild(root.firstChild);
718         }
719         job_store.load( {params:{action: 'list_job',
720                                  client:Ext.brestore.client}});
721         return true;
722     });
723
724     //////////////////////////////////////////////////////////////:
725
726     var job_store = new Ext.data.Store({
727         proxy: new Ext.data.HttpProxy({
728             url: '/cgi-bin/bweb/bresto.pl',
729             method: 'GET',
730             params:{offset:0, limit:50 }
731         }),
732
733         reader: new Ext.data.ArrayReader({
734         }, Ext.data.Record.create([
735            {name: 'jobid' },
736            {name: 'date'  },
737            {name: 'jobname' }
738         ]))
739     });
740
741     var job_combo = new Ext.form.ComboBox({
742         store:           job_store,
743         fieldLabel:      'Jobs',
744         displayField:    'jobname',
745         mode:            'local',
746         triggerAction:   'all',
747         emptyText:       'Select a job...',
748         typeAhead:       true,
749         selectOnFocus:   true,
750         loadMask:        true,
751         forceSelection:  true,
752         width:           350
753     });
754
755     job_combo.on('select', function(e,c) {
756         Ext.brestore.jobid = c.json[0];
757         Ext.brestore.jobdate = c.json[1];
758         root.setText("Root");
759         tree_loader.baseParams = init_params({init:1, action: 'list_dirs'});
760         root.reload();
761
762         file_store.load({params:init_params({action: 'list_files_dirs',
763                                              path:Ext.brestore.path,
764                                              node:Ext.brestore.pathid})
765                         });
766     });
767
768     var where_field = new Ext.form.TextField({
769             fieldLabel: 'Location',
770             id: 'wherefield',
771             name: 'where',
772             width:275,
773             allowBlank:false
774     });
775
776     function sel_option(item, check)
777     {
778         if (item.id == 'id_vosb') {
779            Ext.brestore.option_vosb = check;
780         }
781         if (item.id == 'id_vafv') {
782            Ext.brestore.option_vafv = check;
783         }
784         if (item.id == 'id_vcopies') {
785            Ext.brestore.option_vcopies = check;
786         }
787     }
788
789     var menu = new Ext.menu.Menu({
790         id: 'div-main-menu',
791         items: [ 
792            new Ext.menu.CheckItem({
793                 id: 'id_vosb',
794                 text: 'View only selected backup',
795                 checked: Ext.brestore.option_vosb,
796                 checkHandler: sel_option
797             }),
798            new Ext.menu.CheckItem({
799                 id: 'id_vafv',
800                 text: 'View all file versions',
801                 checked: Ext.brestore.option_vafv,
802                 checkHandler: sel_option
803               }),
804            new Ext.menu.CheckItem({
805                 id: 'id_copies',
806                 text: 'View copies version',
807                 checked: Ext.brestore.option_vcopies,
808                 checkHandler: sel_option
809             })
810         ]
811     });
812
813     var tb = new Ext.Toolbar({
814         items: [
815             client_combo,
816             job_combo,
817             '-',
818             {
819                 id: 'prevbp',
820                 cls: 'x-btn-icon',
821                 icon: 'prev.png',
822                 disabled: true,
823                 handler: function() { 
824                     if (!pop_path()) {
825                         return;
826                     }
827                     Ext.brestore.offset=0;
828                     update_limits();       
829                     file_store.load({params:init_params({action: 'list_files_dirs',
830                                                          node:Ext.brestore.pathid})
831                                     });
832                     
833                 }
834
835             },
836             { 
837               text: 'Change location',
838               cls:'x-btn-text-icon',
839               handler: function() { 
840                   var where = where_field.getValue();
841                   if (!where) {
842                       Ext.MessageBox.show({
843                           title: 'Bad parameter',
844                           msg: 'Location is empty!',
845                           buttons: Ext.MessageBox.OK,
846                           icon: Ext.MessageBox.ERROR
847                       });
848                       return;
849                   }
850                   Ext.brestore.root_path=where;
851                   root.setText(where);
852                   tree_loader.baseParams = init_params({ 
853                       action:'list_dirs', path: where
854                   });
855                   root.reload();
856               }
857             },
858             where_field,
859             {
860                 text:'Options',
861                 iconCls: 'bmenu',  // <-- icon
862                 menu: menu  // assign menu by instance
863             },
864             '->',                     // Fill
865             {                         // TODO: put this button on south panel
866                 icon: 'mR.png', // icons can also be specified inline
867                 cls: 'x-btn-text-icon',
868                 tooltip: 'Run restore',
869                 text: 'Run restore',
870                 handler: function() {
871                     if (!file_selection_store.data.items.length) {
872                         Ext.MessageBox.show({
873                             title: 'Empty selection',
874                             msg: 'Your object selection list is empty!',
875                             buttons: Ext.MessageBox.OK,
876                             icon: Ext.MessageBox.ERROR
877                         });
878                     } else {
879                         display_run_job();
880                     }
881                 }
882             }]});
883     tb.render('tb-div');
884
885     ////////////////////////////////////////////////////////////////
886     
887     // Define Main interface
888     var MainView = new Ext.Viewport({
889         id:'mainview-panel',
890         title: 'Bacula Web Restore',
891         layout:'border',
892         bodyBorder: false,
893         renderTo: Ext.getBody(),
894         defaults: {
895             collapsible: false,
896             split: true,
897             animFloat: false,
898             autoHide: false,
899             autoScroll: true,
900             useSplitTips: true
901         },
902         tbar: tb,
903         items: [
904             {
905                 title: 'Directories',
906                 region: 'west',
907                 width: '25%',
908                 minSize: 120,
909                 items: tree
910             }, {
911                 title: 'Directory content',
912                 region: 'center',
913                 minSize: '33%',
914                 items: file_grid,
915                 bbar: file_paging
916             }, {
917                 title: 'File version',
918                 region: 'east',
919                 width: '42%',
920                 minSize: 100,
921                 items: file_versions_grid
922               
923             }, {
924                 title: 'Restore selection',
925                 region: 'south',
926                 height: 200,
927                 autoScroll: false,
928                 items: file_selection_grid
929             }
930         ]});
931     client_store.load({params:{action: 'list_client'}});
932
933     // data.selections[0].json[]
934     // data.node.id
935     // http://extjs.com/forum/showthread.php?t=12582&highlight=drag+drop
936
937     var horror_show1 = file_selection_grid.getView().el.dom;
938     var ddrow = new Ext.dd.DropTarget(horror_show1, {
939         ddGroup : 'TreeDD',
940         copy:false,
941         notifyDrop : function(dd, e, data){
942             var r;
943             if (data.selections) {
944                 if (data.grid.id == 'div-files') {
945                     for(var i=0;i<data.selections.length;i++) {
946                         var name = data.selections[i].json[4];
947                         var fnid = data.selections[i].json[1];
948                         if (fnid == 0 && name != '..') {
949                             name = name + '/';
950                         }
951                         r = new file_selection_record({
952                             jobid:     data.selections[0].json[3],
953                             fileid:    data.selections[i].json[0],
954                             filenameid:data.selections[i].json[1],
955                             pathid:    data.selections[i].json[2],
956                             name: Ext.brestore.path + ((name=='..')?'':name),
957                             size:      data.selections[i].json[5],
958                             mtime:     data.selections[i].json[6]
959                         });
960                         file_selection_store.add(r);
961                     }
962                 }
963                 
964                 if (data.grid.id == 'div-file-versions') {
965                     r = new file_selection_record({
966                         jobid:     data.selections[0].json[3],
967                         fileid:    data.selections[0].json[0],
968                         filenameid:data.selections[0].json[1],
969                         pathid:    data.selections[0].json[2],
970                         name: Ext.brestore.path + Ext.brestore.filename,
971                         size:      data.selections[0].json[7],
972                         mtime:     data.selections[0].json[8]     
973                     });
974                     file_selection_store.add(r)
975                 }
976             }
977             
978             if (data.node) {
979                 var path= get_node_path(data.node);
980                 r = new file_selection_record({
981                     jobid:     data.node.attributes.jobid,
982                     fileid:    0,
983                     filenameid:0,
984                     pathid:    data.node.id,
985                     name:      path,
986                     size:      4096,
987                     mtime:     0
988                 });
989                 file_selection_store.add(r)
990             }
991             
992             return true;
993         }});
994
995     function force_reload_media_store() {
996        Ext.brestore.force_reload = 1;
997        reload_media_store();
998        Ext.brestore.force_reload = 0;
999     }
1000
1001     function reload_media_store() {
1002         Ext.brestore.media_store.removeAll();
1003         var items = file_selection_store.data.items;
1004         var tab_fileid=new Array();
1005         var tab_dirid=new Array();
1006         var tab_jobid=new Array();
1007         var enable_compute=false;
1008         for(var i=0;i<items.length;i++) {
1009             if (items[i].data['fileid']) {
1010                tab_fileid.push(items[i].data['fileid']);
1011             } else {
1012                tab_dirid.push(items[i].data['pathid']);
1013                enable_compute=true;
1014             }
1015             tab_jobid.push(items[i].data['jobid']);
1016         }
1017         var res = tab_fileid.join(",");
1018         var res2 = tab_jobid.join(",");
1019         var res3 = tab_dirid.join(",");
1020
1021         Ext.brestore.media_store.baseParams = init_params({
1022             action: 'get_media', 
1023             jobid: res2, 
1024             fileid: res,
1025             dirid: res3,
1026             force: Ext.brestore.force_reload
1027         });
1028         Ext.brestore.media_store.load();
1029         if (enable_compute) {
1030             Ext.get('reload_media').show();
1031         } else {
1032             Ext.get('reload_media').hide();
1033         }
1034     };
1035
1036     function display_run_job() {
1037         if (Ext.brestore.dlglaunch) {
1038             reload_media_store();
1039             Ext.brestore.dlglaunch.show();
1040             return 0;
1041         }
1042         var rclient_combo = new Ext.form.ComboBox({
1043             value: Ext.brestore.client,
1044             fieldLabel: 'Client',
1045             hiddenName:'client',
1046             store: client_store,
1047             displayField:'name',
1048             typeAhead: true,
1049             mode: 'local',
1050             triggerAction: 'all',
1051             emptyText:'Select a client...',
1052             forceSelection: true,
1053             value:  Ext.brestore.client,
1054             selectOnFocus:true
1055         });
1056         var where_text = new Ext.form.TextField({
1057             fieldLabel: 'Where',
1058             name: 'where',
1059             value: '/tmp/bacula-restore'
1060         });
1061         var stripprefix_text = new Ext.form.TextField({
1062             fieldLabel: 'Strip prefix',
1063             name: 'strip_prefix',
1064             value: '',
1065             disabled: 1
1066         });
1067         var addsuffix_text = new Ext.form.TextField({
1068             fieldLabel: 'Add suffix',
1069             name: 'add_suffix',
1070             value: '',
1071             disabled: 1
1072         });
1073         var addprefix_text = new Ext.form.TextField({
1074             fieldLabel: 'Add prefix',
1075             name: 'add_prefix',
1076             value: '',
1077             disabled: 1
1078         });
1079         var rwhere_text = new Ext.form.TextField({
1080             fieldLabel: 'Where regexp',
1081             name: 'regexp_where',
1082             value: '',
1083             disabled: 1
1084         });
1085         var useregexp_bp = new Ext.form.Checkbox({
1086             fieldLabel: 'Use regexp',
1087             name: 'use_regexp',
1088             disabled: 1,
1089             checked: 0,
1090             handler: function(bp,state) {
1091                 if (state) {
1092                     addsuffix_text.disable();
1093                     addprefix_text.disable();
1094                     stripprefix_text.disable();
1095                     rwhere_text.enable();
1096                 } else {
1097                     addsuffix_text.enable();
1098                     addprefix_text.enable();
1099                     stripprefix_text.enable();
1100                     rwhere_text.disable();
1101                 }
1102             }
1103         }); 
1104
1105         var usefilerelocation_bp = new Ext.form.Checkbox({
1106             fieldLabel: 'Use file relocation',
1107             name: 'use_relocation',
1108             checked: 0
1109         });
1110        
1111         usefilerelocation_bp.on('check', function(bp,state) {
1112             if (state) {
1113                 where_text.disable();
1114                 useregexp_bp.enable();
1115                 if (useregexp_bp.getValue()) {
1116                     addsuffix_text.disable();
1117                     addprefix_text.disable();
1118                     stripprefix_text.disable();
1119                     rwhere_text.enable();
1120                 } else {
1121                     addsuffix_text.enable();
1122                     addprefix_text.enable();
1123                     stripprefix_text.enable();
1124                     rwhere_text.disable();
1125                 }
1126             } else {
1127                 where_text.enable();
1128                 addsuffix_text.disable();
1129                 addprefix_text.disable();
1130                 stripprefix_text.disable();
1131                 useregexp_bp.disable();
1132                 rwhere_text.disable();
1133             }
1134             Ext.brestore.use_filerelocation = state;
1135         }); 
1136
1137         useregexp_bp.on('check', function(bp,state) {
1138             if (state) {
1139                 addsuffix_text.disable();
1140                 addprefix_text.disable();
1141                 stripprefix_text.disable();
1142                 rwhere_text.enable();
1143             } else {
1144                 addsuffix_text.enable();
1145                 addprefix_text.enable();
1146                 stripprefix_text.enable();
1147                 rwhere_text.disable();
1148             }
1149         }); 
1150         
1151         var media_store = Ext.brestore.media_store = new Ext.data.Store({
1152             proxy: new Ext.data.HttpProxy({
1153                 url: '/cgi-bin/bweb/bresto.pl',
1154                 method: 'GET',
1155                 params:{offset:0, limit:50 }
1156             }),
1157             
1158             reader: new Ext.data.ArrayReader({
1159             }, Ext.data.Record.create([
1160                 {name: 'volumename'},
1161                 {name: 'enabled'   },
1162                 {name: 'inchanger' }
1163             ]))
1164         });
1165         
1166         var media_cm = new Ext.grid.ColumnModel(
1167             [{
1168                 header:    "InChanger",
1169                 dataIndex: 'inchanger',
1170                 width:     60,
1171                 renderer:  rd_vol_is_online
1172             }, {
1173                 header:    "Volume",
1174                 id:        'volumename', 
1175                 dataIndex: 'volumename',
1176                 width:     200
1177             }
1178             ]);
1179         
1180         // create the grid
1181         var media_grid = new Ext.grid.GridPanel({
1182             id: 'div-media-grid',
1183             store: media_store,
1184             colModel: media_cm,
1185             enableDragDrop: false,
1186             loadMask: true,
1187             width: 400,
1188             height: 180,
1189             frame: true
1190         });
1191
1192         var form_panel = new Ext.FormPanel({
1193             labelWidth : 75, // label settings here cascade unless overridden
1194             frame      : true,
1195             bodyStyle  : 'padding:5px 5px 0',
1196             width      : 250,
1197 //          autoHeight : true,
1198             items: [{
1199                 xtype       :   'tabpanel',
1200                 autoTabs    :   true,
1201                 activeTab   :   0,
1202                 border      :   false,
1203                 bodyStyle   :  'padding:5px 5px 0',
1204                 deferredRender : false,
1205                 items: [{
1206                     xtype   :   'panel',
1207                     title   :   'Restore details',
1208                     items   :  [{
1209                         xtype          : 'fieldset',
1210                         title          : 'Restore options',
1211                         autoHeight     : true,
1212                         defaults       : {width: 210},
1213                         bodyStyle  : 'padding:5px 5px 0',
1214                         items :[ rclient_combo, where_text, replace_combo ]
1215                     }, {
1216                         xtype          : 'fieldset',
1217                         title          : 'Media needed',
1218                         autoHeight     : true,
1219                         defaults       : {width: 280},
1220                         bodyStyle  : 'padding:5px 5px 0',
1221                         items :[ media_grid, 
1222                                  {xtype: 'button', id: 'reload_media',
1223                                   text: 'Compute with directories',
1224                                   tooltip: 'Can take long time...',
1225                                   handler:force_reload_media_store}]
1226                     }],
1227                 }, {
1228                     xtype   :   'panel',
1229                     title   :   'Advanced',
1230                     items   :  [{
1231                         xtype          : 'fieldset',
1232                         title          : 'File relocation',
1233                         autoHeight     : true,
1234                         defaults       : {width: 210},
1235                         bodyStyle      : 'padding:5px 5px 0',
1236                         items :[ usefilerelocation_bp, stripprefix_text, 
1237                                  addprefix_text, addsuffix_text, useregexp_bp,
1238                                  rwhere_text ]
1239                     },{
1240                         xtype          : 'fieldset',
1241                         title          : 'Other options',
1242                         autoHeight     : true,
1243                         defaults       : {width: 210},
1244                         bodyStyle      : 'padding:5px 5px 0',
1245                         defaultType    : 'textfield',
1246                         items :[{
1247                             name: 'when_text',
1248                             fieldLabel: 'When',
1249                             disabled: true,
1250                             tooltip: 'YYY-MM-DD HH:MM'
1251                         }, {
1252                             name: 'prio_text',
1253                             fieldLabel: 'Priority',
1254                             disabled: true,
1255                             tooltip: '1-100'
1256                         }]
1257                     }]
1258                 }]
1259             }],
1260             
1261             buttons: [{
1262                 text: 'Run',
1263                 handler: function() { 
1264                     if(!form_panel.getForm().isValid()) { alert("invalid") } 
1265                     else { launch_restore() }
1266                 }
1267             },{
1268                 text: 'Cancel',
1269                 handler: function() { Ext.brestore.dlglaunch.hide(); }
1270             }]
1271         });
1272
1273         Ext.brestore.dlglaunch = new Ext.Window({
1274             applyTo     : 'resto-div',
1275             title       : 'Restore selection',
1276             layout      : 'fit',
1277             width       : 400,
1278             height      : 500,
1279             closeAction :'hide',
1280             plain       : true,
1281             items       : form_panel
1282         });
1283
1284 //        Ext.brestore.dlglaunch.addKeyListener(27, 
1285 //                                              Ext.brestore.dlglaunch.hide, 
1286 //                                              Ext.brestore.dlglaunch);
1287 /*        
1288  *       var storage_store = new Ext.data.Store({
1289  *           proxy: new Ext.data.HttpProxy({
1290  *               url: '/cgi-bin/bweb/bresto.pl',
1291  *               method: 'GET',
1292  *               params:{action:'list_storage'}
1293  *           }),
1294  *           
1295  *           reader: new Ext.data.ArrayReader({
1296  *           }, Ext.data.Record.create([
1297  *               {name: 'name' }
1298  *           ]))
1299  *       });
1300  */      
1301         ////////////////////////////////////////////////////////////////
1302
1303         function launch_restore() {
1304             var items = file_selection_store.data.items;
1305             var tab_fileid=new Array();
1306             var tab_dirid=new Array();
1307             var tab_jobid=new Array();
1308             for(var i=0;i<items.length;i++) {
1309                 if (items[i].data['fileid']) {
1310                     tab_fileid.push(items[i].data['fileid']);
1311                 } else {
1312                     tab_dirid.push(items[i].data['pathid']);
1313                 }
1314                 tab_jobid.push(items[i].data['jobid']);
1315             }
1316             var res = ';fileid=' + tab_fileid.join(";fileid=");
1317             var res2 = ';dirid=' + tab_dirid.join(";dirid=");
1318             var res3 = ';jobid=' + tab_jobid.join(";jobid=");
1319
1320             var res4 = ';client=' + rclient_combo.getValue();
1321 //            if (storage_combo.getValue()) {
1322 //                res4 = res4 + ';storage=' + storage_combo.getValue();
1323 //            }
1324             if (Ext.brestore.use_filerelocation) {
1325                 if (useregexp_bp.getValue()) {
1326                     res4 = res4 + ';regexwhere=' + rwhere_text.getValue();
1327                 } else {
1328                     var reg = new Array();
1329                     if (stripprefix_text.getValue()) {
1330                         reg.push('!' + stripprefix_text.getValue() + '!!i');
1331                     }
1332                     if (addprefix_text.getValue()) {
1333                         reg.push('!^!' + addprefix_text.getValue() + '!');
1334                     }
1335                     if (addsuffix_text.getValue()) {
1336                         reg.push('!([^/])$!$1' + addsuffix_text.getValue() + '!');
1337                     }
1338                     res4 = res4 + ';regexwhere=' + reg.join(',');
1339                 }
1340             } else {
1341                 res4 = res4 + ';where=' + where_text.getValue();
1342             }
1343             window.location='/cgi-bin/bweb/bresto.pl?action=restore' + res + res2 + res3 + res4;
1344         } // end launch_restore
1345
1346
1347         ////////////////////////////////////////////////////////////////
1348         reload_media_store();
1349         Ext.brestore.dlglaunch.show();
1350 //      storage_store.load({params:{action: 'list_storage'}});
1351     }
1352 });