overte-JulianGro/domain-server/resources/web/content/js/content.js
2018-02-16 16:01:40 -08:00

400 lines
17 KiB
JavaScript

$(document).ready(function(){
var RESTORE_SETTINGS_UPLOAD_ID = 'restore-settings-button';
var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file';
var UPLOAD_CONTENT_ALLOWED_DIV_ID = 'upload-content-allowed';
var UPLOAD_CONTENT_RECOVERING_DIV_ID = 'upload-content-recovering';
function progressBarHTML(extraClass, label) {
var html = "<div class='progress'>";
html += "<div class='" + extraClass + " progress-bar progress-bar-success progress-bar-striped active' role='progressbar' aria-valuemin='0' aria-valuemax='100'>";
html += label + "<span class='sr-only'></span></div></div>";
return html;
}
function setupBackupUpload() {
// construct the HTML needed for the settings backup panel
var html = "<div class='form-group'><div id='" + UPLOAD_CONTENT_ALLOWED_DIV_ID + "'>";
html += "<span class='help-block'>Upload a content archive (.zip) or entity file (.json, .json.gz) to replace the content of this domain.";
html += "<br/>Note: Your domain content will be replaced by the content you upload, but the existing backup files of your domain's content will not immediately be changed.</span>";
html += "<input id='restore-settings-file' name='restore-settings' type='file'>";
html += "<button type='button' id='" + RESTORE_SETTINGS_UPLOAD_ID + "' disabled='true' class='btn btn-primary'>Upload Content</button>";
html += "</div><div id='" + UPLOAD_CONTENT_RECOVERING_DIV_ID + "'>";
html += "<span class='help-block'>Restore in progress</span>";
html += progressBarHTML('recovery', 'Restoring');
html += "</div></div>";
$('#' + Settings.UPLOAD_CONTENT_BACKUP_PANEL_ID + ' .panel-body').html(html);
}
// handle content archive or entity file upload
// when the selected file is changed, enable the button if there's a selected file
$('body').on('change', '#' + RESTORE_SETTINGS_FILE_ID, function() {
if ($(this).val()) {
$('#' + RESTORE_SETTINGS_UPLOAD_ID).attr('disabled', false);
}
});
// when the upload button is clicked, send the file to the DS
// and reload the page if restore was successful or
// show an error if not
$('body').on('click', '#' + RESTORE_SETTINGS_UPLOAD_ID, function(e){
e.preventDefault();
swalAreYouSure(
"Your domain content will be replaced by the uploaded Content Archive or entity file",
"Restore content",
function() {
var files = $('#' + RESTORE_SETTINGS_FILE_ID).prop('files');
var fileFormData = new FormData();
fileFormData.append('restore-file', files[0]);
showSpinnerAlert("Restoring Content");
$.ajax({
url: '/content/upload',
type: 'POST',
cache: false,
processData: false,
contentType: false,
data: fileFormData
}).done(function(data, textStatus, jqXHR) {
swal.close();
showRestartModal();
}).fail(function(jqXHR, textStatus, errorThrown) {
showErrorMessage(
"Error",
"There was a problem restoring domain content.\n"
+ "Please ensure that the content archive or entity file is valid and try again."
);
});
}
);
});
var GENERATE_ARCHIVE_BUTTON_ID = 'generate-archive-button';
var CONTENT_ARCHIVES_NORMAL_ID = 'content-archives-success';
var CONTENT_ARCHIVES_ERROR_ID = 'content-archives-error';
var AUTOMATIC_ARCHIVES_TABLE_ID = 'automatic-archives-table';
var AUTOMATIC_ARCHIVES_TBODY_ID = 'automatic-archives-tbody';
var MANUAL_ARCHIVES_TABLE_ID = 'manual-archives-table';
var MANUAL_ARCHIVES_TBODY_ID = 'manual-archives-tbody';
var AUTO_ARCHIVES_SETTINGS_LINK_ID = 'auto-archives-settings-link';
var ACTION_MENU_CLASS = 'action-menu';
var automaticBackups = [];
var manualBackups = [];
function setupContentArchives() {
// construct the HTML needed for the content archives panel
var html = "<div id='" + CONTENT_ARCHIVES_NORMAL_ID + "'><div class='form-group'>";
html += "<label class='control-label'>Automatic Content Archives</label>";
html += "<span class='help-block'>Your domain server makes regular archives of the content in your domain. In the list below, you can see and download all of your domain content and settings backups. "
html += "<a href='/settings/#automatic_content_archives' id='" + AUTO_ARCHIVES_SETTINGS_LINK_ID + "'>Click here to manage automatic content archive intervals.</a></span>";
html += "</div>";
html += "<table class='table sortable' id='" + AUTOMATIC_ARCHIVES_TABLE_ID + "'>";
var backups_table_head = "<thead><tr class='gray-tr'><th>Archive Name</th><th data-defaultsort='desc'>Archive Date</th>"
+ "<th data-defaultsort='disabled'></th><th class='" + ACTION_MENU_CLASS + "' data-defaultsort='disabled'>Actions</th>"
+ "</tr></thead>";
html += backups_table_head;
html += "<tbody id='" + AUTOMATIC_ARCHIVES_TBODY_ID + "'></tbody></table>";
html += "<div class='form-group'>";
html += "<label class='control-label'>Manual Content Archives</label>";
html += "<span class='help-block'>You can generate and download an archive of your domain content right now. You can also download, delete and restore any archive listed.</span>";
html += "<button type='button' id='" + GENERATE_ARCHIVE_BUTTON_ID + "' class='btn btn-primary'>Generate New Archive</button>";
html += "</div>";
html += "<table class='table sortable' id='" + MANUAL_ARCHIVES_TABLE_ID + "'>";
html += backups_table_head;
html += "<tbody id='" + MANUAL_ARCHIVES_TBODY_ID + "'></tbody></table></div>";
html += "<div class='form-group' id='" + CONTENT_ARCHIVES_ERROR_ID + "' style='display:none;'>"
+ "<span class='help-block'>There was a problem loading your list of automatic and manual content archives. "
+ "Please reload the page to try again.</span></div>";
// put the base HTML in the content archives panel
$('#' + Settings.CONTENT_ARCHIVES_PANEL_ID + ' .panel-body').html(html);
}
var BACKUP_RESTORE_LINK_CLASS = 'restore-backup';
var BACKUP_DOWNLOAD_LINK_CLASS = 'download-backup';
var BACKUP_DELETE_LINK_CLASS = 'delete-backup';
var ACTIVE_BACKUP_ROW_CLASS = 'active-backup';
function reloadBackupInformation() {
// make a GET request to get backup information to populate the table
$.ajax({
url: '/api/backups',
cache: false
}).done(function(data) {
// split the returned data into manual and automatic manual backups
var splitBackups = _.partition(data.backups, function(value, index) {
return value.isManualBackup;
});
manualBackups = splitBackups[0];
automaticBackups = splitBackups[1];
// populate the backups tables with the backups
function createBackupTableRow(backup) {
return "<tr data-backup-id='" + backup.id + "' data-backup-name='" + backup.name + "'>"
+ "<td data-value='" + backup.name.toLowerCase() + "'>" + backup.name + "</td><td data-dateformat='lll'>"
+ moment(backup.createdAtMillis).format('lll')
+ "</td><td class='backup-status'></td><td class='" + ACTION_MENU_CLASS + "'>"
+ "<div class='dropdown'><div class='dropdown-toggle' data-toggle='dropdown' aria-expanded='false'><span class='glyphicon glyphicon-option-vertical'></span></div>"
+ "<ul class='dropdown-menu dropdown-menu-right'>"
+ "<li><a class='" + BACKUP_RESTORE_LINK_CLASS + "' href='#'>Restore from here</a></li><li class='divider'></li>"
+ "<li><a class='" + BACKUP_DOWNLOAD_LINK_CLASS + "' href='#'>Download</a></li><li class='divider'></li>"
+ "<li><a class='" + BACKUP_DELETE_LINK_CLASS + "' href='/api/backups/" + backup.id + "' target='_blank'>Delete</a></li></ul></div></td>";
}
function updateProgressBars($progressBar, value) {
$progressBar.attr('aria-valuenow', value).attr('style', 'width: ' + value + '%');
$progressBar.find('.sr-only').html(data.status.recoveryProgress + "% Complete");
}
// before we add any new rows and update existing ones
// remove our flag for active rows
$('.' + ACTIVE_BACKUP_ROW_CLASS).removeClass(ACTIVE_BACKUP_ROW_CLASS);
function updateOrAddTableRow(backup, tableBodyID) {
// check for a backup with this ID
var $backupRow = $("tr[data-backup-id='" + backup.id + "']");
if ($backupRow.length == 0) {
// create a new row and then add it to the table
$backupRow = $(createBackupTableRow(backup));
$('#' + tableBodyID).append($backupRow);
}
// update the row status column depending on if it is available or recovering
if (!backup.isAvailable) {
// add a progress bar to the status row for availability
$backupRow.find('td.backup-status').html(progressBarHTML('availability', 'Archiving'));
// set the value of the progress bar based on availability progress
updateProgressBars($backupRow.find('.progress-bar'), backup.availabilityProgress * 100);
} else if (backup.id == data.status.recoveringBackupId) {
// add a progress bar to the status row for recovery
$backupRow.find('td.backup-status').html(progressBarHTML('recovery', 'Restoring'));
} else {
// no special status for this row, use an empty status column
$backupRow.find('td.backup-status').html('');
}
$backupRow.find('td.' + ACTION_MENU_CLASS + ' .dropdown').toggle(backup.isAvailable);
$backupRow.addClass(ACTIVE_BACKUP_ROW_CLASS);
}
var automaticRows = "";
if (automaticBackups.length > 0) {
for (var backupIndex in automaticBackups) {
updateOrAddTableRow(automaticBackups[backupIndex], AUTOMATIC_ARCHIVES_TBODY_ID);
}
}
if (manualBackups.length > 0) {
for (var backupIndex in manualBackups) {
updateOrAddTableRow(manualBackups[backupIndex], MANUAL_ARCHIVES_TBODY_ID);
}
}
// at this point, any rows that no longer have the ACTIVE_BACKUP_ROW_CLASS
// are deleted backups, so we remove them from the table
$('tbody tr:not(.' + ACTIVE_BACKUP_ROW_CLASS + ')').remove();
// check if the restore action on all rows should be enabled or disabled
$('.' + BACKUP_RESTORE_LINK_CLASS).parent().toggleClass('disabled', data.status.isRecovering);
// hide or show the manual content upload file and button depending on our recovering status
$('#' + UPLOAD_CONTENT_ALLOWED_DIV_ID).toggle(!data.status.isRecovering);
$('#' + UPLOAD_CONTENT_RECOVERING_DIV_ID).toggle(data.status.isRecovering);
// update the progress bars for current restore status
if (data.status.isRecovering) {
updateProgressBars($('.recovery.progress-bar'), data.status.recoveryProgress * 100);
}
// tell bootstrap sortable to update for the new rows
$.bootstrapSortable({ applyLast: true });
$('#' + CONTENT_ARCHIVES_NORMAL_ID).toggle(true);
$('#' + CONTENT_ARCHIVES_ERROR_ID).toggle(false);
}).fail(function(){
// we've hit the very rare case where we couldn't load the list of backups from the domain server
// set our backups to empty
automaticBackups = [];
manualBackups = [];
// replace the content archives panel with a simple error message
// stating that the user should reload the page
$('#' + CONTENT_ARCHIVES_NORMAL_ID).toggle(false);
$('#' + CONTENT_ARCHIVES_ERROR_ID).toggle(true);
}).always(function(){
// toggle showing or hiding the tables depending on if they have entries
$('#' + AUTOMATIC_ARCHIVES_TABLE_ID).toggle(automaticBackups.length > 0);
$('#' + MANUAL_ARCHIVES_TABLE_ID).toggle(manualBackups.length > 0);
});
}
// handle click in table to restore a given content backup
$('body').on('click', '.' + BACKUP_RESTORE_LINK_CLASS, function(e){
// stop the default behaviour
e.preventDefault();
// grab the name of this backup so we can show it in alerts
var backupName = $(this).closest('tr').attr('data-backup-name');
// grab the ID of this backup in case we need to send a POST
var backupID = $(this).closest('tr').attr('data-backup-id');
// make sure the user knows what is about to happen
swalAreYouSure(
"Your domain content will be replaced by the content archive " + backupName,
"Restore content",
function() {
// show a spinner while we send off our request
showSpinnerAlert("Restoring Content Archive " + backupName);
// setup an AJAX POST to request content restore
$.post('/api/backups/recover/' + backupID).done(function(data, textStatus, jqXHR) {
swal.close();
showRestartModal();
}).fail(function(jqXHR, textStatus, errorThrown) {
showErrorMessage(
"Error",
"There was a problem restoring domain content.\n"
+ "If the problem persists, the content archive may be corrupted."
);
});
}
)
});
// handle click in table to delete a given content backup
$('body').on('click', '.' + BACKUP_DELETE_LINK_CLASS, function(e){
// stop the default behaviour
e.preventDefault();
// grab the name of this backup so we can show it in alerts
var backupName = $(this).closest('tr').attr('data-backup-name');
// grab the ID of this backup in case we need to send the DELETE request
var backupID = $(this).closest('tr').attr('data-backup-id');
// make sure the user knows what is about to happen
swalAreYouSure(
"The content archive " + backupName + " will be deleted and will no longer be available for restore or download from this page.",
"Delete content archive",
function() {
// show a spinner while we send off our request
showSpinnerAlert("Deleting content archive " + backupName);
// setup an AJAX DELETE to request content archive delete
$.ajax({
url: '/api/backups/' + backupID,
type: 'DELETE'
}).done(function(data, textStatus, jqXHR) {
swal.close();
}).fail(function(jqXHR, textStatus, errorThrown) {
showErrorMessage(
"Error",
"There was an unexpected error deleting the content archive"
);
}).always(function(){
// reload the list of content archives in case we deleted a backup
// or it's no longer an available backup for some other reason
reloadBackupInformation();
});
}
)
});
// handle click on automatic content archive settings link
$('body').on('click', '#' + AUTO_ARCHIVES_SETTINGS_LINK_ID, function(e) {
if (Settings.pendingChanges > 0) {
// don't follow the link right away, make sure the user knows they are about to leave
// the page and lose changes
e.preventDefault();
var settingsLink = $(this).attr('href');
swalAreYouSure(
"You have pending changes to content settings that have not been saved. They will be lost if you leave the page to manage automatic content archive intervals.",
"Proceed without Saving",
function() {
// user wants to drop their changes, switch pages
window.location = settingsLink;
}
);
}
});
// handle click on manual archive creation button
$('body').on('click', '#' + GENERATE_ARCHIVE_BUTTON_ID, function(e) {
e.preventDefault();
// show a sweet alert to ask the user to provide a name for their content archive
swal({
title: "Generate a Content Archive",
type: "input",
text: "This will capture the state of all the content in your domain right now, which you can save as a backup and restore from later.",
confirmButtonText: "Generate Archive",
showCancelButton: true,
closeOnConfirm: false,
inputPlaceholder: 'Archive Name'
}, function(inputValue){
if (inputValue === false) {
return false;
}
if (inputValue === "") {
swal.showInputError("Please give the content archive a name.")
return false;
}
// post the provided archive name to ask the server to kick off a manual backup
$.ajax({
type: 'POST',
url: '/api/backups',
data: {
'name': inputValue
}
}).done(function(data) {
// since we successfully setup a new content archive, reload the table of archives
// which should show that this archive is pending creation
reloadBackupInformation();
}).fail(function(jqXHR, textStatus, errorThrown) {
});
swal.close();
});
});
Settings.extraGroupsAtIndex = Settings.extraContentGroupsAtIndex;
Settings.afterReloadActions = function() {
setupBackupUpload();
setupContentArchives();
// load the latest backups immediately
reloadBackupInformation();
// setup a timer to reload them every 5 seconds
setInterval(reloadBackupInformation, 5000);
};
});