🔨 Display backed up snaps in Web UI (Close #3)

This commit is contained in:
Sebastien Clement 2020-01-06 17:19:44 +01:00
parent c403ec5079
commit cc9f35e1ec
4 changed files with 168 additions and 47 deletions

View File

@ -43,16 +43,29 @@ router.get('/formated-local-snap', function(req, res, next) {
});
router.get('/formated-remote-manual', function(req, res, next) {
webdav.init(true, 'cloud.seb6596.ovh', 'admin', 'WPHRG-4jwCw-i8eqg-mtiao-Kmwrw').then(() => {
console.log('success');
}, (err) => {
console.log('failure');
console.log(err);
})
router.get('/formated-backup-manual', function(req, res, next) {
webdav.getFolderContent('/Hassio Backup/Manual/')
.then((contents) => {
contents.sort((a, b) => {
if (moment(a.lastmod).isBefore(moment(b.lastmod)))
return 1;
else
return -1;
})
res.render('backupSnaps',{backups: contents, moment: moment});
});
});
router.get('/formated-backup-auto', function(req, res, next) {
webdav.getFolderContent('/Hassio Backup/Auto/')
.then((contents) => {
res.render('backupSnaps',{backups: contents, moment: moment});
});
});
router.post('/nextcloud-settings', function(req, res, next) {
let settings = req.body;
@ -90,12 +103,12 @@ router.post('/manual-backup', function(req, res, next) {
let id = req.query.id;
let name = req.query.name;
let status = statusTools.getStatus();
if (status.status == "creating" && status.status == "upload" && status.status == "download"){
if (status.status == "creating" && status.status == "upload" && status.status == "download") {
res.status(503);
res.send();
return;
}
hassioApiTools.downloadSnapshot(id)
.then(() => {
webdav.uploadFile(id, '/Hassio Backup/Manual/' + name + '.tar');
@ -112,7 +125,7 @@ router.post('/manual-backup', function(req, res, next) {
router.post('/new-backup', function(req, res, next) {
let status = statusTools.getStatus();
if (status.status == "creating" && status.status == "upload" && status.status == "download"){
if (status.status == "creating" && status.status == "upload" && status.status == "download") {
res.status(503);
res.send();
return;
@ -147,9 +160,6 @@ router.post('/backup-settings', function(req, res, next) {
res.status(400);
res.send();
}
});

View File

@ -163,10 +163,10 @@ class WebdavTools {
let lastPercent = 0;
let req = request.put(option)
.on('drain', () => {
let percent = Math.floor((req.req.connection.bytesWritten / fileSize)*100);
if(lastPercent != percent){
let percent = Math.floor((req.req.connection.bytesWritten / fileSize) * 100);
if (lastPercent != percent) {
lastPercent = percent;
status.progress = percent/100;
status.progress = percent / 100;
statusTools.setStatus(status);
}
@ -180,7 +180,7 @@ class WebdavTools {
reject(status.message);
}).on('response', (res) => {
if (res.statusCode != 204) {
if (res.statusCode != 201) {
status.status = "error";
status.error_code = 4;
status.message = "Fail to upload snapshot to nextcloud (Status code: " + res.statusCode + ") !"
@ -205,6 +205,17 @@ class WebdavTools {
});
}
getFolderContent(path) {
return new Promise((resolve, reject) => {
this.client.getDirectoryContents(path)
.then((contents)=>{
resolve(contents);
}).catch((error)=>{
reject(error);
})
});
}

View File

@ -0,0 +1,48 @@
<% if (locals.backups) { %>
<div class="collection">
<% for(const index in backups) { %>
<a class="collection-item local-snap-listener modal-trigger" href="#modal-<%=backups[index].etag%>"
data-id="<%= backups[index].etag %>">
<div><%= backups[index].basename%><div class="secondary-content">
<%= moment(backups[index].lastmod).format('MMM D, YYYY HH:mm') %></div>
</div>
</a>
<div id="modal-<%=backups[index].etag%>" class="modal modal-fixed-footer blue-grey darken-4 white-text">
<div class="modal-content">
<div class="row">
<div class="col s12 center">
<h4>Backup Detail</h2>
</div>
</div>
<div class="row">
<div class="col s12 center divider">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input disabled type="text" id="name-<%=backups[index].etag%>" value="<%= backups[index].basename %>" />
<label for="name-<%=backups[index].etag%>" class="white-text active">Name</label>
</div>
<div class="input-field col s12">
<input disabled type="text" id="date-<%=backups[index].etag%>"
value="<%=moment(backups[index].lastmod).format('MMM D, YYYY HH:mm')%>" />
<label for="date-<%=backups[index].etag%>" class="white-text active">Date</label>
</div>
</div>
</div>
<div class="modal-footer blue-grey darken-4">
<a href="#!" class="modal-close waves-effect waves-green btn red">Close</a>
</div>
</div>
<% } %>
</div>
<% } %>

View File

@ -131,14 +131,16 @@
</div>
<div class="col s12 m3">
<div class="card cyan darken-3">
<div class="card-content" >
<div class="card-content">
<span class="card-title white-text" style="font-weight: bold;">Manual </span>
<div class="divider"></div>
<div style="width: 100%;" class="center">
<a class="btn green center waves-effect waves-light" id="btn-backup-now" style="margin-top: 7px;">Backup Now</a>
<a class="btn center teal darken-4 waves-effect waves-light" id="btn-clean-now" style="margin-top: 7px;">Clean Now</a>
<a class="btn green center waves-effect waves-light" id="btn-backup-now" style="margin-top: 7px;">Backup
Now</a>
<a class="btn center teal darken-4 waves-effect waves-light" id="btn-clean-now"
style="margin-top: 7px;">Clean Now</a>
</div>
</div>
</div>
</div>
@ -154,6 +156,19 @@
</div>
</div>
</div>
<div class="col s12 m12 l6 ">
<div class="card cyan darken-3">
<div class="card-content">
<span class="card-title center white-text">Nextcloud Backups</span>
<span class="card-title center white-text">Auto</span>
<span class="card-title center white-text divider"></span>
<div id="auto_backups"></div>
<span class="card-title center white-text">Manu</span>
<span class="card-title center white-text divider"></span>
<div id="manual_backups"></div>
</div>
</div>
</div>
</div>
</div>
@ -353,6 +368,8 @@
<script>
var last_status = "";
var last_local_snap = "";
var last_manu_back = "";
var last_auto_back = "";
var loadingModal = null;
document.addEventListener('DOMContentLoaded', function() {
@ -369,34 +386,69 @@
});
function updateDynamicListeners() {
var elems = document.querySelectorAll('.collapsible');
M.Collapsible.init(elems, { accordion: true });
var modals = document.querySelectorAll('.modal:not(#modal-loading)');
M.Modal.init(modals, { dismissible: false });
let loadingModals = document.querySelectorAll('#modal-loading');
M.Modal.init(loadingModals, { dismissible: false });
loadingModal = M.Modal.getInstance(document.querySelector('#modal-loading'));
$('.local-snap-listener').click(function() {
let id = this.getAttribute('data-id');
console.log(id);
});
$('.manual-back-list').click(function() {
let id = this.getAttribute('data-id');
let name = this.getAttribute('data-name');
manualBackup(id, name);
})
}
function updateLocalSnaps() {
let needUpdate = false;
$.get('./api/formated-local-snap', (data) => {
if (JSON.stringify(data) === last_local_snap)
if (JSON.stringify(data) === last_local_snap)
return;
last_local_snap = JSON.stringify(data);
needUpdate = true;
$('#local_snaps').empty();
$('#local_snaps').html(data);
}).always(() => {
updateManuBackup(needUpdate);
});
}
var elems = document.querySelectorAll('.collapsible');
M.Collapsible.init(elems, { accordion: true });
var modals = document.querySelectorAll('.modal:not(#modal-loading)');
M.Modal.init(modals, { dismissible: false });
function updateManuBackup(prevUpdate) {
let needUpdate = false;
$.get('./api/formated-backup-manual', (data) => {
if (JSON.stringify(data) === last_manu_back)
return;
last_manu_back = JSON.stringify(data);
needUpdate = true;
$('#manual_backups').empty();
$('#manual_backups').html(data);
let loadingModals = document.querySelectorAll('#modal-loading');
M.Modal.init(loadingModals, { dismissible: false });
loadingModal = M.Modal.getInstance(document.querySelector('#modal-loading'));
$('.local-snap-listener').click(function() {
let id = this.getAttribute('data-id');
console.log(id);
});
$('.manual-back-list').click(function() {
let id = this.getAttribute('data-id');
let name = this.getAttribute('data-name');
manualBackup(id, name);
})
}).always(() => {
updateAutoBackup(prevUpdate || needUpdate);
});
}
function updateAutoBackup(prevUpdate) {
let needUpdate = false;
$.get('./api/formated-backup-auto', (data) => {
if (JSON.stringify(data) === last_auto_back)
return;
needUpdate = true;
last_auto_back = JSON.stringify(data);
$('#auto_backups').empty();
$('#auto_backups').html(data);
}).always(() => {
if (prevUpdate || needUpdate)
updateDynamicListeners();
});
}
@ -407,23 +459,23 @@
switch (data.status) {
case "error":
printStatus('Error', data.message);
$('#btn-backup-now').removeClass("disabled");
$('#btn-backup-now, #btn-clean-now').removeClass("disabled");
break;
case "idle":
printStatus('Idle', "Waiting for next backup.");
$('#btn-backup-now').removeClass("disabled");
$('#btn-backup-now, #btn-clean-now').removeClass("disabled");
break;
case "download":
printStatusWithBar('Downloading Snapshot', data.progress);
$('#btn-backup-now').addClass("disabled");
$('#btn-backup-now, #btn-clean-now').addClass("disabled");
break;
case "upload":
printStatusWithBar('Uploading Snapshot', data.progress);
$('#btn-backup-now').addClass("disabled");
$('#btn-backup-now, #btn-clean-now').addClass("disabled");
break;
case "creating":
printStatusWithBar('Creating Snapshot', data.progress);
$('#btn-backup-now').addClass("disabled");
$('#btn-backup-now, #btn-clean-now').addClass("disabled");
break;
}
if (data.last_backup != null) {
@ -629,9 +681,9 @@
.done(() => {
M.toast({ html: '<i class="material-icons" style="margin-right:10px">check_box</i> Backup settings saved !', classes: "green" });
M.Modal.getInstance(document.querySelector('#modal-settings-backup')).close();
}).fail(()=>{
}).fail(() => {
M.toast({ html: '<i class="material-icons" style="margin-right:10px">warning</i> Can\'t save backup settings !', classes: "red" });
}).always(()=>{
}).always(() => {
loadingModal.close();
});
}