]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Improve restore wizard
authorMarcin Haba <marcin.haba@bacula.pl>
Wed, 10 Jun 2020 23:23:38 +0000 (01:23 +0200)
committerMarcin Haba <marcin.haba@bacula.pl>
Thu, 11 Jun 2020 06:15:39 +0000 (08:15 +0200)
 - make it working faster with thousands of files
 - the wizard should start working with PHP 7.4
 - improve preserving information in fields during moving back and forward by wizard steps
 - add clientid property to BVFS versions API endpoint
 - fix javascript error in the wizard

gui/baculum/protected/API/Pages/API/BVFSVersions.php
gui/baculum/protected/API/openapi_baculum.json
gui/baculum/protected/Common/Class/BClientScript.php
gui/baculum/protected/Web/JavaScript/misc.js
gui/baculum/protected/Web/Pages/RestoreWizard.page
gui/baculum/protected/Web/Pages/RestoreWizard.php
gui/baculum/themes/Baculum-v2/css/restore-wizard.css

index c513fe54d1d8d105028aca20d4f686b851030feb..9131ce46164b8e4f6b0d71e5c21f2023b0f92e30 100644 (file)
@@ -3,7 +3,7 @@
  * Bacula(R) - The Network Backup Solution
  * Baculum   - Bacula web interface
  *
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2020 Kern Sibbald
  *
  * The main author of Baculum is Marcin Haba.
  * The original author of Bacula is Kern Sibbald, with contributions
@@ -40,6 +40,12 @@ class BVFSVersions extends ConsoleOutputPage {
                $client = null;
                if ($this->Request->contains('client') && $this->getModule('misc')->isValidName($this->Request['client'])) {
                        $client = $this->Request['client'];
+               } elseif ($this->Request->contains('clientid')) {
+                       $clientid = intval($this->Request['clientid']);
+                       $client_row = $this->getModule('client')->getClientById($clientid);
+                       if (is_object($client_row)) {
+                               $client = $client_row->name;
+                       }
                }
 
                if (is_null($client)) {
index b241029012c0d12f2939c41d9eff88d987624bea..c9b8f88a3ad7b612ea6a7321ada87370f2a2c8d1 100644 (file)
                                        }
                                },
                                "parameters": [
+                                       {
+                                               "name": "clientid",
+                                               "in": "query",
+                                               "description": "Client identifier (can be used instead of client value)",
+                                               "required": true,
+                                               "schema": {
+                                                       "type": "integer"
+                                               }
+                                       },
                                        {
                                                "name": "client",
                                                "in": "query",
-                                               "description": "Client name",
+                                               "description": "Client name (can be used instead clientid)",
                                                "required": true,
                                                "schema": {
                                                        "type": "string"
index 8d916f4df5717408236ab8c1a17c4d5bb24090c1..a0adc7c28afc265c6995159425962be1294d11bc 100644 (file)
@@ -31,7 +31,7 @@ Prado::using('System.Web.UI.WebControls.TClientScript');
  */
 class BClientScript extends TClientScript {
 
-       const SCRIPTS_VERSION = 7;
+       const SCRIPTS_VERSION = 8;
 
        public function getScriptUrl()
        {
index b89b018fa9a007211b2d65bdc993dc242d4c3b22..6fb1924352918c1b830335eb3b69958aab042f29 100644 (file)
@@ -643,6 +643,10 @@ var W3SideBar = {
        },
        init: function() {
                this.sidebar = document.getElementById(this.ids.sidebar);
+               if (!this.sidebar) {
+                       // don't initialize for pages without sidebar
+                       return;
+               }
                this.overlay_bg = document.getElementById(this.ids.overlay_bg);
                this.page_main = $(this.css.page_main);
                var hide = Cookies.get_cookie(this.cookies.side_bar_hide);
index d8361eb3c23e14b0670536ba5d600aef9135418a..f3c9d518e4637c506384499c1cf7ffa6a223e16b 100644 (file)
                                <%[ To start, please select backup Client which data you want to restore. ]%>
                        </p>
                        <div class="w3-container">
-                               <div class="w3-third"><com:TLabel ForControl="BackupClientName" Text="<%[ Backup from client: ]%>" /></div>
+                               <div class="w3-third"><com:TLabel ForControl="BackupClient" Text="<%[ Backup from client: ]%>" /></div>
                                <div class="w3-third">
-                                       <com:TDropDownList ID="BackupClientName" CssClass="w3-select w3-border" CausesValidation="false" />
+                                       <com:TDropDownList ID="BackupClient" CssClass="w3-select w3-border" CausesValidation="false" />
                                </div>
                        </div>
                        <div class="w3-container w3-section">
@@ -207,6 +207,7 @@ var oJobsToRestoreList = {
                var table = $('#' + this.ids.job_list).DataTable({
                        data: <%=json_encode(array_values($this->getPage()->jobs_to_restore))%>,
                        deferRender: true,
+                       stateSave: true,
                        columns: [
                                {
                                        className: 'details-control',
@@ -304,6 +305,9 @@ var oJobsToRestoreList = {
                                                        radio.name = 'backup_to_restore';
                                                        radio.value = data;
                                                        radio.className = 'w3-radio';
+                                                       if ('<%=$this->Session->contains('restore_jobid') ? $this->Session['restore_jobid'] : ''%>' == data) {
+                                                               radio.setAttribute('checked', 'checked');
+                                                       }
                                                        ret = radio.outerHTML;
                                                } else {
                                                        ret = data;
@@ -407,7 +411,7 @@ oJobsToRestoreList.init();
                                                </prop:ClientSide.OnLoading>
                                                <prop:ClientSide.OnComplete>
                                                        document.getElementById('restore-browser-files-loading').style.display = 'none';
-                                                       make_draggable('<%=$this->getPage()->DataGridFiles->ClientID%>');
+                                                       make_draggable('restore-browser-files-content');
                                                </prop:ClientSide.OnComplete>
                                                <i class="fa fa-check"></i> &nbsp;<%[ OK ]%>
                                        </com:TActiveLinkButton>
@@ -418,66 +422,155 @@ oJobsToRestoreList.init();
                                        <td rowspan="2" style="height: 100%">
                                                <div id="restore-browser-files-loading" style="display: none"></div>
                                                <div id="restore-browser-files" class="w3-border">
-                                               <com:TActiveDataGrid
-                                                       ID="DataGridFiles"
-                                                       AutoGenerateColumns="false"
-                                                       CellPadding="2px"
-                                                       ShowHeader="false"
-                                                       CssClass="file-browser-detail"
-                                                       ItemStyle.CssClass="file-browser-element"
-                                                       DataKeyField="uniqid"
-                                                       >
-                                                               <prop:EmptyTemplate>
-                                                                       <div class="file-browser-watermark">
-                                                                               <%[ It seems that there is no files for choosing or file records in database for this job has been purged (file retention period expired) ]%>
-                                                                       </div>
-                                                               </prop:EmptyTemplate>
-                                                               <com:TActiveTemplateColumn>
-                                                                       <prop:ItemTemplate>
-                                                                               <com:TPanel ID="FileElementLeft" CssClass="draggable">
-                                                                                       <i class="fas fa-<%=($this->getParent()->Data['type'] == 'dir' ? 'folder w3-text-green' : 'file-alt w3-text-gray')%> item_icon" alt="<%=$this->getParent()->Data['type'] == 'dir' ? 'directory' : 'file' %>"></i> <%=($this->getParent()->Data['name'] != '/') ? preg_replace('/\/$/', '', $this->getParent()->Data['name']) : '/'%>
-                                                                               <div class="restore-browser-element-size">
-                                                                                       <com:TActiveLinkButton
-                                                                                               CssClass="link"
-                                                                                               Style="float: right;"
-                                                                                               OnCallback="Page.addFileToRestore"
-                                                                                               ActiveControl.CallbackParameter="<%=$this->getParent()->Data['uniqid']%>"
-                                                                                               ActiveControl.EnableUpdate="false"
-                                                                                               Visible="<%=!in_array($this->getParent()->Data['name'], $this->getPage()->excluded_elements_from_add)%>"
-                                                                                               ClientSide.OnComplete="Formatters.set_formatters();"
-                                                                                               Text="<%[ Add ]%>"
-                                                                                       />
-                                                                                       <span class="size" style=""><%=isset($this->getParent()->Data['lstat']['size']) ? $this->getParent()->Data['lstat']['size'] : '0'%></span>
-                                                                               </div>
-                                                                               </com:TPanel>
-                                                                               <script type="text/javascript">
-                                                                                       document.getElementById('<%=$this->FileElementLeft->ClientID%>').addEventListener('click', function(event) {
-                                                                                               var el = event.target || event.srcElement;
-                                                                                               if (el.className == 'link') {
-                                                                                                       // 'Add' link doesn't cause sending request
-                                                                                                       return;
-                                                                                               }
-                                                                                               var vposition = el.style.left;
-                                                                                               if(vposition == null || vposition == '0px'){
-                                                                                                       event.stop();
-                                                                                               } else {
-                                                                                                       var cbp = "<%=$this->getParent()->Data['name']%>|<%=@$this->getParent()->Data['pathid']%>|<%=@$this->getParent()->Data['filenameid']%>|<%=@$this->getParent()->Data['jobid']%>";
-                                                                                                       var request = <%=$this->getPage()->FileElementCall->ActiveControl->Javascript %>;
-                                                                                                       request.setCallbackParameter(cbp);
-                                                                                                       var ocf = request.options.onComplete;
-                                                                                                       request.options.onComplete = function() {
-                                                                                                               ocf();
-                                                                                                               Formatters.set_formatters();
-                                                                                                               make_draggable();
-                                                                                                       };
-                                                                                                       request.dispatch();
-                                                                                               }
-                                                                                       });
-                                                                               </script>
-                                                                       </prop:ItemTemplate>
-                                                               </com:TActiveTemplateColumn>
-                                               </com:TActiveDataGrid>
-                                               <com:TCallback ID="FileElementCall" OnCallback="Page.getVersions">
+                                                       <div id="restore-browser-files-content"></div>
+                                               </div>
+<script>
+var oRestoreBrowserFiles = {
+       ids: {
+               content: 'restore-browser-files-content'
+       },
+       cls: {
+               draggable: 'draggable',
+               watermark: 'file-browser-watermark',
+               folder: 'fas fa-folder',
+               file: 'fas fa-file-alt',
+               item_icon: 'item_icon',
+               green: 'w3-text-green',
+               gray: 'w3-text-gray',
+               item: 'file-browser-element',
+               item_right: 'restore-browser-element-right',
+               link: 'link',
+               size: 'size'
+       },
+       txts: {
+               no_files: '<%[ It seems that there is no files for choosing or file records in database for this job has been purged (file retention period expired) ]%>',
+               add: '<%[ Add ]%>'
+       },
+       types: {
+               directory: 'dir',
+               file: 'file',
+       },
+       excluded_items: ['.', '..'],
+       init: function(items) {
+               this.load_items();
+       },
+       load_items: function() {
+               var cb = <%=$this->SetBrowserFiles->ActiveControl->Javascript%>;
+               cb.dispatch();
+       },
+       populate: function(items) {
+               oRestoreBrowserFiles.clear_browser();
+               if (!Array.isArray(items) || items.length === 0) {
+                       oRestoreBrowserFiles.add_empty_item();
+               } else {
+                       for (var i = 0; i < items.length; i++) {
+                               oRestoreBrowserFiles.add_item(items[i]);
+                       }
+               }
+               make_draggable();
+       },
+       add_empty_item: function() {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = this.cls.watermark;
+               div.textContent = this.txts.no_files;
+               container.appendChild(div);
+       },
+       add_item: function(item) {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = [
+                       this.cls.item,
+                       this.cls.draggable
+               ].join(' ');
+               div.setAttribute('data-source', 'file_browser');
+               div.setAttribute('data-uniqid', item.uniqid);
+               div.addEventListener('click', function(e) {
+                       var el = event.target || event.srcElement;
+                       if (el.className == this.cls.link) {
+                               // 'Add' link doesn't cause sending request
+                               return;
+                       }
+                       var vposition = el.style.left;
+                       if(vposition == null || vposition == '0px'){
+                               event.stop();
+                       } else {
+                               var cbp = [item.name, item.pathid, item.filenameid, item.jobid].join('|');
+                               var request = <%=$this->getPage()->GetVersions->ActiveControl->Javascript%>;
+                               request.setCallbackParameter(cbp);
+                               var ocf = request.options.onComplete;
+                               request.options.onComplete = function() {
+                                       ocf();
+                                       Formatters.set_formatters();
+                                       make_draggable();
+                               };
+                               request.dispatch();
+                       }
+               }.bind(this));
+               var i = document.createElement('I');
+               if (item.type === this.types.directory) {
+                       i.className = [
+                               this.cls.folder,
+                               this.cls.green,
+                               this.cls.item_icon
+                       ].join(' ');
+               } else if (item.type === this.types.file) {
+                       i.className = [
+                               this.cls.file,
+                               this.cls.gray,
+                               this.cls.item_icon
+                       ].join(' ');
+               }
+               var txt = item.name;
+               if (txt != '/') {
+                       txt = txt.replace(/\/$/, '');
+               }
+               txt = document.createTextNode(' ' + txt);
+               var right = document.createElement('DIV');
+               right.className = this.cls.item_right;
+               if (this.excluded_items.indexOf(item.name) === -1) {
+                       var link = document.createElement('A');
+                       link.href = 'javascript:void(0)';
+                       link.className = 'link';
+                       var link_label = document.createTextNode(this.txts.add);
+                       link.appendChild(link_label);
+                       link.style.float = 'right';
+                       right.appendChild(link);
+                       link.addEventListener('click', function(e) {
+                               var cb = <%=$this->AddFileToRestore->ActiveControl->Javascript%>;
+                               var param = ['file_browser', item.uniqid].join('|');
+                               cb.setCallbackParameter(param);
+                               cb.dispatch();
+                       });
+               }
+               var size = document.createElement('SPAN');
+               size.className = this.cls.size;
+               var lss = item.lstat ? item.lstat.size : 0;
+               size.textContent = lss;
+               right.appendChild(size);
+               div.appendChild(i);
+               div.appendChild(txt);
+               div.appendChild(right);
+               container.appendChild(div);
+       },
+       clear_browser: function() {
+               var container = document.getElementById(this.ids.content);
+               while (container.firstChild) {
+                       container.removeChild(container.firstChild);
+               }
+       }
+};
+$(function() {
+       oRestoreBrowserFiles.init();
+});
+</script>
+                                               <com:TCallback ID="SetBrowserFiles" OnCallback="Page.loadBrowserFiles" />
+                                               <com:TCallback ID="AddFileToRestore" OnCallback="Page.addFileToRestore">
+                                                       <prop:ClientSide.OnComplete>
+                                                               Formatters.set_formatters();
+                                                       </prop:ClientSide.OnComplete>
+                                               </com:TCallback>
+                                               <com:TCallback ID="GetVersions" OnCallback="Page.getVersions">
                                                        <prop:ClientSide.OnLoading>
                                                                document.getElementById('restore-browser-files-loading').style.display = 'block';
                                                        </prop:ClientSide.OnLoading>
@@ -485,63 +578,155 @@ oJobsToRestoreList.init();
                                                                document.getElementById('restore-browser-files-loading').style.display = 'none';
                                                        </prop:ClientSide.OnComplete>
                                                </com:TCallback>
-                                               </div>
                                        </td>
                                        <td style="height: 50%">
                                                <div id="restore-browser-versions" class="w3-border" style="position: relative">
-                                                       <com:TActiveDataGrid
-                                                               ID="VersionsDataGrid"
-                                                               ShowHeader="false"
-                                                               AutoGenerateColumns="false"
-                                                               CellPadding="2px"
-                                                               CssClass="file-browser-detail"
-                                                               ItemStyle.CssClass="file-browser-element"
-                                                               DataKeyField="uniqid"
-                                                       >
-                                                               <prop:EmptyTemplate>
-                                                                       <div class="file-browser-watermark">
-                                                                               <%[ To see file versions please click a file on the left files browser. ]%>
-                                                                       </div>
-                                                               </prop:EmptyTemplate>
-                                                               <com:TActiveTemplateColumn>
-                                                                       <prop:ItemTemplate>
-                                                                               <com:TPanel ID="FileElementToRestore" CssClass="draggable" Style="height: 28px;">
-                                                                                       <span class="w3-third">
-                                                                                               <i class="fas fa-<%=($this->getParent()->Data['type'] == 'dir' ? 'folder w3-text-green' : 'file-alt w3-text-gray')%> item_icon" alt="<%=$this->getParent()->Data['type'] == 'dir' ? 'directory' : 'file'%>"></i>
-                                                                                                <%=$this->getParent()->Data['name']%>
-                                                                                       </span>
-                                                                                       <span class="w3-third">
-                                                                                               MTIME:<%=date("Y-m-d H:i:s", $this->getParent()->Data['lstat']['mtime'])%>
-                                                                                       </span>
-                                                                                       <span class="w3-third">
-                                                                                               <%[ Size: ]%>
-                                                                                               <span class="size"><%=$this->getParent()->Data['lstat']['size']%></span>
-                                                                                       <com:TActiveLinkButton
-                                                                                               CssClass="link"
-                                                                                               Style="float: right;"
-                                                                                               OnCallback="Page.addFileToRestore"
-                                                                                               ActiveControl.CallbackParameter="<%=$this->getParent()->Data['uniqid']%>"
-                                                                                               ActiveControl.EnableUpdate="false"
-                                                                                               ClientSide.OnComplete="Formatters.set_formatters();"
-                                                                                               Text="<%[ Add ]%>"
-                                                                                       />
-                                                                                       </span>
-                                                                               </com:TPanel>
-                                                                               <script type="text/javascript">
-                                                                                       document.getElementById('<%=$this->FileElementToRestore->ClientID%>').addEventListener('mouseover', function(event) {
-                                                                                               var tip_fields = [
-                                                                                                       '<%[ JobId: ]%> <%=$this->getParent()->Data['jobid']%>',
-                                                                                                       '<%[ Volume: ]%> <%=$this->getParent()->Data['volname']%>',
-                                                                                                       '<%[ InChanger: ]%> <%=$this->getParent()->Data['inchanger'] ? Prado::localize('Yes') : Prado::localize('No')%>',
-                                                                                                       '<%[ Sum: ]%> <%=$this->getParent()->Data['md5']%>'
-                                                                                               ];
-                                                                                               showTip(this, '<%=$this->getParent()->Data['name']%>', tip_fields.join('<br />'));
-                                                                                       });
-                                                                               </script>
-                                                                       </prop:ItemTemplate>
-                                                               </com:TActiveTemplateColumn>
-                                                       </com:TActiveDataGrid>
-                                                       </div>
+                                                       <div id="restore-browser-versions-content" class="file-browser-detail"></div>
+                                               </div>
+<script>
+var oRestoreBrowserVersions = {
+       ids: {
+               content: 'restore-browser-versions-content'
+       },
+       cls: {
+               draggable: 'draggable',
+               watermark: 'file-browser-watermark',
+               file: 'fas fa-file-alt',
+               item_icon: 'item_icon',
+               gray: 'w3-text-gray',
+               third: 'w3-third',
+               item: 'file-browser-element',
+               item_right: 'restore-browser-element-right',
+               size: 'size',
+               link: 'link'
+       },
+       txts: {
+               no_files: '<%[ To see file versions please click a file on the left files browser. ]%>',
+               add: '<%[ Add ]%>',
+               jobid: '<%[ JobId: ]%>',
+               volume: '<%[ Volume: ]%>',
+               inchanger: '<%[ InChanger: ]%>',
+               sum: '<%[ Sum: ]%>',
+               yes: '<%[ Yes ]%>',
+               no: '<%[ No ]%>'
+       },
+       types: {
+               file: 'file'
+       },
+       init: function() {
+               this.load_items();
+       },
+       load_items: function() {
+               var cb = <%=$this->SetFileVersions->ActiveControl->Javascript%>;
+               cb.dispatch();
+       },
+       populate: function(items) {
+               oRestoreBrowserVersions.clear_browser();
+               if (!Array.isArray(items) || items.length === 0) {
+                       oRestoreBrowserVersions.add_empty_item();
+               } else {
+                       for (var i = 0; i < items.length; i++) {
+                               oRestoreBrowserVersions.add_item(items[i]);
+                       }
+               }
+               make_draggable();
+       },
+       add_empty_item: function() {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = this.cls.watermark;
+               div.textContent = this.txts.no_files;
+               container.appendChild(div);
+       },
+       add_item: function(item) {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = [
+                       this.cls.item,
+                       this.cls.draggable
+               ].join(' ');
+               div.style.height = '32px';
+               div.setAttribute('data-source', 'version_browser');
+               div.setAttribute('data-uniqid', item.uniqid);
+
+               // file name
+               var span_name = document.createElement('SPAN');
+               span_name.className = this.cls.third;
+               span_name.style.wordBreak = 'break-all';
+               var i = document.createElement('I');
+               if (item.type === this.types.file) {
+                       i.className = [
+                               this.cls.file,
+                               this.cls.gray,
+                               this.cls.item_icon
+                       ].join(' ');
+               }
+               var name = (item.name.length > 60) ? item.name.substr(0, 57) + '...' : item.name;
+               span_name.setAttribute('title', item.name);
+               name = document.createTextNode(' ' + name);
+               span_name.appendChild(i);
+               span_name.appendChild(name);
+
+               // file mtime
+               var span_mtime = document.createElement('SPAN');
+               span_mtime.className = this.cls.third;
+               var mtime = 'MTIME: ' + (item.lstat ? Units.format_date(item.lstat.mtime) : 0);
+               mtime = document.createTextNode(mtime);
+               span_mtime.appendChild(mtime);
+
+               // file size and add button
+               var span_size = document.createElement('SPAN');
+               span_size.className = this.cls.third;
+               var span_size_cont = document.createElement('SPAN');
+               span_size_cont.className = this.cls.size;
+               var size_label = document.createTextNode('<%[ Size: ]%> ');
+               var lsize = item.lstat ? item.lstat.size : 0;
+               var size = document.createTextNode(lsize);
+               span_size_cont.appendChild(size);
+               span_size.appendChild(size_label);
+               span_size.appendChild(span_size_cont);
+
+               var link = document.createElement('A');
+               link.href = 'javascript:void(0)';
+               link.className = this.cls.link;
+               link.style.float = 'right';
+               var link_label = document.createTextNode(this.txts.add);
+               link.appendChild(link_label);
+               span_size.appendChild(link);
+               link.addEventListener('click', function(e) {
+                       var cb = <%=$this->AddFileToRestore->ActiveControl->Javascript%>;
+                       var param = ['version_browser', item.uniqid].join('|');
+                       cb.setCallbackParameter(param);
+                       cb.dispatch();
+               });
+
+               div.addEventListener('mouseover', function() {
+                       var tip_fields = [
+                               this.txts.jobid + ' ' + item.jobid,
+                               this.txts.volume + ' ' + item.volname,
+                               this.txts.inchanger + ' ' + (item.inchanger === '1' ? this.txts.yes : this.txts.no),
+                               this.txts.sum + ' ' + item.md5
+                       ];
+                       showTip(div, item.name, tip_fields.join('<br />'));
+               }.bind(this));
+
+               div.appendChild(span_name);
+               div.appendChild(span_mtime);
+               div.appendChild(span_size);
+               container.appendChild(div);
+       },
+       clear_browser: function() {
+               var container = document.getElementById(this.ids.content);
+               while (container.firstChild) {
+                       container.removeChild(container.firstChild);
+               }
+       }
+};
+$(function() {
+       oRestoreBrowserVersions.init();
+});
+</script>
+                                               <com:TCallback ID="SetFileVersions" OnCallback="Page.loadFileVersions" />
                                        </td>
                                </tr>
                                <tr>
@@ -552,51 +737,163 @@ oJobsToRestoreList.init();
                                                                OnCallback="removeSelectedFile"
                                                                ClientSide.OnComplete="set_formatters();"
                                                        />
-                                                       <script type="text/javascript">
-                                                               function remove_selected_item(uniqid) {
-                                                                       var cb = <%=$this->RemoveSelectedItem->ActiveControl->Javascript%>;
-                                                                       cb.setCallbackParameter(uniqid);
-                                                                       cb.dispatch();
-                                                               }
-                                                       </script>
-                                                       <com:TJuiDroppable ID="SelectedVersionsDropper" Height="100%" Width="100%"
-                                                               Options.accept=".draggable"
-                                                               OnDrop="addFileToRestore"
-                                                               OnDeactivate="callFormatters"
-                                                               >
-                                                                       <com:TActiveDataGrid
-                                                                               ID="SelectedVersionsDataGrid"
-                                                                               ShowHeader="false"
-                                                                               AutoGenerateColumns="false"
-                                                                               CellPadding="2px"
-                                                                               CssClass="file-browser-detail"
-                                                                               ItemStyle.CssClass="file-browser-element"
-                                                                               DataKeyField="uniqid"
-                                                                       >
-                                                                       <prop:EmptyTemplate>
-                                                                               <div class="file-browser-watermark">
-                                                                                       <%[ To add a file to restore please click 'Add' link or please drag here the file from the top frame or from the frame on the left. ]%>
-                                                                               </div>
-                                                                       </prop:EmptyTemplate>
-                                                                       <com:TActiveTemplateColumn>
-                                                                               <prop:ItemTemplate>
-                                                                                               <com:TPanel ID="FileElement" Style="clear: both">
-                                                                                                       <span class="w3-third">
-                                                                                                               <i class="fas fa-<%=($this->getParent()->Data['type'] == 'dir' ? 'folder w3-text-green' : 'file-alt w3-text-gray')%> item_icon" title="<%=$this->getParent()->Data['type'] == 'dir' ? 'directory' : 'file'%>"></i>
-                                                                                                               <%=$this->getParent()->Data['name']%>
-                                                                                                       </span>
-                                                                                                       <span class="w3-third">
-                                                                                                               MTIME:<%=is_array($this->getParent()->Data['lstat']) ? date("Y-m-d H:i:s", $this->getParent()->Data['lstat']['mtime']) : '-'%>
-                                                                                                       </span>
-                                                                                                       <span class="w3-third">
-                                                                                                               <%[ Size: ]%><span class="size"><%=is_array($this->getParent()->Data['lstat']) ? $this->getParent()->Data['lstat']['size'] : '0'%></span>
-                                                                                                               <a href="javascript:void(0)" class="w3-right remove_selected_item" onclick="remove_selected_item('<%=$this->getParent()->Data['uniqid']%>'); return false;"><i class="fa fa-trash-alt item_selected_del_btn"></i></a>
-                                                                                                       </span>
-                                                                                               </com:TPanel>
-                                                                               </prop:ItemTemplate>
-                                                                       </com:TActiveTemplateColumn>
-                                                                       </com:TActiveDataGrid>
-                                                               </com:TJuiDroppable>
+                                                       <div id="restore-browser-selected-files" class="file-browser-detail" style="width: 100%; height: 100%; position: relative;"></div>
+<script>
+var oRestoreBrowserSelectedFiles = {
+       ids: {
+               content: 'restore-browser-selected-files'
+       },
+       cls: {
+               watermark: 'file-browser-watermark',
+               folder: 'fas fa-folder',
+               file: 'fas fa-file-alt',
+               trash: 'fa fa-trash-alt',
+               gray: 'w3-text-gray',
+               green: 'w3-text-green',
+               third: 'w3-third',
+               right: 'w3-right',
+               item: 'file-browser-element',
+               item_icon: 'item_icon',
+               size: 'size',
+               link: 'link',
+               rm_sel_item: 'remove_selected_item',
+               item_sel_btn: 'item_selected_del_btn'
+       },
+       txts: {
+               no_files: "<%[ To add a file to restore please click 'Add' link or please drag here the file from the top frame or from the frame on the left. ]%>"
+       },
+       types: {
+               directory: 'dir',
+               file: 'file'
+       },
+       init: function() {
+               this.load_items();
+               this.init_browser();
+       },
+       init_browser: function() {
+               $('#' + this.ids.content).droppable({
+                       accept: '.draggable',
+                       drop: function(e, ui) {
+                               var source = ui.draggable.attr('data-source');
+                               var uniqid = ui.draggable.attr('data-uniqid');
+                               var param = [source, uniqid].join('|');
+                               var selected_versions_cb = <%=$this->AddFileToRestore->ActiveControl->Javascript%>;
+                               selected_versions_cb.setCallbackParameter(param);
+                               selected_versions_cb.dispatch();
+                       }
+               });
+       },
+       load_items: function() {
+               var cb = <%=$this->SetBrowserSelectedFiles->ActiveControl->Javascript%>;
+               cb.dispatch();
+       },
+       add_empty_item: function() {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = this.cls.watermark;
+               div.textContent = this.txts.no_files;
+               container.appendChild(div);
+       },
+       populate: function(items) {
+               oRestoreBrowserSelectedFiles.clear_browser();
+               if (!Array.isArray(items) || items.length === 0) {
+                       oRestoreBrowserSelectedFiles.add_empty_item();
+               } else {
+                       for (var i = 0; i < items.length; i++) {
+                               oRestoreBrowserSelectedFiles.add_item(items[i]);
+                       }
+               }
+       },
+       add_item: function(item) {
+               var container = document.getElementById(this.ids.content);
+               var div = document.createElement('DIV');
+               div.className = this.cls.item;
+               div.style.height = '32px';
+               div.setAttribute('data-uniqid', item.uniqid);
+
+               // file name
+               var span_name = document.createElement('SPAN');
+               span_name.className = this.cls.third;
+               span_name.style.wordBreak = 'break-all';
+               var i = document.createElement('I');
+               if (item.type === this.types.file) {
+                       i.className = [
+                               this.cls.file,
+                               this.cls.gray,
+                               this.cls.item_icon
+                       ].join(' ');
+               } else if (item.type === this.types.directory) {
+                       i.className = [
+                               this.cls.folder,
+                               this.cls.green,
+                               this.cls.item_icon
+                       ].join(' ');
+               }
+               var txt = item.name;
+               if (txt != '/') {
+                       txt = txt.replace(/\/$/, '');
+               }
+               var name = (txt.length > 60) ? txt.substr(0, 57) + '...' : txt;
+               span_name.setAttribute('title', txt);
+               name = document.createTextNode(' ' + name);
+               span_name.appendChild(i);
+               span_name.appendChild(name);
+
+               // file mtime
+               var span_mtime = document.createElement('SPAN');
+               span_mtime.className = this.cls.third;
+               var mtime = 'MTIME: ' + (item.lstat ? Units.format_date(item.lstat.mtime) : 0);
+               mtime = document.createTextNode(mtime);
+               span_mtime.appendChild(mtime);
+
+               // file size and add button
+               var span_size = document.createElement('SPAN');
+               span_size.className = this.cls.third;
+               var span_size_cont = document.createElement('SPAN');
+               span_size_cont.className = this.cls.size;
+               var size_label = document.createTextNode('<%[ Size: ]%> ');
+               var lsize = item.lstat ? item.lstat.size : 0;
+               var size = document.createTextNode(lsize);
+               span_size_cont.appendChild(size);
+               span_size.appendChild(size_label);
+               span_size.appendChild(span_size_cont);
+
+               var link = document.createElement('A');
+               link.href = 'javascript:void(0)';
+               link.className = [
+                       this.cls.link,
+                       this.cls.right
+               ].join(' ');
+               i  = document.createElement('I');
+               i.className = [
+                       this.cls.trash,
+                       this.cls.item_sel_btn
+               ].join(' ');
+               link.appendChild(i);
+               span_size.appendChild(link);
+               link.addEventListener('click', function(e) {
+                       var cb = <%=$this->RemoveSelectedItem->ActiveControl->Javascript%>;
+                       cb.setCallbackParameter(item.uniqid);
+                       cb.dispatch();
+               });
+
+               div.appendChild(span_name);
+               div.appendChild(span_mtime);
+               div.appendChild(span_size);
+               container.appendChild(div);
+       },
+       clear_browser: function() {
+               var container = document.getElementById(this.ids.content);
+               while (container.firstChild) {
+                       container.removeChild(container.firstChild);
+               }
+       }
+};
+$(function() {
+       oRestoreBrowserSelectedFiles.init();
+});
+</script>
+                                               <com:TCallback ID="SetBrowserSelectedFiles" OnCallback="Page.loadSelectedFiles" />
                                                </div>
                                        </td>
                                </tr>
@@ -633,7 +930,7 @@ oJobsToRestoreList.init();
                                        set_browser_sizes();
                                });
                                set_browser_sizes();
-                               make_draggable('<%=$this->getPage()->DataGridFiles->ClientID%>');
+                               make_draggable('restore-browser-files-content');
                                Formatters.set_formatters();
                        </script>
                </com:TWizardStep>
@@ -757,7 +1054,7 @@ oJobsToRestoreList.init();
                                <legend><%[ Source parameters ]%></legend>
                                <div class="w3-section w3-row">
                                        <div class="w3-col w3-third"><%[ Backup data from client: ]%></div>
-                                       <div class="w3-col w3-third bold"><%=$this->BackupClientName->SelectedValue%></div>
+                                       <div class="w3-col w3-third bold"><%=$this->BackupClient->SelectedItem->Text%></div>
                                </div>
                                <div class="w3-section w3-row">
                                        <div class="w3-col w3-third"><%[ Backup selection method: ]%></div>
@@ -792,7 +1089,7 @@ oJobsToRestoreList.init();
                                <legend><%[ Destination parameters ]%></legend>
                                <div class="w3-section w3-row">
                                        <div class="w3-col w3-third"><%[ Restore to client: ]%></div>
-                                       <div class="w3-col w3-third bold"><%=$this->RestoreClient->SelectedValue%></div>
+                                       <div class="w3-col w3-third bold"><%=$this->RestoreClient->SelectedItem->Text%></div>
                                </div>
                                <div class="w3-section w3-row">
                                        <div class="w3-col w3-third"><%[ Restore to path: ]%></div>
index 602d2188c8e995d3588800d023b468216111f9fa..67f20faf5b6fe82248242024ae79cafba604bf42 100644 (file)
@@ -3,7 +3,7 @@
  * Bacula(R) - The Network Backup Solution
  * Baculum   - Bacula web interface
  *
- * Copyright (C) 2013-2019 Kern Sibbald
+ * Copyright (C) 2013-2020 Kern Sibbald
  *
  * The main author of Baculum is Marcin Haba.
  * The original author of Bacula is Kern Sibbald, with contributions
@@ -44,34 +44,36 @@ class RestoreWizard extends BaculumWebPage
         * Job levels allowed to restore.
         */
 
-       private $joblevel = array('F', 'I', 'D');
+       private $joblevel = ['F', 'I', 'D'];
+
        /**
         * Job statuses allowed to restore.
         */
-       private $jobstatus = array('T', 'W', 'A', 'E', 'e', 'f');
+       private $jobstatus = ['T', 'W', 'A', 'E', 'e', 'f'];
 
        /**
         * File browser special directories.
         */
-       private $browser_root_dir = array(
+       private $browser_root_dir = [
                'name' => '.',
                'type' => 'dir',
                'fileid' => null,
+               'pathid' => null,
+               'filenameid' => null,
+               'jobid' => null,
                'lstat' => '',
                'uniqid' => null
-       );
-       private $browser_up_dir = array(
+       ];
+       private $browser_up_dir = [
                'name' => '..',
                'type' => 'dir',
                'fileid' => null,
+               'pathid' => null,
+               'filenameid' => null,
+               'jobid' => null,
                'lstat' => '',
                'uniqid' => null
-       );
-
-       /**
-        * Used to provide in template selected by user single jobid to restore.
-        */
-       public $restore_single_jobid;
+       ];
 
        /**
         * Stores file relocation option. Used in template.
@@ -79,12 +81,13 @@ class RestoreWizard extends BaculumWebPage
        public $file_relocation_opt;
 
        /**
-        * FIle browser elements for which 'Add' button is unavailable.
+        * Stores list of jobs possible to select to restore.
         */
-       public $excluded_elements_from_add = array('.', '..');
-
        public $jobs_to_restore;
 
+       /**
+        * If set to true, show modal with error message about problem during restore start.
+        */
        public $show_error = false;
 
        /**
@@ -92,35 +95,48 @@ class RestoreWizard extends BaculumWebPage
         */
        const BVFS_PATH_PREFIX = 'b2';
 
+       /**
+        * Initialize restore page.
+        *
+        * @param TXmlElement $param page config
+        * @return none
+        */
        public function onInit($param) {
                parent::onInit($param);
-               if (!$this->IsPostBack && !$this->IsCallBack) {
-                       $this->resetWizard();
-                       $this->loadBackupClients();
-                       $this->setPreDefinedJobIdToRestore();
+               if ($this->IsPostBack || $this->IsCallBack) {
+                       return;
+               }
+               $this->resetWizard();
+               $this->loadBackupClients();
+               if ($this->Request->contains('jobid')) {
+                       $this->setJobIdToRestore($this->Request['jobid']);
                }
        }
 
+       /**
+        * On pre-render action.
+        *
+        * @param TXmlElement $param page config
+        * @return none
+        */
        public function onPreRender($param) {
                parent::onPreRender($param);
                $this->setNavigationButtons();
        }
 
        /**
-        * Set pre-defined jobid to restore.
+        * Set jobid to restore.
         * Used to restore specific job by jobid.
         *
         * @return none
         */
-       public function setPreDefinedJobIdToRestore() {
-               if ($this->Request->contains('jobid')) {
-                       $jobid = intval($this->Request['jobid']);
-                       $this->setRestoreByJobId($jobid);
-                       $this->RestoreWizard->setActiveStep($this->Step3);
-                       $param = new stdClass;
-                       $param->CurrentStepIndex = 1;
-                       $this->RestoreWizard->raiseEvent('OnNextButtonClick', null, $param);
-               }
+       public function setJobIdToRestore($jobid) {
+               $jobid = intval($jobid);
+               $this->setRestoreByJobId($jobid);
+               $this->RestoreWizard->setActiveStep($this->Step3);
+               $param = new stdClass;
+               $param->CurrentStepIndex = 1;
+               $this->RestoreWizard->raiseEvent('OnNextButtonClick', null, $param);
        }
 
        /**
@@ -129,20 +145,18 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function setRestoreByJobId($jobid) {
-               $_SESSION['restore_single_jobid'] = $jobid;
-               $job = $this->getModule('api')->get(array('jobs', $_SESSION['restore_single_jobid']))->output;
+               $this->Session->add('restore_jobid', $jobid);
+               $job = $this->getModule('api')->get(
+                       ['jobs', $jobid]
+               )->output;
                if (is_object($job)) {
                        $this->loadRestoreClients();
-                       $client = $this->getBackupClient($job->clientid);
-                       // client is null for restore backup from deleted clients in catalog
-                       if (!is_null($client)) {
-                               $this->BackupClientName->SelectedValue = $client;
-                               $this->RestoreClient->SelectedValue = $client;
-                               $this->loadBackupsForClient();
-                               $step_index = new stdClass;
-                               $step_index->CurrentStepIndex = 3;
-                               $this->wizardNext(null, $step_index);
-                       }
+                       $this->BackupClient->SelectedValue = $job->clientid;
+                       $this->RestoreClient->SelectedValue = $job->clientid;
+                       $this->loadBackupsForClient();
+                       $step_index = new stdClass;
+                       $step_index->CurrentStepIndex = 3;
+                       $this->wizardNext(null, $step_index);
                }
        }
 
@@ -174,31 +188,36 @@ class RestoreWizard extends BaculumWebPage
                        $this->loadGroupBackupToRestore();
                        $this->loadGroupFileSetToRestore();
                        $this->loadRestoreClients();
-                       if (isset($_SESSION['restore_single_jobid'])) {
-                               $this->restore_single_jobid = $_SESSION['restore_single_jobid'];
+                       if ($this->BackupClient->DataChanged) {
+                               // remove previous restore jobid only if user changed client selection
+                               $this->Session->remove('restore_jobid');
                        }
                } elseif ($param->CurrentStepIndex === 1) {
                        if ($this->Request->contains('backup_to_restore')) {
-                               $_SESSION['restore_single_jobid'] = $this->Request['backup_to_restore'];
-                       }
-                       if (isset($_SESSION['restore_path'])) {
-                               $_SESSION['restore_path'] = array();
+                               $this->Session->add(
+                                       'restore_jobid',
+                                       $this->Request['backup_to_restore']
+                               );
                        }
+                       $this->setRestorePath();
                        $this->setFileVersions();
-                       $this->loadSelectedFiles();
-                       $this->loadFileVersions();
+                       $this->loadSelectedFiles(null, null);
+                       $this->loadFileVersions(null, null);
                        $this->goToPath();
                } elseif ($param->CurrentStepIndex === 2) {
                        $this->loadRequiredVolumes();
                } elseif ($param->CurrentStepIndex === 3) {
-                       if (isset($_SESSION['file_relocation'])) {
-                               $this->file_relocation_opt = $_SESSION['file_relocation'];
+                       if ($this->Session->contains('file_relocation')) {
+                               $this->file_relocation_opt = $this->Session['file_relocation'];
                        }
                } elseif ($param->CurrentStepIndex === 4) {
                        if ($this->Request->contains('file_relocation')) {
-                               $_SESSION['file_relocation'] = $this->Request['file_relocation'];
+                               $this->Session->add(
+                                       'file_relocation',
+                                       $this->Request['file_relocation']
+                               );
                        }
-                       $this->file_relocation_opt = $_SESSION['file_relocation'];
+                       $this->file_relocation_opt = $this->Session['file_relocation'];
                }
                $this->setNavigationButtons();
        }
@@ -211,16 +230,15 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function wizardPrev($sender, $param) {
-               if ($param->CurrentStepIndex === 2) {
-                       $this->restore_single_jobid = $_SESSION['restore_single_jobid'];
+               if ($param->CurrentStepIndex === 1) {
+               } elseif ($param->CurrentStepIndex === 2) {
                        $this->loadBackupsForClient();
                } elseif ($param->CurrentStepIndex === 3) {
-                       $this->setFileVersions();
-                       $this->loadSelectedFiles();
-                       $this->loadFileVersions();
+                       $this->loadSelectedFiles(null, null);
+                       $this->loadFileVersions(null, null);
                        $this->goToPath();
                } elseif ($param->CurrentStepIndex === 5) {
-                       $this->file_relocation_opt = $_SESSION['file_relocation'];
+                       $this->file_relocation_opt = $this->Session['file_relocation'];
                }
        }
 
@@ -242,14 +260,18 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function loadBackupClients() {
-               $client_list = array();
-               $clients = $this->getModule('api')->get(array('clients'))->output;
-               for ($i = 0; $i < count($clients); $i++) {
-                       $client_list[$clients[$i]->name] = $clients[$i]->name;
+               $client_list = [];
+               $clients = $this->getModule('api')->get(
+                       ['clients']
+               )->output;
+               if (is_array($clients)) {
+                       for ($i = 0; $i < count($clients); $i++) {
+                               $client_list[$clients[$i]->clientid] = $clients[$i]->name;
+                       }
+                       asort($client_list);
                }
-               asort($client_list);
-               $this->BackupClientName->dataSource = $client_list;
-               $this->BackupClientName->dataBind();
+               $this->BackupClient->DataSource = $client_list;
+               $this->BackupClient->dataBind();
        }
 
        /**
@@ -258,13 +280,18 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function loadRestoreClients() {
-               $client_list = array();
-               $clients = $this->getModule('api')->get(array('clients'))->output;
-               for ($i = 0; $i < count($clients); $i++) {
-                       $client_list[$clients[$i]->name] = $clients[$i]->name;
+               $client_list = [];
+               $clients = $this->getModule('api')->get(
+                       ['clients']
+               )->output;
+               if (is_array($clients)) {
+                       for ($i = 0; $i < count($clients); $i++) {
+                               $client_list[$clients[$i]->clientid] = $clients[$i]->name;
+                       }
+                       asort($client_list);
                }
-               $this->RestoreClient->SelectedValue = $this->BackupClientName->SelectedValue;
-               $this->RestoreClient->dataSource = $client_list;
+               $this->RestoreClient->DataSource = $client_list;
+               $this->RestoreClient->SelectedValue = $this->BackupClient->SelectedValue;
                $this->RestoreClient->dataBind();
        }
 
@@ -274,10 +301,12 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function loadBackupsForClient() {
-               $clientid = $this->getBackupClientId();
-               $jobs_for_client = $this->getModule('api')->get(array('clients', $clientid, 'jobs'))->output;
+               $clientid = $this->BackupClient->SelectedValue;
+               $jobs_for_client = $this->getModule('api')->get(
+                       ['clients', $clientid, 'jobs']
+               )->output;
                $jobs = $this->getModule('misc')->objectToArray($jobs_for_client);
-               $this->jobs_to_restore = array_filter($jobs, array($this, 'isJobToRestore'));
+               $this->jobs_to_restore = array_filter($jobs, [$this, 'isJobToRestore']);
        }
 
        /**
@@ -287,7 +316,7 @@ class RestoreWizard extends BaculumWebPage
         * @return true if job should be listed to restore, otherwise false
         */
        private function isJobToRestore($job) {
-               $jobtype = array('B');
+               $jobtype = ['B'];
                if ($this->EnableCopyJobRestore->Checked) {
                        $jobtype[] = 'C';
                }
@@ -305,25 +334,7 @@ class RestoreWizard extends BaculumWebPage
                $this->setFileVersions();
                $this->setFilesToRestore();
                $this->markFileToRestore(null, null);
-               $_SESSION['restore_path'] = array();
-       }
-
-
-       /**
-        * Get selected backup client identifier.
-        *
-        * @return mixed client identifier or null if no clientid found
-        */
-       public function getBackupClientId() {
-               $clientid = null;
-               $clients = $this->getModule('api')->get(array('clients'))->output;
-               for ($i = 0; $i < count($clients); $i++) {
-                       if ($clients[$i]->name === $this->BackupClientName->SelectedValue) {
-                               $clientid = $clients[$i]->clientid;
-                               break;
-                       }
-               }
-               return $clientid;
+               $this->setRestorePath();
        }
 
        /**
@@ -334,7 +345,7 @@ class RestoreWizard extends BaculumWebPage
         */
        public function getBackupClient($clientid) {
                $client = null;
-               $clients = $this->getModule('api')->get(array('clients'))->output;
+               $clients = $this->getModule('api')->get(['clients'])->output;
                for ($i = 0; $i < count($clients); $i++) {
                        if ($clients[$i]->clientid === $clientid) {
                                $client = $clients[$i]->name;
@@ -350,18 +361,18 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function loadGroupBackupToRestore() {
-               $jobs = $this->getModule('api')->get(array('jobs'))->output;
+               $jobs = $this->getModule('api')->get(['jobs'])->output;
                $jobs = $this->getModule('misc')->objectToArray($jobs);
-               $clientid = $this->getBackupClientId();
-               $job_group_list = array();
+               $clientid = intval($this->BackupClient->SelectedValue);
+               $job_group = [];
                for ($i = 0; $i < count($jobs); $i++) {
-                       $job = $this->getModule('misc')->objectToArray($jobs[$i]);
                        if ($this->isJobToRestore($jobs[$i]) && $jobs[$i]['clientid'] === $clientid) {
-                               $job_group_list[$jobs[$i]['name']] = $jobs[$i]['name'];
+                               $job_group[$jobs[$i]['name']] = $jobs[$i]['name'];
                        }
                }
+               asort($job_group);
 
-               $this->GroupBackupToRestore->dataSource = $job_group_list;
+               $this->GroupBackupToRestore->DataSource = $job_group;
                $this->GroupBackupToRestore->dataBind();
        }
 
@@ -371,14 +382,14 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function loadGroupFileSetToRestore() {
-               $filesets = $this->getModule('api')->get(array('filesets'))->output;
-               $fileset_list = array();
+               $filesets = $this->getModule('api')->get(['filesets'])->output;
+               $fileset_group = [];
                for ($i = 0; $i < count($filesets); $i++) {
-                       $fileset_list[$filesets[$i]->filesetid] = $filesets[$i]->fileset . ' (' . $filesets[$i]->createtime . ')';
+                       $fileset_group[$filesets[$i]->filesetid] = $filesets[$i]->fileset . ' (' . $filesets[$i]->createtime . ')';
                }
-               asort($fileset_list);
+               asort($fileset_group);
 
-               $this->GroupBackupFileSet->dataSource = $fileset_list;
+               $this->GroupBackupFileSet->DataSource = $fileset_group;
                $this->GroupBackupFileSet->dataBind();
        }
 
@@ -389,46 +400,47 @@ class RestoreWizard extends BaculumWebPage
         */
        private function prepareBrowserContent() {
                $jobids = $this->getElementaryBackup();
-               $elements = array();
+               $elements = [];
                if (!empty($jobids)) {
                        // generating Bvfs may take a moment
                        $this->generateBvfsCache($jobids);
 
                        // get directory and file list
-                       $query = '?' . http_build_query(array(
+                       $query = '?' . http_build_query([
                                'jobids' => $jobids,
-                               'path' => implode($_SESSION['restore_path']),
+                               'path' => implode($this->Session['restore_path']),
                                'output' => 'json'
-                       ));
+                       ]);
                        $bvfs_dirs = $this->getModule('api')->get(
-                               array('bvfs', 'lsdirs', $query)
+                               ['bvfs', 'lsdirs', $query]
                        );
-                       $dirs = array();
+                       $dirs = [];
                        if ($bvfs_dirs->error === 0) {
                                $dirs = json_decode(json_encode($bvfs_dirs->output), true);
                        }
 
                        // get files list
                        $bvfs_files = $this->getModule('api')->get(
-                               array('bvfs', 'lsfiles', $query)
+                               ['bvfs', 'lsfiles', $query]
                        );
-                       $files = array();
+                       $files = [];
                        if ($bvfs_files->error === 0) {
                                $files = json_decode(json_encode($bvfs_files->output), true);
                        }
 
                        $elements = array_merge($dirs, $files);
-                       $elements = array_map(array('RestoreWizard', 'addUniqid'), $elements);
-                       if (count($_SESSION['restore_path']) > 0) {
+                       $elements = array_map(['RestoreWizard', 'addUniqid'], $elements);
+                       if (count($this->Session['restore_path']) > 0) {
                                array_unshift($elements, $this->browser_root_dir);
                        }
                }
                if (count($elements) > 0) {
                        $this->NoFileFound->Display = 'None';
-               } elseif (isset($_SESSION['restore_single_jobid'])) {
+               } elseif ($this->Session->contains('restore_jobid')) {
                        $this->NoFileFound->Display = 'Dynamic';
                }
-               $this->loadBrowserFiles($elements);
+               $this->setBrowserFiles($elements);
+               $this->loadBrowserFiles(null, null);
        }
 
        /**
@@ -456,18 +468,18 @@ class RestoreWizard extends BaculumWebPage
         */
        private function getElementaryBackup() {
                $jobids = '';
-               if ($this->OnlySelectedBackupSelection->Checked && isset($_SESSION['restore_single_jobid'])) {
+               if ($this->OnlySelectedBackupSelection->Checked && $this->Session->contains('restore_jobid')) {
                        $params = [
-                               'jobid' => $_SESSION['restore_single_jobid']
+                               'jobid' => $this->Session['restore_jobid']
                        ];
                        if ($this->EnableCopyJobRestore->Checked) {
                                $params['inc_copy_job'] = 1;
                        }
                        $query = '?' . http_build_query($params);
                        $jobs = $this->getModule('api')->get(
-                               array('bvfs', 'getjobids', $query)
+                               ['bvfs', 'getjobids', $query]
                        );
-                       $ids = is_object($jobs) ? $jobs->output : array();
+                       $ids = is_object($jobs) ? $jobs->output : [];
                        foreach ($ids as $jobid) {
                                if (preg_match('/^([\d\,]+)$/', $jobid, $match) == 1) {
                                        $jobids = $match[1];
@@ -475,23 +487,23 @@ class RestoreWizard extends BaculumWebPage
                                }
                        }
                        if (empty($jobids)) {
-                               $jobids = $_SESSION['restore_single_jobid'];
+                               $jobids = $this->Session['restore_jobid'];
                        }
                } else {
                        $params = [
-                               'client' => $this->BackupClientName->SelectedValue,
+                               'clientid' => $this->BackupClient->SelectedValue,
                                'filesetid' => $this->GroupBackupFileSet->SelectedValue
                        ];
                        if ($this->EnableCopyJobRestore->Checked) {
                                $params['inc_copy_job'] = 1;
                        }
                        $query = '?' . http_build_query($params);
-                       $jobs_recent = $this->getModule('api')->get(array(
+                       $jobs_recent = $this->getModule('api')->get([
                                'jobs',
                                'recent',
                                $this->GroupBackupToRestore->SelectedValue,
                                $query
-                       ));
+                       ]);
                        if (count($jobs_recent->output) > 0) {
                                $ids = $jobs_recent->output;
                                $jobids = implode(',', $ids);
@@ -531,19 +543,23 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        private function goToPath($path = '', $full_path = false) {
-               if (!empty($path) && !$full_path) {
+               if (!empty($path) && !$full_path && $this->Session->contains('restore_path')) {
                        if ($path == $this->browser_up_dir['name']) {
-                               array_pop($_SESSION['restore_path']);
+                               $rp = $this->Session['restore_path'];
+                               array_pop($rp);
+                               $this->Session->add('restore_path', $rp);
                        } elseif ($path == $this->browser_root_dir['name']) {
-                               $_SESSION['restore_path'] = array();
+                               $this->setRestorePath();
                        } else {
-                               array_push($_SESSION['restore_path'], $path);
+                               $rp = $this->Session['restore_path'];
+                               array_push($rp, $path);
+                               $this->Session->add('restore_path', $rp);
                        }
                }
                if ($full_path && is_array($path)) {
-                       $_SESSION['restore_path'] = $path;
+                       $this->setRestorePath($path);
                }
-               $this->setBrowserPath();
+               $this->loadBrowserPath();
                $this->prepareBrowserContent();
        }
 
@@ -556,39 +572,22 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        public function addFileToRestore($sender, $param) {
-               $uniqid = null;
-               $source_element_id = null;
-               $file_prop = array();
-               if (get_class($param) == 'Prado\Web\UI\ActiveControls\TCallbackEventParameter') {
-                       $id_parts = explode('_', $sender->ClientID, 6);
-                       $source_element_id = $id_parts[3];
-                       $uniqid = $param->CallbackParameter;
-               } else {
-                       $control = $param->DraggableControl;
-                       $item = $control->getNamingContainer();
-                       $id_parts = explode('_', $control->ClientID, 6);
-                       $source_element_id = $id_parts[3];
-               }
-               if ($source_element_id == $this->VersionsDataGrid->ID) {
-                       if (is_null($uniqid)) {
-                               $uniqid = $this->VersionsDataGrid->getDataKeys()->itemAt($item->getItemIndex());
-                       }
+               $file_prop = [];
+               list($source, $uniqid) = explode('|', $param->CallbackParameter, 2);
+               if ($source === 'version_browser') {
                        $file_prop = $this->getFileVersions($uniqid);
-               } else {
-                       if (is_null($uniqid)) {
-                               $uniqid = $this->DataGridFiles->getDataKeys()->itemAt($item->getItemIndex());
-                       }
+               } elseif ($source === 'file_browser') {
                        $file_prop = $this->getBrowserFile($uniqid);
                }
 
                if ($file_prop['name'] != $this->browser_root_dir['name'] && $file_prop['name'] != $this->browser_up_dir['name']) {
                        $this->markFileToRestore($uniqid, $file_prop);
-                       $this->loadSelectedFiles();
+                       $this->loadSelectedFiles(null, null);
                }
        }
 
        /**
-        * Remove file from files marked to restre.
+        * Remove file from files marked to restore.
         *
         * @param TCallback $sender sender object
         * @param TEventParameter $param param object
@@ -597,7 +596,7 @@ class RestoreWizard extends BaculumWebPage
        public function removeSelectedFile($sender, $param) {
                $uniqid = $param->CallbackParameter;
                $this->unmarkFileToRestore($uniqid);
-               $this->loadSelectedFiles();
+               $this->loadSelectedFiles(null, null);
        }
 
        /**
@@ -614,9 +613,9 @@ class RestoreWizard extends BaculumWebPage
                        $this->goToPath($filename);
                        return;
                }
-               $clientname = $this->BackupClientName->SelectedValue;
+               $clientid = $this->BackupClient->SelectedValue;
                $params = [
-                       'client' => $clientname,
+                       'clientid' => $clientid,
                        'jobid' => $jobid,
                        'pathid' => $pathid,
                        'filenameid' => $filenameid,
@@ -638,21 +637,15 @@ class RestoreWizard extends BaculumWebPage
                };
 
                $query = '?' . http_build_query($params);
-               $versions = $this->getModule('api')->get(array('bvfs', 'versions', $query))->output;
+               $versions = $this->getModule('api')->get(
+                       ['bvfs', 'versions', $query]
+               )->output;
                $versions = json_decode(json_encode($versions), true);
                $file_versions = array_map($add_version_filename_func, $versions);
-               $file_versions = array_map(array('RestoreWizard', 'addUniqid'), $file_versions);
+               $file_versions = array_map(['RestoreWizard', 'addUniqid'], $file_versions);
                $this->setFileVersions($file_versions);
-               $this->VersionsDataGrid->dataSource = $file_versions;
-               $this->VersionsDataGrid->dataBind();
-               $this->loadSelectedFiles();
-       }
-
-       /**
-        * Call formatters method.
-        */
-       public function callFormatters($sender, $param) {
-               $this->getCallbackClient()->callClientFunction('set_formatters');
+               $this->loadFileVersions(null, null);
+               $this->loadSelectedFiles(null, null);
        }
 
        /*
@@ -661,10 +654,9 @@ class RestoreWizard extends BaculumWebPage
         * @param array $files files to list.
         * @return none
         */
-       private function loadBrowserFiles($files) {
-               $this->setBrowserFiles($files);
-               $this->DataGridFiles->dataSource = $files;
-               $this->DataGridFiles->dataBind();
+       public function loadBrowserFiles($sender, $param) {
+               $files = $this->Session->contains('files_browser') ? $this->Session['files_browser'] : [];
+               $this->getCallbackClient()->callClientFunction('oRestoreBrowserFiles.populate', [$files]);
        }
 
        /**
@@ -672,9 +664,9 @@ class RestoreWizard extends BaculumWebPage
         *
         * @return none;
         */
-       private function loadFileVersions() {
-               $this->VersionsDataGrid->dataSource = $_SESSION['files_versions'];
-               $this->VersionsDataGrid->dataBind();
+       public function loadFileVersions($sender, $param) {
+               $versions = $this->Session->contains('files_versions') ? $this->Session['files_versions'] : [];
+               $this->getCallbackClient()->callClientFunction('oRestoreBrowserVersions.populate', [array_values($versions)]);
        }
 
        /**
@@ -682,9 +674,9 @@ class RestoreWizard extends BaculumWebPage
         *
         * @return none
         */
-       private function loadSelectedFiles() {
-               $this->SelectedVersionsDataGrid->dataSource = $_SESSION['restore'];
-               $this->SelectedVersionsDataGrid->dataBind();
+       public function loadSelectedFiles($sender, $param) {
+               $files = $this->Session->contains('files_restore') ? $this->Session['files_restore'] : [];
+               $this->getCallbackClient()->callClientFunction('oRestoreBrowserSelectedFiles.populate', [array_values($files)]);
        }
 
        /**
@@ -692,8 +684,9 @@ class RestoreWizard extends BaculumWebPage
         *
         * @return none
         */
-       private function setBrowserPath() {
-               $this->PathField->Text = implode($_SESSION['restore_path']);
+       private function loadBrowserPath() {
+               $path = $this->Session->contains('restore_path') ? $this->Session['restore_path'] : [];
+               $this->PathField->Text = implode($path);
        }
 
        /**
@@ -704,8 +697,8 @@ class RestoreWizard extends BaculumWebPage
         */
        private function generateBvfsCache($jobids) {
                $this->getModule('api')->set(
-                       array('bvfs', 'update'),
-                       array('jobids' => $jobids)
+                       ['bvfs', 'update'],
+                       ['jobids' => $jobids]
                );
        }
 
@@ -715,8 +708,8 @@ class RestoreWizard extends BaculumWebPage
         * @param array $versions file versions data
         * @return none
         */
-       private function setFileVersions($versions = array()) {
-               $_SESSION['files_versions'] = $versions;
+       private function setFileVersions($versions = []) {
+               $this->Session->add('files_versions', $versions);
        }
 
        /**
@@ -726,11 +719,13 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        private function getFileVersions($uniqid) {
-               $versions = array();
-               foreach ($_SESSION['files_versions'] as $file) {
-                       if (key_exists('uniqid', $file) && $file['uniqid'] === $uniqid) {
-                               $versions = $file;
-                               break;
+               $versions = [];
+               if ($this->Session->contains('files_versions')) {
+                       foreach ($this->Session['files_versions'] as $file) {
+                               if (key_exists('uniqid', $file) && $file['uniqid'] === $uniqid) {
+                                       $versions = $file;
+                                       break;
+                               }
                        }
                }
                return $versions;
@@ -742,8 +737,18 @@ class RestoreWizard extends BaculumWebPage
         * @param array $files file list
         * @return none
         */
-       private function setBrowserFiles($files = array()) {
-               $_SESSION['files_browser'] = $files;
+       private function setBrowserFiles($files = []) {
+               $this->Session->add('files_browser', $files);
+       }
+
+       /**
+        * Set restore browser path.
+        *
+        * @param array $files file list
+        * @return none
+        */
+       private function setRestorePath($path = []) {
+               $this->Session->add('restore_path', $path);
        }
 
        /**
@@ -753,11 +758,13 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        private function getBrowserFile($uniqid) {
-               $element = array();
-               foreach ($_SESSION['files_browser'] as $file) {
-                       if (key_exists('uniqid', $file) && $file['uniqid'] === $uniqid) {
-                               $element = $file;
-                               break;
+               $element = [];
+               if ($this->Session->contains('files_browser')) {
+                       foreach ($this->Session['files_browser'] as $file) {
+                               if (key_exists('uniqid', $file) && $file['uniqid'] === $uniqid) {
+                                       $element = $file;
+                                       break;
+                               }
                        }
                }
                return $element;
@@ -772,9 +779,11 @@ class RestoreWizard extends BaculumWebPage
         */
        private function markFileToRestore($uniqid, $file) {
                if (is_null($uniqid)) {
-                       $_SESSION['restore'] = array();
+                       $this->setFilesToRestore();
                } elseif ($file['name'] != $this->browser_root_dir['name'] && $file['name'] != $this->browser_up_dir['name']) {
-                       $_SESSION['restore'][$uniqid] = $file;
+                       $fr = $this->Session['files_restore'];
+                       $fr[$uniqid] = $file;
+                       $this->Session->add('files_restore', $fr);
                }
        }
 
@@ -785,8 +794,10 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        private function unmarkFileToRestore($uniqid) {
-               if (key_exists($uniqid, $_SESSION['restore'])) {
-                       unset($_SESSION['restore'][$uniqid]);
+               if (key_exists($uniqid, $this->Session['files_restore'])) {
+                       $fr = $this->Session['files_restore'];
+                       unset($fr[$uniqid]);
+                       $this->Session['files_restore'] = $fr;
                }
        }
 
@@ -796,7 +807,7 @@ class RestoreWizard extends BaculumWebPage
         * @return array list with files to restore
         */
        public function getFilesToRestore() {
-               return $_SESSION['restore'];
+               return ($this->Session->contains('files_restore') ? $this->Session['files_restore'] : []);
        }
 
        /**
@@ -805,8 +816,8 @@ class RestoreWizard extends BaculumWebPage
         * @param array $files files to restore
         * @return none
         */
-       public function setFilesToRestore($files = array()) {
-               $_SESSION['restore'] = $files;
+       public function setFilesToRestore($files = []) {
+               $this->Session->add('files_restore', $files);
        }
 
        /**
@@ -816,9 +827,9 @@ class RestoreWizard extends BaculumWebPage
         * @return array list fileids and dirids
         */
        public function getRestoreElements($as_object = false) {
-               $fileids = array();
-               $dirids = array();
-               $findexes = array();
+               $fileids = [];
+               $dirids = [];
+               $findexes = [];
                foreach ($this->getFilesToRestore() as $uniqid => $properties) {
                        if ($properties['type'] == 'dir') {
                                $dirids[] = $properties['pathid'];
@@ -829,7 +840,11 @@ class RestoreWizard extends BaculumWebPage
                                }
                        }
                }
-               $ret = array('fileid' => $fileids, 'dirid' => $dirids, 'findex' => $findexes);
+               $ret = [
+                       'fileid' => $fileids,
+                       'dirid' => $dirids,
+                       'findex' => $findexes
+               ];
                if ($as_object === true) {
                        $ret = (object)$ret;
                }
@@ -845,7 +860,7 @@ class RestoreWizard extends BaculumWebPage
                $jobids = $this->getElementaryBackup();
                $path = self::BVFS_PATH_PREFIX . getmypid();
                $restore_elements = $this->getRestoreElements();
-               $cmd_props = array('jobids' => $jobids, 'path' => $path);
+               $cmd_props = ['jobids' => $jobids, 'path' => $path];
                $is_element = false;
                if (count($restore_elements['fileid']) > 0) {
                        $cmd_props['fileid'] = implode(',', $restore_elements['fileid']);
@@ -863,7 +878,7 @@ class RestoreWizard extends BaculumWebPage
                $jobid = null;
                $ret = new stdClass;
                $restore_props = [];
-               $restore_props['client'] = $this->RestoreClient->SelectedValue;
+               $restore_props['client'] = $this->RestoreClient->SelectedItem->Text;
                if ($_SESSION['file_relocation'] == 2) {
                        if (!empty($this->RestoreStripPrefix->Text)) {
                                $restore_props['strip_prefix'] = $this->RestoreStripPrefix->Text;
@@ -885,27 +900,39 @@ class RestoreWizard extends BaculumWebPage
                $restore_props['replace'] = $this->ReplaceFiles->SelectedValue;
                $restore_props['restorejob'] = $this->RestoreJob->SelectedValue;
                if ($is_element) {
-                       $this->getModule('api')->create(array('bvfs', 'restore'), $cmd_props);
+                       $this->getModule('api')->create(
+                               ['bvfs', 'restore'],
+                               $cmd_props
+                       );
                        $restore_props['rpath'] = $path;
 
-                       $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restore_props);
+                       $ret = $this->getModule('api')->create(
+                               ['jobs', 'restore'],
+                               $restore_props
+                       );
                        $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output);
                        // Remove temporary BVFS table
-                       $this->getModule('api')->set(array('bvfs', 'cleanup'), array('path' => $path));
-               } elseif (count($_SESSION['files_browser']) === 0 && isset($_SESSION['restore_single_jobid'])) {
+                       $this->getModule('api')->set(['bvfs', 'cleanup'], ['path' => $path]);
+               } elseif (count($this->Session['files_browser']) === 0 && $this->Session->contains('restore_jobid')) {
                        $restore_props['full'] = 1;
-                       $restore_props['id'] = $_SESSION['restore_single_jobid'];
-                       $job = $this->getModule('api')->get(array('jobs', $_SESSION['restore_single_jobid']))->output;
+                       $restore_props['id'] = $this->Session['restore_jobid'];
+                       $job = $this->getModule('api')->get(
+                               ['jobs', $this->Session['restore_jobid']]
+                       )->output;
                        if (is_object($job)) {
                                $restore_props['fileset'] = $job->fileset;
                        }
-                       $ret = $this->getModule('api')->create(array('jobs', 'restore'), $restore_props);
+                       $ret = $this->getModule('api')->create(
+                               ['jobs', 'restore'],
+                               $restore_props
+                       );
                        $jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output);
                } else {
                        $ret->output = ['No file to restore found'];
                }
-               $url_params = array();
+               $url_params = [];
                if (is_numeric($jobid)) {
+                       $this->resetWizard();
                        $url_params['jobid'] = $jobid;
                        $this->goToPage('JobHistoryView', $url_params);
                } else {
@@ -920,8 +947,10 @@ class RestoreWizard extends BaculumWebPage
         * @return none
         */
        private function loadRestoreJobs() {
-               $restore_job_tasks = $this->getModule('api')->get(array('jobs', 'resnames', '?type=R'))->output;
-               $jobs = array();
+               $restore_job_tasks = $this->getModule('api')->get(
+                       ['jobs', 'resnames', '?type=R']
+               )->output;
+               $jobs = [];
                foreach ($restore_job_tasks as $director => $restore_jobs) {
                        $jobs = array_merge($jobs, $restore_jobs);
                }
@@ -930,7 +959,7 @@ class RestoreWizard extends BaculumWebPage
        }
 
        private function loadRequiredVolumes() {
-               $volumes = array();
+               $volumes = [];
                foreach ($this->getFilesToRestore() as $uniqid => $props) {
                        list($jobid, $pathid, $fileid) = explode(':', $uniqid, 3);
                        if ($jobid === '0') {
@@ -942,13 +971,15 @@ class RestoreWizard extends BaculumWebPage
                                continue;
                        }
                        // it can be expensive for many restore paths
-                       $result = $this->getModule('api')->get(array('volumes', 'required', $jobid, $fileid));
+                       $result = $this->getModule('api')->get(
+                               ['volumes', 'required', $jobid, $fileid]
+                       );
                        if ($result->error === 0) {
                                for ($i = 0; $i < count($result->output); $i++) {
-                                       $volumes[$result->output[$i]->volume] = array(
+                                       $volumes[$result->output[$i]->volume] = [
                                                'volume' => $result->output[$i]->volume,
                                                'inchanger' => $result->output[$i]->inchanger
-                                       );
+                                       ];
                                }
                        }
                }
@@ -966,11 +997,13 @@ class RestoreWizard extends BaculumWebPage
                $this->setBrowserFiles();
                $this->setFileVersions();
                $this->setFilesToRestore();
-               $this->markFileToRestore(null, null);
+               $this->Session->remove('files_browser');
+               $this->Session->remove('files_versions');
+               $this->Session->remove('files_restore');
                $this->loadRestoreJobs();
-               $_SESSION['restore_path'] = array();
-               $_SESSION['restore_single_jobid'] = null;
-               unset($_SESSION['file_relocation']);
+               $this->Session->remove('restore_path');
+               $this->Session->remove('restore_jobid');
+               $this->Session->remove('file_relocation');
        }
 }
 ?>
index 5508df7d18034f890e31f11c9323679dd6100d3a..c298e7c04c11dbceda3f86879c6be6c7cff61987 100644 (file)
@@ -11,7 +11,6 @@
        width: 100%;
        height: 100% !important;
        background-color: white;
-       padding: 0 4px;
 }
 
 #restore-browser-files-loading {
        background: rgba(182,182,182,0.4) url('/themes/Baculum-v2/loader-small.gif') no-repeat center center;
 }
 
+#restore-browser-files-content {
+       position: relative;
+       height: 100%;
+}
+
 .file-browser-detail {
        width: 100%;
 }
 
-tr.file-browser-element {
+div.file-browser-element {
        cursor: pointer;
+       padding: 4px 8px;
+       clear: both;
 }
 
-tr.file-browser-element:hover {
+div.file-browser-element:hover {
        background-color: rgb(219, 222, 223);
 }
 
-.restore-browser-element-size {
+.restore-browser-element-right {
        float: right;
        width: 100px;
 }
 
-.restore-browser-element-size {
+.restore-browser-element-right {
        line-height: 24px;
 }
 
 .file-browser-watermark {
-       padding: 68px 10px;
+       position: absolute;
+       top: 50%;
+       left: 50%;
+       transform: translate(-50%, -50%);
        text-align: center;
        font-size: 21px;
        color: rgb(185, 184, 184);