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