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