</prop:ClientSide.OnLoading>
<prop:ClientSide.OnComplete>
oJobsToRestoreList.show_find_job_by_filename_loader(false);
- <%=$this->Session->contains('restore_jobid') ? 'oJobsToRestoreList.set_jobid(' . $this->Session['restore_jobid'] . ');' : ''%>
+ <%=$this->Session->contains('restore_job') ? 'oJobsToRestoreList.set_jobid(' . $this->Session['restore_job']['jobid'] . ');' : ''%>
</prop:ClientSide.OnComplete>
</com:TCallback>
<script type="text/javascript">
var radio = document.createElement('INPUT');
radio.type = 'radio';
radio.name = 'backup_to_restore';
- radio.value = data;
+ radio.value = [data, row.name, row.type, row.endtime, row.jobstatus].join('|');
radio.className = 'w3-radio';
- if ('<%=$this->Session->contains('restore_jobid') ? $this->Session['restore_jobid'] : ''%>' == data) {
+ if ('<%=$this->Session->contains('restore_job') ? $this->Session['restore_job']['jobid'] : ''%>' == data) {
radio.setAttribute('checked', 'checked');
}
ret = radio.outerHTML;
<com:TPanel ID="NoFileFound" Style="height: 38px" Display="None">
<%[ No file found for selected backup. It can mean file records for this backup are pruned. Restoring selected files is not available but if you continue, there will be performed full restore all backup files. ]%>
</com:TPanel>
+ <com:TCallback
+ ID="LoadPath"
+ OnCallback="loadPath"
+ >
+ <prop:ClientSide.OnLoading>
+ document.getElementById('restore-browser-files-loading').style.display = 'block';
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ document.getElementById('restore-browser-files-loading').style.display = 'none';
+ make_draggable('restore-browser-files-content');
+ </prop:ClientSide.OnComplete>
+ </com:TCallback>
<div class="w3-row">
- <div class="w3-col" style="width: 15%;"><%[ Path: ]%></div>
+ <div class="w3-col" style="width: 15%; text-align: right; padding: 10px;"><%[ Path: ]%></div>
<div class="w3-col" style="width: 85%;">
<com:TActiveTextBox
ID="PathField"
CssClass="w3-input w3-twothird w3-border"
Style="display: inline"
- Attributes.onkeydown="var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode === 13) {$('#<%=$this->LoadPathBtn->ClientID%>').click(); return false; } return true;"
+ Attributes.onkeydown="var keycode = (event.keyCode ? event.keyCode : event.which); if (keycode === 13) {oRestoreBrowserFiles.load_browser_content(); return false; } return true;"
/>
- <com:TActiveLinkButton
- ID="LoadPathBtn"
- CssClass="w3-button w3-green"
- OnClick="loadPath">
- <prop:ClientSide.OnLoading>
- document.getElementById('restore-browser-files-loading').style.display = 'block';
- </prop:ClientSide.OnLoading>
- <prop:ClientSide.OnComplete>
- document.getElementById('restore-browser-files-loading').style.display = 'none';
- make_draggable('restore-browser-files-content');
- </prop:ClientSide.OnComplete>
+ <button type="button" id="load_path_btn" class="w3-button w3-green" onclick="oRestoreBrowserFiles.load_browser_content();">
<i class="fa fa-check"></i> <%[ OK ]%>
- </com:TActiveLinkButton>
+ </button>
+ </div>
+ </div>
+ <div class="w3-row w3-hide-small w3-small">
+ <span><%[ # Directories: ]%></span>
+ <com:TActiveLabel
+ ID="RestoreBrowserDirCount"
+ CssClass="w3-show-inline-block"
+ Style="min-width: 20px;"
+ Text="0"
+ />
+ <span><%[ # Files: ]%></span>
+ <com:TActiveLabel
+ ID="RestoreBrowserFileCount"
+ CssClass="w3-show-inline-block"
+ Style="min-width: 20px;"
+ Text="0"
+ />
+ <div class="w3-right w3-half w3-hide-small" style="text-align: right; margin-top: 5px">
+ <span><%[ Backup client ]%>:</span>
+ <com:TActiveLabel
+ ID="RestoreBrowserClient"
+ CssClass="w3-show-inline-block w3-margin-right"
+ Style="font-weight: bold"
+ />
+ <span><%[ Job type ]%>:</span>
+ <com:TActiveLabel
+ ID="RestoreBrowserType"
+ CssClass="w3-show-inline-block w3-margin-right"
+ Style="font-weight: bold"
+ />
+ <span><%[ Job name ]%>:</span>
+ <com:TActiveLabel
+ ID="RestoreBrowserName"
+ CssClass="w3-show-inline-block w3-margin-right"
+ Style="font-weight: bold"
+ />
+ <span><%[ Status ]%>: </span>
+ <com:TActiveLabel
+ ID="RestoreBrowserStatus"
+ CssClass="w3-show-inline-block w3-margin-right"
+ Style="vertical-align: top"
+ />
+ <span><%[ Restore time point ]%>:</span>
+ <com:TActiveLabel
+ ID="RestoreBrowserTimePoint"
+ CssClass="w3-show-inline-block"
+ Style="font-weight: bold"
+ />
</div>
</div>
<table id="restore-browser">
<div id="restore-browser-files" class="w3-border">
<div id="restore-browser-files-content"></div>
</div>
+ <div id="restore-browser-nav" class="w3-hide-small" style="height: 57px; padding: 8px 0;">
+ <button type="button" class="w3-button w3-dark-grey w3-right" onclick="oRestoreBrowserFiles.next_page();"><%[ Next ]%> <i class="fa fa-arrow-right"></i></button>
+ <button type="button" class="w3-button w3-dark-grey w3-right w3-margin-right" onclick="oRestoreBrowserFiles.prev_page();"><i class="fa fa-arrow-left"></i> <%[ Previous ]%></button>
+ <com:TActiveTextBox
+ ID="RestoreBrowserLimit"
+ CssClass="w3-input w3-border w3-right w3-show-inline-block w3-margin-right"
+ Width="70px"
+ Text="2000"
+ />
+ <span class="w3-right" style="padding: 8px 2px 8px 8px"><%[ Limit: ]%></span>
+ <com:TActiveTextBox
+ ID="RestoreBrowserOffset"
+ CssClass="w3-input w3-border w3-right w3-show-inline-block"
+ Width="70px"
+ Text="0"
+ />
+ <span class="w3-right" style="padding: 8px 2px"><%[ Offset: ]%></span>
+ <input type="text" id="restore-browser-search" class="w3-input w3-border w3-show-inline-block" style="width: 170px" placeholder="🔍 <%[ Search... ]%>" />
+ <input type="checkbox" class="w3-check w3-margin-left" id="restore-browser-search-insensitive" />
+ <label for="restore-browser-search-insensitive" style="padding: 8px 2px"><%[ case sensitive ]%></label>
+ </div>
<script>
var oRestoreBrowserFiles = {
ids: {
- content: 'restore-browser-files-content'
+ content: 'restore-browser-files-content',
+ search: 'restore-browser-search',
+ case_sensitive: 'restore-browser-search-insensitive',
+ offset: '<%=$this->RestoreBrowserOffset->ClientID%>',
+ limit: '<%=$this->RestoreBrowserLimit->ClientID%>',
+ type: '<%=$this->RestoreBrowserType->ClientID%>',
+ status: '<%=$this->RestoreBrowserStatus->ClientID%>',
+ time_point: '<%=$this->RestoreBrowserTimePoint->ClientID%>'
},
cls: {
draggable: 'draggable',
},
excluded_items: ['.', '..'],
init: function(items) {
+ this.set_events();
this.load_items();
+ this.set_browser_headers();
+ },
+ load_browser_content: function() {
+ var cb = <%=$this->LoadPath->ActiveControl->Javascript%>;
+ cb.dispatch();
},
load_items: function() {
var cb = <%=$this->SetBrowserFiles->ActiveControl->Javascript%>;
if(vposition == null || vposition == '0px'){
event.stop();
} else {
+ if (item.type === this.types.directory) {
+ var offset = document.getElementById(this.ids.offset);
+ offset.value = 0;
+ var search = document.getElementById(this.ids.search);
+ search.value = '';
+ }
var cbp = [item.name, item.pathid, item.filenameid, item.jobid].join('|');
var request = <%=$this->getPage()->GetVersions->ActiveControl->Javascript%>;
request.setCallbackParameter(cbp);
div.appendChild(right);
container.appendChild(div);
},
+ set_events: function() {
+ document.getElementById(this.ids.offset).addEventListener('keypress', function(e) {
+ var kc = event.which || event.keyCode;
+ if (kc === 13) {
+ this.load_browser_content();
+ }
+ }.bind(this));
+ document.getElementById(this.ids.limit).addEventListener('keypress', function(e) {
+ var kc = event.which || event.keyCode;
+ if (kc === 13) {
+ this.load_browser_content();
+ }
+ }.bind(this));
+ var search = document.getElementById(this.ids.search);
+ var case_sensitive = document.getElementById(this.ids.case_sensitive);
+ var search_func = function(e) {
+ var els = document.querySelectorAll('#' + this.ids.content + ' div.' + this.cls.item);
+ var cs = case_sensitive.checked;
+ var txt, regex, regex_opts;
+ for (var i = 0; i < els.length; i++) {
+ txt = els[i].childNodes[1].textContent;
+ if (cs) {
+ regex = new RegExp(search.value);
+ } else {
+ regex = new RegExp(search.value, 'i');
+ }
+ if (regex.test(txt)) {
+ if (els[i].style.display == 'none') {
+ els[i].style.removeProperty('display');
+ }
+ } else {
+ els[i].style.display = 'none';
+ }
+ }
+ }.bind(this);
+ search.addEventListener('keyup', search_func);
+ case_sensitive.addEventListener('click', search_func);
+ },
+ prev_page: function() {
+ var offset = document.getElementById(this.ids.offset);
+ var limit = document.getElementById(this.ids.limit);
+ var new_offset = parseInt(offset.value, 10) - parseInt(limit.value, 10);
+ if (new_offset < 0) {
+ new_offset = 0;
+ }
+ offset.value = new_offset;
+ this.load_browser_content();
+ },
+ next_page: function() {
+ var offset = document.getElementById(this.ids.offset);
+ var limit = document.getElementById(this.ids.limit);
+ var new_offset = parseInt(offset.value, 10) + parseInt(limit.value, 10);
+ offset.value = new_offset;
+ this.load_browser_content();
+ },
clear_browser: function() {
var container = document.getElementById(this.ids.content);
while (container.firstChild) {
container.removeChild(container.firstChild);
}
+ },
+ set_browser_headers: function() {
+ var type = document.getElementById(this.ids.type);
+ type.textContent = JobType.get_type(type.textContent);
+ var status = document.getElementById(this.ids.status);
+ status.innerHTML = JobStatus.get_icon(status.textContent).outerHTML;
+ var time_point = document.getElementById(this.ids.time_point);
+ var d = date_time_to_ts(time_point.textContent);
+ time_point.textContent = Units.format_date(d);
}
};
$(function() {
Prado::using('System.Web.UI.WebControls.TWizard');
Prado::using('System.Web.UI.WebControls.TDataGrid');
Prado::using('System.Web.UI.JuiControls.TJuiDroppable');
+Prado::using('System.Web.UI.ActiveControls.TActiveLabel');
Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
Prado::using('System.Web.UI.ActiveControls.TActiveDataGrid');
Prado::using('System.Web.UI.ActiveControls.TActiveRepeater');
* @return none
*/
public function setRestoreByJobId($jobid) {
- $this->Session->add('restore_jobid', $jobid);
$job = $this->getModule('api')->get(
['jobs', $jobid]
)->output;
if (is_object($job)) {
+ $this->setRestoreJob($jobid, $job->name, $job->type, $job->endtime, $job->jobstatus);
$this->loadRestoreClients();
$this->BackupClient->SelectedValue = $job->clientid;
$this->RestoreClient->SelectedValue = $job->clientid;
}
}
+ private function setRestoreJob($jobid, $name, $type, $endtime, $jobstatus) {
+ $this->Session->add(
+ 'restore_job',
+ [
+ 'jobid' => $jobid,
+ 'name' => $name,
+ 'type' => $type,
+ 'endtime' => $endtime,
+ 'jobstatus' => $jobstatus
+ ]
+ );
+ }
+
/**
* Set navigation buttons.
* Used for restore specific jobid (hide previous button)
$this->loadRestoreClients();
if ($this->BackupClient->DataChanged) {
// remove previous restore jobid only if user changed client selection
- $this->Session->remove('restore_jobid');
+ $this->Session->remove('restore_job');
}
} elseif ($param->CurrentStepIndex === 1) {
if ($this->Request->contains('backup_to_restore')) {
- $this->Session->add(
- 'restore_jobid',
- $this->Request['backup_to_restore']
- );
+ list($jobid, $name, $type, $endtime, $jobstatus) = explode('|', $this->Request['backup_to_restore'], 5);
+ $this->setRestoreJob($jobid, $name, $type, $endtime, $jobstatus);
}
$this->setRestorePath();
$this->setFileVersions();
// generating Bvfs may take a moment
$this->generateBvfsCache($jobids);
+ $offset = intval($this->RestoreBrowserOffset->Text);
+ $limit = intval($this->RestoreBrowserLimit->Text);
+
// get directory and file list
$q = [
'jobids' => $jobids,
+ 'offset' => $offset,
+ 'limit' => $limit,
'output' => 'json'
];
if ($this->Session->contains('restore_pathid')) {
if ($bvfs_dirs->error === 0) {
$dirs = json_decode(json_encode($bvfs_dirs->output), true);
}
+ $dir_count = count($dirs);
+ if ($dir_count == 1 && ($dirs[0]['name'] == '/' || preg_match('/^[A-Z]+:\/$/i', $dirs[0]['name']) === 1)) {
+ $this->RestoreBrowserDirCount->Text = $dir_count;
+ } elseif ($dir_count == 0) {
+ $this->RestoreBrowserDirCount->Text = 0;
+ } else {
+ $this->RestoreBrowserDirCount->Text = ($dir_count - 1);
+ }
+
+ if ($this->Session->contains('restore_job')) {
+ $this->RestoreBrowserClient->Text = $this->BackupClient->SelectedItem->Text;
+ $this->RestoreBrowserName->Text = $this->Session['restore_job']['name'];
+ $this->RestoreBrowserType->Text = $this->Session['restore_job']['type'];
+ $this->RestoreBrowserStatus->Text = $this->Session['restore_job']['jobstatus'];
+ $this->RestoreBrowserTimePoint->Text = $this->Session['restore_job']['endtime'];
+ }
// get files list
$bvfs_files = $this->getModule('api')->get(
if ($bvfs_files->error === 0) {
$files = json_decode(json_encode($bvfs_files->output), true);
}
+ $this->RestoreBrowserFileCount->Text = count($files);
$elements = array_merge($dirs, $files);
$elements = array_map(['RestoreWizard', 'addUniqid'], $elements);
}
if (count($elements) > 0) {
$this->NoFileFound->Display = 'None';
- } elseif ($this->Session->contains('restore_jobid')) {
+ } elseif ($this->Session->contains('restore_job')) {
$this->NoFileFound->Display = 'Dynamic';
}
$this->setBrowserFiles($elements);
*/
private function getElementaryBackup() {
$jobids = '';
- if ($this->OnlySelectedBackupSelection->Checked && $this->Session->contains('restore_jobid')) {
+ if ($this->OnlySelectedBackupSelection->Checked && $this->Session->contains('restore_job')) {
$params = [
- 'jobid' => $this->Session['restore_jobid']
+ 'jobid' => $this->Session['restore_job']['jobid']
];
if ($this->EnableCopyJobRestore->Checked) {
$params['inc_copy_job'] = 1;
}
}
if (empty($jobids)) {
- $jobids = $this->Session['restore_jobid'];
+ $jobids = $this->Session['restore_job']['jobid'];
}
} else {
$params = [
]);
if (count($jobs_recent->output) > 0) {
$ids = $jobs_recent->output;
+ if (count($ids) > 0) {
+ $jobid = $ids[0];
+ $job = $this->getModule('api')->get(
+ ['jobs', $jobid]
+ )->output;
+ if (is_object($job)) {
+ $this->setRestoreJob($jobid, $job->name, $job->type, $job->endtime, $job->jobstatus);
+ }
+ }
$jobids = implode(',', $ids);
}
}
}
$path[$i] .= '/';
}
+ $path = array_filter($path); // remove empty item if any
$this->goToPath($path, true);
}
* There is possible to pass both single directory 'somedir'
* or whole path '/etc/somedir'.
*
- * @param string $path path to go
+ * @param string|array $path path to go
* @param bool $full_path determines if $path param is full path or relative path (singel directory)
* @return none
*/
$jobid = $this->getModule('misc')->findJobIdStartedJob($ret->output);
// Remove temporary BVFS table
$this->getModule('api')->set(['bvfs', 'cleanup'], ['path' => $path]);
- } elseif (count($this->Session['files_browser']) === 0 && $this->Session->contains('restore_jobid')) {
+ } elseif (count($this->Session['files_browser']) === 0 && $this->Session->contains('restore_job')) {
$restore_props['full'] = 1;
- $restore_props['id'] = $this->Session['restore_jobid'];
+ $restore_props['id'] = $this->Session['restore_job']['jobid'];
$job = $this->getModule('api')->get(
- ['jobs', $this->Session['restore_jobid']]
+ ['jobs', $this->Session['restore_job']['jobid']]
)->output;
if (is_object($job)) {
$restore_props['fileset'] = $job->fileset;
$this->loadRestoreJobs();
$this->Session->remove('restore_path');
$this->Session->remove('restore_pathid');
- $this->Session->remove('restore_jobid');
+ $this->Session->remove('restore_job');
$this->Session->remove('file_relocation');
}
}