mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Merge pull request #110 from zamentur/backup
[enh] Allow backup/restore
This commit is contained in:
commit
8d79e2f577
11 changed files with 8866 additions and 25 deletions
|
@ -449,3 +449,7 @@ a.list-group-item-heading,
|
||||||
.clearfix();
|
.clearfix();
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label .list-group-item-text {
|
||||||
|
font-weight:normal;
|
||||||
|
}
|
||||||
|
|
4
src/dist/css/style.min.css
vendored
4
src/dist/css/style.min.css
vendored
File diff suppressed because one or more lines are too long
8312
src/dist/js/script.min.js
vendored
8312
src/dist/js/script.min.js
vendored
File diff suppressed because one or more lines are too long
219
src/js/app.js
219
src/js/app.js
|
@ -304,6 +304,7 @@ var app = Sammy('#main', function (sam) {
|
||||||
.click(function(e){
|
.click(function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
$('#modal footer button').unbind( "click" );
|
||||||
// Reset & Hide modal
|
// Reset & Hide modal
|
||||||
box
|
box
|
||||||
.removeClass('no-title')
|
.removeClass('no-title')
|
||||||
|
@ -340,7 +341,67 @@ var app = Sammy('#main', function (sam) {
|
||||||
return arr1.filter(function (a) {
|
return arr1.filter(function (a) {
|
||||||
return ((arr2.indexOf(a) == -1) && (a !== ""));
|
return ((arr2.indexOf(a) == -1) && (a !== ""));
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
groupHooks: function(hooks) {
|
||||||
|
data={};
|
||||||
|
var rules=[
|
||||||
|
{
|
||||||
|
id:'configuration',
|
||||||
|
isIn:function (hook) {
|
||||||
|
return hook.indexOf('conf_')==0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
$.each(hooks, function(i, hook) {
|
||||||
|
var group_id=hook;
|
||||||
|
$.each(rules, function(i, rule) {
|
||||||
|
if (rule.isIn(hook))
|
||||||
|
{
|
||||||
|
group_id='adminjs_group_'+rule.id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(group_id in data)
|
||||||
|
data[group_id]={
|
||||||
|
name:y18n.t('hook_'+group_id),
|
||||||
|
value:data[group_id].value+','+hook,
|
||||||
|
description:data[group_id].description+', '+y18n.t('hook_'+hook)
|
||||||
|
};
|
||||||
|
else
|
||||||
|
data[group_id]={
|
||||||
|
name:y18n.t('hook_'+group_id),
|
||||||
|
value:hook,
|
||||||
|
description:(group_id==hook)?y18n.t('hook_desc_'+hook):y18n.t('hook_'+hook)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
ungroupHooks: function(hooks,apps) {
|
||||||
|
var data={};
|
||||||
|
data['apps']=apps;
|
||||||
|
data['hooks']=hooks;
|
||||||
|
if (data['hooks']==undefined)
|
||||||
|
data['hooks']=[];
|
||||||
|
else if (data['hooks'].constructor !== Array)
|
||||||
|
data['hooks']=[data['hooks']];
|
||||||
|
if (data['apps']==undefined)
|
||||||
|
data['apps']=[];
|
||||||
|
else if (data['apps'].constructor !== Array)
|
||||||
|
data['apps']=[params['apps']];
|
||||||
|
if (data['hooks'].length==0)
|
||||||
|
data['ignore_hooks']='';
|
||||||
|
if (data['apps'].length==0)
|
||||||
|
data['ignore_apps']='';
|
||||||
|
var split_hooks=[];
|
||||||
|
$.each(data['hooks'], function(i, hook) {
|
||||||
|
split_hooks.concat(hook.split(','));
|
||||||
|
});
|
||||||
|
data['hooks']=split_hooks;
|
||||||
|
return data;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1820,11 +1881,165 @@ var app = Sammy('#main', function (sam) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Backup view
|
var config_hooks = [
|
||||||
|
'system_ldap',
|
||||||
|
'system_ssowat',
|
||||||
|
'system_cron',
|
||||||
|
'system_ssh',
|
||||||
|
'system_xmpp',
|
||||||
|
'system_mysql',
|
||||||
|
'system_yunohost',
|
||||||
|
'system_nginx'
|
||||||
|
];
|
||||||
|
// Storage list
|
||||||
sam.get('#/backup', function (c) {
|
sam.get('#/backup', function (c) {
|
||||||
c.view('backup/backup');
|
var storages = [];
|
||||||
|
|
||||||
|
var item = {
|
||||||
|
id: 'local',
|
||||||
|
name: y18n.t('local_archives'),
|
||||||
|
uri: '/home/yunohost.backup/'
|
||||||
|
};
|
||||||
|
storages.push(item);
|
||||||
|
|
||||||
|
c.view('backup/backup', {'storages':storages});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Storage list
|
||||||
|
sam.get('#/storages/create', function (c) {
|
||||||
|
c.view('backup/storage_create', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a storage
|
||||||
|
sam.post('#/storages', function (c) {
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/storages');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a backup
|
||||||
|
sam.get('#/backup/:storage/create', function (c) {
|
||||||
|
var data=[];
|
||||||
|
data['storage']={
|
||||||
|
id:c.params['storage'],
|
||||||
|
name:y18n.t('local_archives')
|
||||||
|
};
|
||||||
|
c.api('/hooks/backup', function(hooks) {
|
||||||
|
data['hooks']=c.groupHooks(hooks['hooks']);
|
||||||
|
data['apps']={};
|
||||||
|
c.api('/apps?raw', function(apps) { // http://api.yunohost.org/#!/app/app_list_get_8
|
||||||
|
$.each(apps, function(app_id, app) {
|
||||||
|
if (app['installed'])
|
||||||
|
data['apps'][app_id]={
|
||||||
|
name: app['manifest']['name']
|
||||||
|
};
|
||||||
|
});
|
||||||
|
c.view('backup/backup_create', data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
sam.post('#/backup/:storage', function (c) {
|
||||||
|
var params = c.ungroupHooks(c.params['hooks'],c.params['apps']);
|
||||||
|
c.api('/backup', function() {
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']);
|
||||||
|
}, 'POST', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restore a backup
|
||||||
|
sam.post('#/backup/:storage/:archive/restore', function (c) {
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('backup'),
|
||||||
|
y18n.t('confirm_restore', [c.params['archive']]),
|
||||||
|
$.proxy(function(c){
|
||||||
|
var params=c.ungroupHooks(c.params['hooks'],c.params['apps']);
|
||||||
|
params['force']='';
|
||||||
|
c.api('/backup/restore/'+c.params['archive'], function(data) {
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
}, 'POST', params);
|
||||||
|
},this,c),
|
||||||
|
function(){
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete a backup
|
||||||
|
sam.get('#/backup/:storage/:archive/delete', function (c) {
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('backup'),
|
||||||
|
y18n.t('confirm_delete', [c.params['archive']]),
|
||||||
|
function(){
|
||||||
|
c.api('/backup/archives/'+c.params['archive'], function(data) {
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']);
|
||||||
|
}, 'DELETE');
|
||||||
|
},
|
||||||
|
function(){
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Download a backup
|
||||||
|
sam.get('#/backup/:storage/:archive/download', function (c) {
|
||||||
|
c.api('/backup/'+c.params['archive']+'/download', function(data) {
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
}, 'GET');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy a backup
|
||||||
|
sam.get('#/backup/:storage/:archive/copy', function (c) {
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upload a backup
|
||||||
|
sam.get('#/backup/:storage/:archive/upload', function (c) {
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Get archive info
|
||||||
|
sam.get('#/backup/:storage/:archive', function (c) {
|
||||||
|
c.api('/backup/archives/'+c.params['archive']+'?with_details', function(data) {
|
||||||
|
data['storage']={
|
||||||
|
id:c.params['storage'],
|
||||||
|
name:y18n.t('local_archives')
|
||||||
|
};
|
||||||
|
data['other_storages']=[];
|
||||||
|
data['name']=c.params['archive'];
|
||||||
|
data['hooks']=c.groupHooks(Object.keys(data['hooks']));
|
||||||
|
data['items']=(data['hooks']!={} || data['apps']!=[]);
|
||||||
|
c.view('backup/backup_info', data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Archive list
|
||||||
|
sam.get('#/backup/:storage', function (c) {
|
||||||
|
c.api('/backup/archives?with_info', function(data) {
|
||||||
|
data['storage']={
|
||||||
|
id:'local',
|
||||||
|
name:y18n.t('local_archives')
|
||||||
|
};
|
||||||
|
data['archives2']=[];
|
||||||
|
$.each(data['archives'], function(name, info) {
|
||||||
|
info['name']=name;
|
||||||
|
data['archives2'].unshift(info)
|
||||||
|
});
|
||||||
|
data['archives']=data['archives2'];
|
||||||
|
c.view('backup/backup_list', data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -243,5 +243,43 @@
|
||||||
"user_new_mail": "newmail@mydomain.org",
|
"user_new_mail": "newmail@mydomain.org",
|
||||||
"user_new_forward": "newforward@myforeigndomain.org",
|
"user_new_forward": "newforward@myforeigndomain.org",
|
||||||
"user_mailbox_quota": "Mailbox quota",
|
"user_mailbox_quota": "Mailbox quota",
|
||||||
"mailbox_quota_description": "Mailbox quota must be a size with b/k/M/G/T suffix or 0 to disable the quota."
|
"mailbox_quota_description": "Mailbox quota must be a size with b/k/M/G/T suffix or 0 to disable the quota.",
|
||||||
|
|
||||||
|
"local_archives": "Local archives",
|
||||||
|
"storages_new": "New remote storage",
|
||||||
|
"storages_no": "No storages.",
|
||||||
|
"backup_new": "New backup",
|
||||||
|
"backups_no": "No backup",
|
||||||
|
"upload_archive": "Archive upload",
|
||||||
|
"upload": "Upload",
|
||||||
|
"archive_empty": "Empty archive",
|
||||||
|
"backup_archive_delete": "Delete this archive",
|
||||||
|
"backup_archive_copy": "Copy this archive on another storage",
|
||||||
|
"copy": "Copy",
|
||||||
|
"backup_create": "Create a backup",
|
||||||
|
"restore": "Restore",
|
||||||
|
"download": "Download",
|
||||||
|
"hook_data_home": "User data",
|
||||||
|
"hook_desc_data_home": "User data located in /home/USER",
|
||||||
|
"hook_data_mail": "Mail",
|
||||||
|
"hook_desc_data_mail": "Mail which are on the server",
|
||||||
|
"hook_conf_ldap": "LDAP",
|
||||||
|
"hook_conf_ssh": "SSH",
|
||||||
|
"hook_conf_ynh_mysql": "Password MySQL",
|
||||||
|
"hook_conf_nginx": "Nginx",
|
||||||
|
"hook_conf_cron": "Regular tasks",
|
||||||
|
"hook_conf_xmpp": "XMPP",
|
||||||
|
"hook_conf_ynh_firewall": "Firewall",
|
||||||
|
"hook_conf_ynh_certs": "Security certificates",
|
||||||
|
"hook_conf_ssowat": "SSOwat",
|
||||||
|
"hook_adminjs_group_configuration": "Configuration",
|
||||||
|
"backup_optional_encryption": "Optional encryption",
|
||||||
|
"backup_optional_password": "Optional password",
|
||||||
|
"backup_encryption_warning": "Don't forget this password, you will need it if you want restore the archive",
|
||||||
|
"backup_action": "Backup",
|
||||||
|
"backup_archive_download": "Download this archive",
|
||||||
|
"storage_create": "Add a remote storage",
|
||||||
|
"confirm_restore": "Are you sure you want to restore %s ?",
|
||||||
|
"backup_type": "Type",
|
||||||
|
"path": "Path"
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,5 +224,43 @@
|
||||||
"user_emailaliases": "Adresses supplémentaires",
|
"user_emailaliases": "Adresses supplémentaires",
|
||||||
"user_emailforward": "Adresses de transfert",
|
"user_emailforward": "Adresses de transfert",
|
||||||
"user_new_mail": "nouvelle_adresse@domaine.org",
|
"user_new_mail": "nouvelle_adresse@domaine.org",
|
||||||
"user_new_forward": "nouveau_transfert@domainedistant.org"
|
"user_new_forward": "nouveau_transfert@domainedistant.org",
|
||||||
|
|
||||||
|
"local_archives": "Archives locales",
|
||||||
|
"storages_new": "Nouveau stockage distant",
|
||||||
|
"storages_no": "Aucun stockage.",
|
||||||
|
"backup_new": "Nouvelle sauvegarde",
|
||||||
|
"backups_no": "Aucune sauvegarde.",
|
||||||
|
"upload_archive": "Uploader une sauvegarde",
|
||||||
|
"upload": "Uploader",
|
||||||
|
"archive_empty": "La sauvegarde est vide.",
|
||||||
|
"backup_archive_delete": "Supprimer cette sauvegarde",
|
||||||
|
"backup_archive_copy": "Copier cette sauvegarde sur un autre stockage",
|
||||||
|
"copy": "Copier",
|
||||||
|
"backup_create": "Créer une sauvegarde",
|
||||||
|
"restore": "Restorer",
|
||||||
|
"download": "Télécharger",
|
||||||
|
"hook_data_home": "Données utilisateurs",
|
||||||
|
"hook_desc_data_home": "Les données des utilisateurs situées dans /home/USER",
|
||||||
|
"hook_data_mail": "Mail",
|
||||||
|
"hook_desc_data_mail": "Les mails qui sont encore sur le serveur",
|
||||||
|
"hook_conf_ldap": "LDAP",
|
||||||
|
"hook_conf_ssh": "SSH",
|
||||||
|
"hook_conf_ynh_mysql": "Mot de passe MySQL",
|
||||||
|
"hook_conf_nginx": "Nginx",
|
||||||
|
"hook_conf_cron": "Tâches régulières",
|
||||||
|
"hook_conf_xmpp": "XMPP",
|
||||||
|
"hook_conf_ynh_firewall": "Pare-feu",
|
||||||
|
"hook_conf_ynh_certs": "Certificats de sécurité",
|
||||||
|
"hook_conf_ssowat": "SSOwat",
|
||||||
|
"hook_adminjs_group_configuration": "Configuration",
|
||||||
|
"backup_optional_encryption": "Chiffrement optionnel",
|
||||||
|
"backup_optional_password": "Mot de passe optionnel",
|
||||||
|
"backup_encryption_warning": "N'oubliez pas ce mot de passe, vous en aurez besoin pour restaurer cette sauvegarde",
|
||||||
|
"backup_action": "Sauvegarder",
|
||||||
|
"backup_archive_download": "Télécharger cette sauvegarde",
|
||||||
|
"storage_create": "Ajouter un stockage distant",
|
||||||
|
"confirm_restore": "Êtes-vous sur de vouloir restaurer %s ?",
|
||||||
|
"backup_type": "Type",
|
||||||
|
"path": "Répertoire"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,30 @@
|
||||||
|
|
||||||
|
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/backup">{{t 'backup'}}</a>
|
<a href="#/backup" class="btn btn-default">{{t 'backup'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions-group">
|
||||||
|
<!--<a href="#/storages/create" class="btn btn-success slide">
|
||||||
|
<span class="fa-plus"></span> {{t 'storages_new'}}
|
||||||
|
</a>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="list-group">
|
||||||
|
{{#each storages}}
|
||||||
|
<a href="#/backup/{{id}}" class="list-group-item slide clearfix">
|
||||||
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
|
<h2 class="list-group-item-heading">{{name}} <small>{{id}}</small></h2>
|
||||||
|
<p class="list-group-item-text">{{uri}}</p>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
<span class="fa-exclamation-triangle"></span>
|
<span class="fa-exclamation-triangle"></span>
|
||||||
<strong>{{t 'backup_warning_title'}}</strong>
|
{{t 'storages_no'}}
|
||||||
<br>{{t 'backup_warning_desc'}}
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
50
src/views/backup/backup_create.ms
Normal file
50
src/views/backup/backup_create.ms
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/backup" class="btn btn-default">{{t 'backup'}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}" class="btn btn-default">{{storage.name}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}/create" class="btn btn-default">{{t 'backup_create'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<form action="#/backup/{{storage.id}}" method="POST" class="form-horizontal">
|
||||||
|
<div class="list-group">
|
||||||
|
{{#each hooks}}
|
||||||
|
<label for="{{@key}}" class="list-group-item">
|
||||||
|
<span class="pull-right"><input type="checkbox" id="{{@key}}" name="hooks" value="{{value}}" checked></span>
|
||||||
|
<h2 class="list-group-item-heading">{{name}}</h2>
|
||||||
|
<p class="list-group-item-text">{{description}}</p>
|
||||||
|
</label>
|
||||||
|
{{/each}}
|
||||||
|
{{#each apps}}
|
||||||
|
<label for="{{id}}" class="list-group-item">
|
||||||
|
<span class="pull-right"><input type="checkbox" id="{{id}}" name="apps" value="{{id}}" checked></span>
|
||||||
|
<h2 class="list-group-item-heading">{{name}} <small>{{id}}</small></h2>
|
||||||
|
</label>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<!--<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title"><span class="fa-fw fa-lock"></span> {{t 'backup_optional_encryption'}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<label for="label" class="col-sm-12">{{t 'password'}}</label>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<input type="password" id="password" name="password" class="form-control" placeholder="{{t 'backup_optional_password'}}">
|
||||||
|
<p class="text-warning">
|
||||||
|
{{t 'backup_encryption_warning'}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator"></div>-->
|
||||||
|
<span class="pull-right">
|
||||||
|
<input type="submit" class="btn btn-success slide back" value="{{t 'backup_action'}}" />
|
||||||
|
</span>
|
||||||
|
</form>
|
87
src/views/backup/backup_info.ms
Normal file
87
src/views/backup/backup_info.ms
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/backup" class="btn btn-default">{{t 'backup'}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}" class="btn btn-default">{{storage.name}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}/{{name}}" class="btn btn-default">{{name}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<form action="#/backup/{{storage.id}}/{{name}}/restore" method="POST" class="form-horizontal">
|
||||||
|
<div class="list-group">
|
||||||
|
{{#each hooks}}
|
||||||
|
<label for="{{@key}}" class="list-group-item">
|
||||||
|
<span class="pull-right"><input type="checkbox" id="{{@key}}" name="hooks" value="{{value}}" checked></span>
|
||||||
|
<h2 class="list-group-item-heading">{{name}}</h2>
|
||||||
|
<p class="list-group-item-text">{{description}}</p>
|
||||||
|
</label>
|
||||||
|
{{/each}}
|
||||||
|
{{#each apps}}
|
||||||
|
<label for="{{id}}" class="list-group-item">
|
||||||
|
<span class="pull-right"><input type="checkbox" id="{{id}}" name="apps" value="{{id}}" checked></span>
|
||||||
|
<h2 class="list-group-item-heading">{{name}} <small>{{id}}</small></h2>
|
||||||
|
</label>
|
||||||
|
{{/each}}
|
||||||
|
{{^items}}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<span class="fa-exclamation-triangle"></span>
|
||||||
|
{{t 'archive_empty'}}
|
||||||
|
</div>
|
||||||
|
{{/items}}
|
||||||
|
</div>
|
||||||
|
{{#if items}}
|
||||||
|
<span class="pull-right">
|
||||||
|
<input type="submit" class="btn btn-danger slide back" value="{{t 'restore'}}" />
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
<span class="fa-fw fa-wrench"></span> {{t 'operations'}}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<!--<div class="container">
|
||||||
|
<p>{{t 'backup_archive_download'}}</p>
|
||||||
|
<a class="btn btn-info slide" href="#/backup/{{storage.id}}/{{name}}/download">
|
||||||
|
<span class="fa-download"></span> {{t 'download'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<hr>-->
|
||||||
|
<div class="container">
|
||||||
|
<p>{{t 'backup_archive_delete'}}</p>
|
||||||
|
<a href="#/backup/{{storage.id}}/{{name}}/delete" class="btn btn-danger slide">
|
||||||
|
<span class="fa-trash"></span> {{t 'delete'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{#if other_storages}}
|
||||||
|
<hr>
|
||||||
|
<div class="container">
|
||||||
|
<p>{{t 'backup_archive_copy'}}</p>
|
||||||
|
<form action="#/backup/{{storage.id}}/{{name}}/copy" method="POST" class="form-horizontal">
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<label for="label" class="col-sm-12">{{t 'url'}}</label>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<select id="storage" name="storage" class="form-control" required>
|
||||||
|
{{#each storages}}
|
||||||
|
<option value="{{id}}">{{name}} ({{uri}})</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="text-center">
|
||||||
|
<input type="submit" class="btn btn-success slide" value="{{t 'copy'}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
53
src/views/backup/backup_list.ms
Normal file
53
src/views/backup/backup_list.ms
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/backup" class="btn btn-default">{{t 'backup'}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}" class="btn btn-default">{{storage.name}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions-group">
|
||||||
|
<a href="#/backup/{{storage.id}}/create" class="btn btn-success slide">
|
||||||
|
<span class="fa-plus"></span> {{t 'backup_new'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="list-group">
|
||||||
|
{{#each archives}}
|
||||||
|
<a href="#/backup/{{../storage.id}}/{{name}}" class="list-group-item slide clearfix">
|
||||||
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
|
<h2 class="list-group-item-heading">{{created_at}} <small>{{name}} ({{humanSize size}})</small></h2>
|
||||||
|
<p class="list-group-item-text">{{path}}</p>
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
||||||
|
{{^archives}}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<span class="fa-exclamation-triangle"></span>
|
||||||
|
{{t 'backups_no'}}
|
||||||
|
</div>
|
||||||
|
{{/archives}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title"><span class="fa-fw fa-download"></span> {{t 'upload_archive'}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form action="#/backup/{{storage.id}}/upload" method="POST" class="form-horizontal">
|
||||||
|
<div class="form-group has-feedback">
|
||||||
|
<label for="label" class="col-sm-12">{{t 'url'}}</label>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<input type="file" id="url" name="url" value="" required pattern="^.*\.tar\.gz$">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="text-center">
|
||||||
|
<input type="submit" class="btn btn-success slide" value="{{t 'upload'}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>-->
|
52
src/views/backup/storage_create.ms
Normal file
52
src/views/backup/storage_create.ms
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/backup" class="btn btn-default">{{t 'backup'}}</a>
|
||||||
|
<a href="#/backup/{{storage.id}}/create" class="btn btn-default">{{t 'storage_create'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<form action="#/storages" method="POST" class="form-horizontal">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="type" class="col-sm-3 control-label">{{t 'backup_type'}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select class="form-control" name="type">
|
||||||
|
<option>sftp</option>
|
||||||
|
<option>ftp</option>
|
||||||
|
<option>rsync</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="domain" class="col-sm-3 control-label">{{t 'domain'}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" id="domain" name="domain" class="form-control" placeholder="monserver.fr" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="username" class="col-sm-3 control-label">{{t 'user_username'}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" id="username" name="username" class="form-control" placeholder="johndoe" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password" class="col-sm-3 control-label">{{t 'password'}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="password" id="password" name="password" class="form-control" placeholder="•••••" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="path" class="col-sm-3 control-label">{{t 'path'}}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" id="path" name="path" class="form-control" placeholder="~/" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<input type="submit" class="btn btn-success slide back" value="{{t 'save'}}">
|
||||||
|
</div>
|
||||||
|
</form>
|
Loading…
Add table
Reference in a new issue