]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/html/bresto.js
77a605dd2893a57fb3c8e03b0c306647656c241c
[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 John Walker.
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             console.info("DropTarget");
851             var r;
852             if (data.selections) {
853                 if (data.grid.id == 'div-files') {
854                     for(var i=0;i<data.selections.length;i++) {
855                         r = new file_selection_record({
856                             jobid:     data.selections[0].json[3],
857                             fileid:    data.selections[i].json[0],
858                             filenameid:data.selections[i].json[1],
859                             pathid:    data.selections[i].json[2],
860                             name: Ext.brestore.path + data.selections[i].json[4],
861                             size:      data.selections[i].json[5],
862                             mtime:     data.selections[i].json[6]
863                         });
864                         file_selection_store.add(r);
865                     }
866                 }
867                 
868                 if (data.grid.id == 'div-file-versions') {
869                     r = new file_selection_record({
870                         jobid:     data.selections[0].json[3],
871                         fileid:    data.selections[0].json[0],
872                         filenameid:data.selections[0].json[1],
873                         pathid:    data.selections[0].json[2],
874                         name: Ext.brestore.path + Ext.brestore.filename,
875                         size:      data.selections[0].json[7],
876                         mtime:     data.selections[0].json[8]     
877                     });
878                     file_selection_store.add(r)
879                 }
880             }
881             
882             if (data.node) {
883                 var path= get_node_path(data.node);
884                 r = new file_selection_record({
885                     jobid:     data.node.attributes.jobid,
886                     fileid:    0,
887                     filenameid:0,
888                     pathid:    data.node.id,
889                     name:      path,
890                     size:      4096,
891                     mtime:     0
892                 });
893                 file_selection_store.add(r)
894             }
895             
896             return true;
897         }});
898
899     function force_reload_media_store() {
900        Ext.brestore.force_reload = 1;
901        reload_media_store();
902        Ext.brestore.force_reload = 0;
903     }
904
905     function reload_media_store() {
906         var items = file_selection_store.data.items;
907         var tab_fileid=new Array();
908         var tab_dirid=new Array();
909         var tab_jobid=new Array();
910         var enable_compute=false;
911         for(var i=0;i<items.length;i++) {
912             if (items[i].data['fileid']) {
913                tab_fileid.push(items[i].data['fileid']);
914             } else {
915                tab_dirid.push(items[i].data['pathid']);
916                enable_compute=true;
917             }
918             tab_jobid.push(items[i].data['jobid']);
919         }
920         var res = tab_fileid.join(",");
921         var res2 = tab_jobid.join(",");
922         var res3 = tab_dirid.join(",");
923
924         Ext.brestore.media_store.baseParams = init_params({
925             action: 'get_media', 
926             jobid: res2, 
927             fileid: res,
928             dirid: res3,
929             force: Ext.brestore.force_reload
930         });
931         Ext.brestore.media_store.load();
932         if (enable_compute) {
933             Ext.get('reload_media').show();
934         } else {
935             Ext.get('reload_media').hide();
936         }
937     };
938
939     function display_run_job() {
940         if (Ext.brestore.dlglaunch) {
941             reload_media_store();
942             Ext.brestore.dlglaunch.show();
943             return 0;
944         }
945         var rclient_combo = new Ext.form.ComboBox({
946             value: Ext.brestore.client,
947             fieldLabel: 'Client',
948             hiddenName:'client',
949             store: client_store,
950             displayField:'name',
951             typeAhead: true,
952             mode: 'local',
953             triggerAction: 'all',
954             emptyText:'Select a client...',
955             forceSelection: true,
956             value:  Ext.brestore.client,
957             selectOnFocus:true
958         });
959         var where_text = new Ext.form.TextField({
960             fieldLabel: 'Where',
961             name: 'where',
962             value: '/tmp/bacula-restore'
963         });
964         var stripprefix_text = new Ext.form.TextField({
965             fieldLabel: 'Strip prefix',
966             name: 'strip_prefix',
967             value: '',
968             disabled: 1
969         });
970         var addsuffix_text = new Ext.form.TextField({
971             fieldLabel: 'Add suffix',
972             name: 'add_suffix',
973             value: '',
974             disabled: 1
975         });
976         var addprefix_text = new Ext.form.TextField({
977             fieldLabel: 'Add prefix',
978             name: 'add_prefix',
979             value: '',
980             disabled: 1
981         });
982         var rwhere_text = new Ext.form.TextField({
983             fieldLabel: 'Where regexp',
984             name: 'regexp_where',
985             value: '',
986             disabled: 1
987         });
988         var useregexp_bp = new Ext.form.Checkbox({
989             fieldLabel: 'Use regexp',
990             name: 'use_regexp',
991             disabled: 1,
992             checked: 0,
993             handler: function(bp,state) {
994                 if (state) {
995                     addsuffix_text.disable();
996                     addprefix_text.disable();
997                     stripprefix_text.disable();
998                     rwhere_text.enable();
999                 } else {
1000                     addsuffix_text.enable();
1001                     addprefix_text.enable();
1002                     stripprefix_text.enable();
1003                     rwhere_text.disable();
1004                 }
1005             }
1006         }); 
1007
1008         var usefilerelocation_bp = new Ext.form.Checkbox({
1009             fieldLabel: 'Use file relocation',
1010             name: 'use_relocation',
1011             checked: 0
1012         });
1013        
1014         usefilerelocation_bp.on('check', function(bp,state) {
1015             if (state) {
1016                 where_text.disable();
1017                 useregexp_bp.enable();
1018                 if (useregexp_bp.getValue()) {
1019                     addsuffix_text.disable();
1020                     addprefix_text.disable();
1021                     stripprefix_text.disable();
1022                     rwhere_text.enable();
1023                 } else {
1024                     addsuffix_text.enable();
1025                     addprefix_text.enable();
1026                     stripprefix_text.enable();
1027                     rwhere_text.disable();
1028                 }
1029             } else {
1030                 where_text.enable();
1031                 addsuffix_text.disable();
1032                 addprefix_text.disable();
1033                 stripprefix_text.disable();
1034                 useregexp_bp.disable();
1035                 rwhere_text.disable();
1036             }
1037         }); 
1038
1039         useregexp_bp.on('check', function(bp,state) {
1040             if (state) {
1041                 addsuffix_text.disable();
1042                 addprefix_text.disable();
1043                 stripprefix_text.disable();
1044                 rwhere_text.enable();
1045             } else {
1046                 addsuffix_text.enable();
1047                 addprefix_text.enable();
1048                 stripprefix_text.enable();
1049                 rwhere_text.disable();
1050             }
1051         }); 
1052         
1053         var media_store = Ext.brestore.media_store = new Ext.data.Store({
1054             proxy: new Ext.data.HttpProxy({
1055                 url: '/cgi-bin/bweb/bresto.pl',
1056                 method: 'GET',
1057                 params:{offset:0, limit:50 }
1058             }),
1059             
1060             reader: new Ext.data.ArrayReader({
1061             }, Ext.data.Record.create([
1062                 {name: 'volumename'},
1063                 {name: 'enabled'   },
1064                 {name: 'inchanger' }
1065             ]))
1066         });
1067         
1068         var media_cm = new Ext.grid.ColumnModel(
1069             [{
1070                 header:    "InChanger",
1071                 dataIndex: 'inchanger',
1072                 width:     60,
1073                 renderer:  rd_vol_is_online
1074             }, {
1075                 header:    "Volume",
1076                 id:        'volumename', 
1077                 dataIndex: 'volumename',
1078                 width:     200
1079             }
1080             ]);
1081         
1082         // create the grid
1083         var media_grid = new Ext.grid.GridPanel({
1084             id: 'div-media-grid',
1085             store: media_store,
1086             colModel: media_cm,
1087             enableDragDrop: false,
1088             loadMask: true,
1089             width: 400,
1090             height: 180,
1091             frame: true
1092         });
1093
1094         var form_panel = new Ext.FormPanel({
1095             labelWidth : 75, // label settings here cascade unless overridden
1096             frame      : true,
1097             bodyStyle  : 'padding:5px 5px 0',
1098             width      : 250,
1099 //          autoHeight : true,
1100             items: [{
1101                 xtype       :   'tabpanel',
1102                 autoTabs    :   true,
1103                 activeTab   :   0,
1104                 border      :   false,
1105                 bodyStyle   :  'padding:5px 5px 0',
1106                 deferredRender : false,
1107                 items: [{
1108                     xtype   :   'panel',
1109                     title   :   'Restore details',
1110                     items   :  [{
1111                         xtype          : 'fieldset',
1112                         title          : 'Restore options',
1113                         autoHeight     : true,
1114                         defaults       : {width: 210},
1115                         bodyStyle  : 'padding:5px 5px 0',
1116                         items :[ rclient_combo, where_text, replace_combo ]
1117                     }, {
1118                         xtype          : 'fieldset',
1119                         title          : 'Media needed',
1120                         autoHeight     : true,
1121                         defaults       : {width: 280},
1122                         bodyStyle  : 'padding:5px 5px 0',
1123                         items :[ media_grid, 
1124                                  {xtype: 'button', id: 'reload_media',
1125                                   text: 'Compute with directories',
1126                                   tooltip: 'Can take long time...',
1127                                   handler:force_reload_media_store}]
1128                     }],
1129                 }, {
1130                     xtype   :   'panel',
1131                     title   :   'Advanced',
1132                     items   :  [{
1133                         xtype          : 'fieldset',
1134                         title          : 'File relocation',
1135                         autoHeight     : true,
1136                         defaults       : {width: 210},
1137                         bodyStyle      : 'padding:5px 5px 0',
1138                         items :[ usefilerelocation_bp, stripprefix_text, 
1139                                  addprefix_text, addsuffix_text, useregexp_bp,
1140                                  rwhere_text ]
1141                     },{
1142                         xtype          : 'fieldset',
1143                         title          : 'Other options',
1144                         autoHeight     : true,
1145                         defaults       : {width: 210},
1146                         bodyStyle      : 'padding:5px 5px 0',
1147                         defaultType    : 'textfield',
1148                         items :[{
1149                             name: 'when_text',
1150                             fieldLabel: 'When',
1151                             disabled: true,
1152                             tooltip: 'YYY-MM-DD HH:MM'
1153                         }, {
1154                             name: 'prio_text',
1155                             fieldLabel: 'Priority',
1156                             disabled: true,
1157                             tooltip: '1-100'
1158                         }]
1159                     }]
1160                 }]
1161             }],
1162             
1163             buttons: [{
1164                 text: 'Run',
1165                 handler: function() { 
1166                     if(!form_panel.getForm().isValid()) { alert("invalid") } 
1167                     else { launch_restore() }
1168                 }
1169             },{
1170                 text: 'Cancel',
1171                 handler: function() { Ext.brestore.dlglaunch.hide(); }
1172             }]
1173         });
1174
1175         Ext.brestore.dlglaunch = new Ext.Window({
1176             applyTo     : 'resto-div',
1177             title       : 'Restore selection',
1178             layout      : 'fit',
1179             width       : 400,
1180             height      : 500,
1181             closeAction :'hide',
1182             plain       : true,
1183             items       : form_panel
1184         });
1185
1186 //        Ext.brestore.dlglaunch.addKeyListener(27, 
1187 //                                              Ext.brestore.dlglaunch.hide, 
1188 //                                              Ext.brestore.dlglaunch);
1189 /*        
1190  *       var storage_store = new Ext.data.Store({
1191  *           proxy: new Ext.data.HttpProxy({
1192  *               url: '/cgi-bin/bweb/bresto.pl',
1193  *               method: 'GET',
1194  *               params:{action:'list_storage'}
1195  *           }),
1196  *           
1197  *           reader: new Ext.data.ArrayReader({
1198  *           }, Ext.data.Record.create([
1199  *               {name: 'name' }
1200  *           ]))
1201  *       });
1202  */      
1203         ////////////////////////////////////////////////////////////////
1204
1205         function launch_restore() {
1206             var items = file_selection_store.data.items;
1207             var tab_fileid=new Array();
1208             var tab_dirid=new Array();
1209             var tab_jobid=new Array();
1210             for(var i=0;i<items.length;i++) {
1211                 if (items[i].data['fileid']) {
1212                     tab_fileid.push(items[i].data['fileid']);
1213                 } else {
1214                     tab_dirid.push(items[i].data['pathid']);
1215                 }
1216                 tab_jobid.push(items[i].data['jobid']);
1217             }
1218             var res = ';fileid=' + tab_fileid.join(";fileid=");
1219             var res2 = ';dirid=' + tab_dirid.join(";dirid=");
1220             var res3 = ';jobid=' + tab_jobid.join(";jobid=");
1221
1222             var res4 = ';client=' + rclient_combo.getValue();
1223 //            if (storage_combo.getValue()) {
1224 //                res4 = res4 + ';storage=' + storage_combo.getValue();
1225 //            }
1226             if (Ext.brestore.use_filerelocation) {
1227                 if (useregexp_bp.getValue()) {
1228                     res4 = res4 + ';regexwhere=' + rwhere_text.getValue();
1229                 } else {
1230                     var reg = new Array();
1231                     if (stripprefix_text.getValue()) {
1232                         reg.push('!' + stripprefix_text.getValue() + '!!i');
1233                     }
1234                     if (addprefix_text.getValue()) {
1235                         reg.push('!^!' + addprefix_text.getValue() + '!');
1236                     }
1237                     if (addsuffix_text.getValue()) {
1238                         reg.push('!([^/])$!$1' + addsuffix_text.getValue() + '!');
1239                     }
1240                     res4 = res4 + ';regexwhere=' + reg.join(',');
1241                 }
1242             } else {
1243                 res4 = res4 + ';where=' + where_text.getValue();
1244             }
1245             window.location='/cgi-bin/bweb/bresto.pl?action=restore' + res + res2 + res3 + res4;
1246         } // end launch_restore
1247
1248
1249         ////////////////////////////////////////////////////////////////
1250         reload_media_store();
1251         Ext.brestore.dlglaunch.show();
1252 //      storage_store.load({params:{action: 'list_storage'}});
1253     }
1254 });