423 lines
25 KiB
HTML
423 lines
25 KiB
HTML
<!-- Modal details -->
|
|
<div class="modal fade" id="backupDetailsModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Backup Details</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-xs-3 text-muted">Id:</div>
|
|
<div class="col-xs-9 text-right">{{ backupDetails.backup.id }}</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-3 text-muted">Date:</div>
|
|
<div class="col-xs-9 text-right">{{ backupDetails.backup.creationTime | prettyLongDate }}</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-3 text-muted">Version:</div>
|
|
<div class="col-xs-9 text-right">v{{ backupDetails.backup.packageVersion }}</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-3 text-muted">Format:</div>
|
|
<div class="col-xs-9 text-right">{{ backupDetails.backup.format }}</div>
|
|
</div>
|
|
<br/>
|
|
<p class="text-muted">References backups of {{ backupDetails.backup.contents.length }} apps:</p>
|
|
<span ng-repeat="app in backupDetails.backup.contents | orderBy:['label','fqdn']">
|
|
<a ng-href="/#/app/{{app.id}}/backups">{{app.label || app.fqdn}}</a><span ng-hide="$last">,</span>
|
|
</span>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal backup failed -->
|
|
<div class="modal fade" id="createBackupFailedModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Unable to create backup</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
{{ createBackup.errorMessage }}
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-success" data-dismiss="modal">OK</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- modal backup config -->
|
|
<div class="modal fade" id="configureScheduleAndRetentionModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Configure Backup Schedule and Retention</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form name="configureScheduleAndRetentionForm" role="form" novalidate ng-submit="configureScheduleAndRetention.submit()" autocomplete="off">
|
|
<fieldset>
|
|
<p class="has-error text-center" ng-show="configureScheduleAndRetention.error">{{ configureScheduleAndRetention.error.generic }}</p>
|
|
|
|
<div class="form-group">
|
|
<label class="control-label" for="storageInterval">Backup Interval</label>
|
|
<select class="form-control" id="storageInterval" ng-model="configureScheduleAndRetention.intervalSecs" ng-options="a.value as a.name for a in intervalTimes"></select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="control-label" for="storageRetention">Retention Policy</label>
|
|
<select class="form-control" id="storageRetention" ng-model="configureScheduleAndRetention.retentionPolicy" ng-options="a.value as a.name for a in retentionPolicies"></select>
|
|
</div>
|
|
|
|
</fieldset>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer ">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-outline btn-success pull-right" ng-click="configureScheduleAndRetention.submit()" ng-disabled="configureScheduleAndRetention.$invalid || configureScheduleAndRetention.busy"><i class="fa fa-circle-notch fa-spin" ng-show="configureScheduleAndRetention.busy"></i><span> Save</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- modal backup config -->
|
|
<div class="modal fade" id="configureBackupModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h4 class="modal-title">Configure Backup Storage</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form name="configureBackupForm" role="form" novalidate ng-submit="configureBackup.submit()" autocomplete="off">
|
|
<fieldset>
|
|
<p class="has-error text-center" ng-show="configureBackup.error">{{ configureBackup.error.generic }}</p>
|
|
|
|
<div class="form-group">
|
|
<label class="control-label" for="storageProviderProvider">Storage provider <sup><a ng-href="{{ config.webServerOrigin }}/documentation/backups/#storage-providers" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
|
<p class="small text-info" ng-show="backupConfig.provider !== configureBackup.provider">Backups in the old storage location have to be removed manually.</p>
|
|
<select class="form-control" id="storageProviderProvider" ng-model="configureBackup.provider" ng-options="a.value as a.name for a in storageProvider" ng-change=configureBackup.clearProviderFields()></select>
|
|
</div>
|
|
|
|
<!-- Noop -->
|
|
<div class="form-group" ng-show="configureBackup.provider === 'noop'">
|
|
<p class="has-error">
|
|
This option breaks the backup and restore functionality of Cloudron and should only be used for testing. Please make sure the server is completely backed up using alternate means.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- SSHFS/CIFS/NFS -->
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.mountPoint || (configureBackupForm.mountPoint.$dirty && !configureBackup.mountPoint) }" ng-show="mountlike(configureBackup.provider)">
|
|
<label class="control-label" for="inputConfigureMountPoint">Mount point</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.mountPoint" id="inputConfigureMountPoint" name="mountPoint" ng-disabled="configureBackup.busy" placeholder="Folder where filesystem is mounted" ng-required="mountlike(configureBackup.provider)">
|
|
<p>The mount point has to be setup manually. See <a ng-href="{{ config.webServerOrigin }}/documentation/backups/#{{ configureBackup.provider }}" target="_blank">docs</a>.</p>
|
|
</div>
|
|
|
|
<!-- Filesystem -->
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.backupFolder || !configureBackup.backupFolder }" ng-show="configureBackup.provider === 'filesystem'">
|
|
<label class="control-label" for="inputConfigureBackupFolder">Local backup directory</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.backupFolder" id="inputConfigureBackupFolder" name="backupFolder" ng-disabled="configureBackup.busy" placeholder="Directory for backups" ng-required="configureBackup.provider === 'filesystem'">
|
|
</div>
|
|
|
|
<div class="checkbox" ng-show="configureBackup.provider === 'filesystem'">
|
|
<label>
|
|
<input type="checkbox" ng-model="configureBackup.externalDisk" id="inputConfigureExternalDisk">Backup directory is an external EXT4 Disk</input>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Filesystem/SSHFS/CIFS/NFS -->
|
|
<div class="checkbox" ng-show="configureBackup.provider === 'filesystem' || mountlike(configureBackup.provider)">
|
|
<label>
|
|
<input type="checkbox" ng-model="configureBackup.useHardlinks" id="inputConfigureUseHardlinks">Use hardlinks</input>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- S3/Minio/SOS/GCS -->
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.endpoint }" ng-show="configureBackup.provider === 'minio' || configureBackup.provider === 's3-v4-compat'">
|
|
<label class="control-label" for="inputConfigureBackupEndpoint">Endpoint</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.endpoint" id="inputConfigureBackupEndpoint" name="endpoint" ng-disabled="configureBackup.busy" placeholder="URL of Minio/S3 Compatible" ng-required="configureBackup.provider === 'minio' || configureBackup.provider === 's3-v4-compat'">
|
|
</div>
|
|
|
|
<div class="checkbox" ng-show="configureBackup.provider === 'minio' || configureBackup.provider === 's3-v4-compat'" >
|
|
<label>
|
|
<input type="checkbox" ng-model="configureBackup.acceptSelfSignedCerts" id="inputConfigureBackupSelfSigned">Accept Self-signed certificate</input>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.bucket }" ng-show="s3like(configureBackup.provider) || configureBackup.provider === 'gcs'">
|
|
<label class="control-label" for="inputConfigureBackupBucket">Bucket name</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.bucket" id="inputConfigureBackupBucket" name="bucket" ng-disabled="configureBackup.busy" ng-required="s3like(configureBackup.provider)">
|
|
</div>
|
|
|
|
<!-- S3/Minio/SOS/GCS/SSHFS/CIFS/NFS -->
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.prefix }" ng-show="configureBackup.provider !== 'filesystem' && configureBackup.provider !== 'noop'">
|
|
<label class="control-label" for="inputConfigureBackupPrefix">Prefix</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.prefix" id="inputConfigureBackupPrefix" name="prefix" ng-disabled="configureBackup.busy" placeholder="Prefix for backup file names">
|
|
</div>
|
|
|
|
<!-- S3/Minio/SOS/GCS -->
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 's3'">
|
|
<label class="control-label" for="inputConfigureBackupS3Region">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupS3Region" ng-model="configureBackup.region" ng-options="a.value as a.name for a in s3Regions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 's3'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 's3-v4-compat'">
|
|
<label class="control-label" for="inputConfigureBackupS3V4CompatRegion">Region</label>
|
|
<input class="form-control" type="text" name="region" id="inputConfigureBackupS3V4CompatRegion" ng-model="configureBackup.region" ng-disabled="configureBackup.busy" placeholder="Leave empty to use us-east-1 as default"></input>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'digitalocean-spaces'">
|
|
<label class="control-label" for="inputConfigureBackupDORegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupDORegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in doSpacesRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'digitalocean-spaces'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'exoscale-sos'">
|
|
<label class="control-label" for="inputConfigureBackupExoscaleRegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupExoscaleRegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in exoscaleSosRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'exoscale-sos'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'wasabi'">
|
|
<label class="control-label" for="inputConfigureBackupWasabiRegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupWasabiRegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in wasabiRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'wasabi'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'scaleway-objectstorage'">
|
|
<label class="control-label" for="inputConfigureBackupScalewayRegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupScalewayRegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in scalewayRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'scaleway-objectstorage'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'linode-objectstorage'">
|
|
<label class="control-label" for="inputConfigureBackupLinodeRegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupLinodeRegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in linodeRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'linode-objectstorage'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.region }" ng-show="configureBackup.provider === 'ovh-objectstorage'">
|
|
<label class="control-label" for="inputConfigureBackupOvhRegion">Region</label>
|
|
<select class="form-control" name="region" id="inputConfigureBackupOvhRegion" ng-model="configureBackup.endpoint" ng-options="a.value as a.name for a in ovhRegions" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'ovh-objectstorage'"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.accessKeyId }" ng-show="s3like(configureBackup.provider)">
|
|
<label class="control-label" for="inputConfigureBackupAccessKeyId">Access key id</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.accessKeyId" id="inputConfigureBackupAccessKeyId" name="accessKeyId" ng-disabled="configureBackup.busy" ng-required="s3like(configureBackup.provider)">
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.secretAccessKey }" ng-show="s3like(configureBackup.provider)">
|
|
<label class="control-label" for="inputConfigureBackupSecretAccessKey">Secret access key</label>
|
|
<input type="text" class="form-control" ng-model="configureBackup.secretAccessKey" id="inputConfigureBackupSecretAccessKey" name="secretAccessKey" ng-disabled="configureBackup.busy" ng-required="s3like(configureBackup.provider)">
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.gcsKeyInput }" ng-show="configureBackup.provider === 'gcs'">
|
|
<label class="control-label" for="gcsKeyInput">Service Account Key</label>
|
|
|
|
<div class="input-group">
|
|
<input type="file" id="gcsKeyFileInput" style="display:none"/>
|
|
<input type="text" class="form-control" placeholder="Service Account Key" ng-model="configureBackup.gcsKey.keyFileName" id="gcsKeyInput" name="cert" onclick="getElementById('gcsKeyFileInput').click();" style="cursor: pointer;" ng-disabled="configureBackup.busy" ng-required="configureBackup.provider === 'gcs'">
|
|
<span class="input-group-addon">
|
|
<i class="fa fa-upload" onclick="getElementById('gcsKeyFileInput').click();"></i>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group" ng-show="configureBackup.provider !== 'noop'">
|
|
<label class="control-label" for="storageFormat">Storage Format <sup><a ng-href="{{ config.webServerOrigin }}/documentation/backups/#backup-formats" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
|
<p class="small text-info" ng-show="backupConfig.format !== configureBackup.format">Previous backups using the old storage format have to be removed manually.</p>
|
|
<select class="form-control" id="storageFormat" ng-model="configureBackup.format" ng-options="a.value as a.name for a in formats"></select>
|
|
</div>
|
|
|
|
<div class="form-group" ng-class="{ 'has-error': configureBackup.error.password }" ng-show="configureBackup.provider !== 'noop'">
|
|
<label class="control-label" for="inputConfigureBackupPassword">Encryption Password (optional) <sup><a ng-href="{{ config.webServerOrigin }}/documentation/backups/#encryption" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
|
<p class="small">Save this passphrase in a safe place. Cloudron does not store this password. Backups cannot be decrypted without the passphrase</p>
|
|
<input type="text" class="form-control" name="password" ng-model="configureBackup.password" id="inputConfigureBackupPassword" name="prefix" ng-disabled="configureBackup.busy" placeholder="Passphrase used to encrypt the backups">
|
|
</div>
|
|
|
|
<input class="ng-hide" type="submit" ng-disabled="configureBackupForm.$invalid"/>
|
|
</fieldset>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer ">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-outline btn-success pull-right" ng-click="configureBackup.submit()" ng-disabled="configureBackupForm.$invalid || configureBackup.busy"><i class="fa fa-circle-notch fa-spin" ng-show="configureBackup.busy"></i><span> Save</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
|
|
<div class="text-left">
|
|
<h1>Backups</h1>
|
|
</div>
|
|
|
|
<div class="text-left">
|
|
<h3>Location</h3>
|
|
</div>
|
|
|
|
<div class="card" style="margin-bottom: 15px;">
|
|
<p>Cloudron makes a complete backup of your system at the configured location.
|
|
<span ng-show="manualBackupApps.length">
|
|
The following apps have automatic backups disabled:
|
|
<span ng-repeat="app in manualBackupApps">
|
|
<a ng-href="/#/app/{{app.id}}/backups">{{app.label || app.fqdn}}</a><span ng-hide="$last">,</span>
|
|
</span>
|
|
</span>
|
|
</p>
|
|
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Provider</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span>{{ prettyProviderName(backupConfig.provider) }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Location</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span ng-show="backupConfig.provider === 'filesystem'">{{ backupConfig.backupFolder }}</span>
|
|
<span ng-show="mountlike(backupConfig.provider)">{{ backupConfig.mountPoint + (backupConfig.prefix ? '/' : '') + backupConfig.prefix }}</span>
|
|
<span ng-show="backupConfig.provider !== 's3' && backupConfig.provider !== 'minio' && (s3like(backupConfig.provider) || backupConfig.provider === 'gcs')">{{ backupConfig.bucket + (backupConfig.prefix ? '/' : '') + backupConfig.prefix }}</span>
|
|
<span ng-show="backupConfig.provider === 's3'">{{ backupConfig.region + ' ' + backupConfig.bucket + (backupConfig.prefix ? '/' : '') + backupConfig.prefix }}</span>
|
|
<span ng-show="backupConfig.provider === 'minio'">{{ backupConfig.endpoint + ' ' + backupConfig.bucket + (backupConfig.prefix ? '/' : '') + backupConfig.prefix }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" ng-show="backupConfig.endpoint && backupConfig.provider !== 'minio'">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Endpoint</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span>{{ backupConfig.endpoint || backupConfig.region }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Storage Format</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span>{{ backupConfig.format }} <i class="fas fa-lock" ng-show="backupConfig.password" ></i></span>
|
|
</div>
|
|
</div>
|
|
|
|
<br/>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12 text-right">
|
|
<button class="btn btn-outline btn-primary pull-right" ng-show="user.role === 'owner'" ng-click="configureBackup.show()">Configure</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-left">
|
|
<h3>Schedule and Retention</h3>
|
|
</div>
|
|
|
|
<div class="card" style="margin-bottom: 15px;">
|
|
<p>Cloudron makes a complete backup of your system based on this scheduled interval and keeps backups with the specified retention policy. </p>
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Interval</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span>{{ prettyBackupInterval(backupConfig.intervalSecs) }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-6">
|
|
<span class="text-muted">Retention Policy</span>
|
|
</div>
|
|
<div class="col-xs-6 text-right">
|
|
<span>{{ prettyBackupRetentionPolicy(backupConfig.retentionPolicy) }}</span>
|
|
</div>
|
|
</div>
|
|
<br/>
|
|
<div class="row">
|
|
<div class="col-md-12 text-right">
|
|
<button class="btn btn-outline btn-primary pull-right" ng-show="user.role === 'owner'" ng-click="configureScheduleAndRetention.show()">Configure</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-left">
|
|
<h3>Listing</h3>
|
|
</div>
|
|
|
|
<div class="card card-large">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<p ng-show="!backups.length">No backups have been made yet</p>
|
|
|
|
<table class="table table-hover" style="margin: 0;" ng-hide="!backups.length">
|
|
<thead>
|
|
<tr>
|
|
<th>Version</th>
|
|
<th>Date</th>
|
|
<th>Contents</th>
|
|
<th class="text-right" width="180px">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="backup in backups">
|
|
<td ng-click="backupDetails.show(backup)" class="hand">v{{ backup.packageVersion }}</td>
|
|
<td ng-click="backupDetails.show(backup)" class="hand"><span uib-tooltip="{{ backup.creationTime | prettyLongDate }}">{{ backup.creationTime | prettyDate }}</span></td>
|
|
<td ng-click="backupDetails.show(backup)" class="hand">
|
|
<span ng-show="!backup.contents.length">No apps</span>
|
|
<span ng-show="backup.contents.length">{{ backup.contents.length }} apps</span>
|
|
</td>
|
|
<td class="text-right no-wrap" style="vertical-align: bottom">
|
|
<button class="btn btn-xs btn-default" ng-click="downloadConfig(backup)" uib-tooltip="Download Backup Configuration"><i class="fas fa-file-alt"></i></button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<br/>
|
|
|
|
<div class="row" ng-show="createBackup.busy">
|
|
<div class="col-md-12" style="margin-bottom: 10px;">
|
|
<div class="progress progress-striped active animateMe">
|
|
<div class="progress-bar progress-bar-success" role="progressbar" style="width: {{ createBackup.percent }}%"></div>
|
|
</div>
|
|
<p>{{ createBackup.message }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" ng-show="!createBackup.busy && !createBackup.active && createBackup.errorMessage">
|
|
<div class="col-md-12">
|
|
<p class="has-error">{{ createBackup.errorMessage }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12 text-right">
|
|
<button class="btn btn-default" ng-click="createBackup.startCleanup()" ng-show="!createBackup.busy" style="margin-right: 5px">Cleanup Backups</button>
|
|
<button class="btn btn-outline btn-primary" ng-click="createBackup.startBackup()" ng-show="!createBackup.busy"">Backup now</button>
|
|
<button class="btn btn-outline btn-danger" ng-click="createBackup.stopTask()" ng-show="createBackup.busy"">Stop {{ createBackup.taskType === 'backup' ? 'Backup' : 'Cleanup' }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-left">
|
|
<h3>Logs</h3>
|
|
</div>
|
|
|
|
<div class="card card-large" style="margin-bottom: 15px;">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<p>
|
|
Please be careful when uploading these logs to a public server since they may contain sensitive information.
|
|
</p>
|
|
<a class="btn btn-primary pull-right" ng-href="/logs.html?taskId={{createBackup.taskId}}" ng-disabled="!createBackup.taskId" target="_blank">Show Logs</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|