437 lines
18 KiB
JavaScript
437 lines
18 KiB
JavaScript
// Copyright 1999-2024. WebPros International GmbH. All rights reserved.
|
|
|
|
Jsw.onReady(function() {
|
|
const appState = PanelMigrator.initAppState();
|
|
|
|
// Global variable representing current status of migration. Updated periodically with AJAX request.
|
|
var statusData = MIGRATION_STATUS_DATA;
|
|
|
|
// Run specified function for each customer in results column (from raw migration list)
|
|
// callback - function that receives 2 arguments: customer login as string and status item HTML element
|
|
function foreachResultCustomer(callback) {
|
|
$$('.customerStatus').each(function(element) {
|
|
var customerLogin = element.select(".customerLogin")[0].textContent.strip();
|
|
callback(customerLogin, element);
|
|
});
|
|
}
|
|
|
|
// Run specified function for each reseller in results column (from raw migration list)
|
|
// callback - function that receives 2 arguments: reseller login as string and status item HTML element
|
|
function foreachResultReseller(callback) {
|
|
$$('.resellerStatus').each(function(element) {
|
|
var resellerLogin = element.select(".resellerLogin")[0].textContent.strip();
|
|
callback(resellerLogin, element);
|
|
});
|
|
}
|
|
|
|
// Run specified function for each subscription in results column (from raw migration list)
|
|
// callback - function that receives 2 arguments: subscription name as string and status item HTML element
|
|
function foreachResultSubscription(callback) {
|
|
$$('.subscription-finished').each(function (element) {
|
|
var subscriptionName = element.select(".subscription-name")[0].textContent.strip();
|
|
callback(subscriptionName, element)
|
|
});
|
|
}
|
|
|
|
// Run specified function for each subscription in queue column (from raw migration list)
|
|
// callback - function that receives 2 arguments: subscription name as string and queue item HTML element
|
|
function foreachQueueSubscription(callback) {
|
|
$$('.subscription-in-progress').each(function (element) {
|
|
var subscriptionName = element.select(".subscription-name")[0].textContent.strip();
|
|
callback(subscriptionName, element);
|
|
});
|
|
}
|
|
|
|
// Run specified function for overall result
|
|
// callback - function that receives 1 argument: overall item HTML element
|
|
function forResultOverall(callback) {
|
|
var overallElement = $$('.overallStatus')[0];
|
|
callback(overallElement);
|
|
}
|
|
|
|
function forResultServerSettings(callback) {
|
|
var serverElement = $('migration-status-block-results-server-settings');
|
|
callback(serverElement);
|
|
}
|
|
|
|
// Root update function: called once we get new data about migration status with AJAX request
|
|
function updateMigrationStatus()
|
|
{
|
|
updateQueue();
|
|
updatePreChecks();
|
|
updateResults();
|
|
}
|
|
|
|
// Update left column: migration queue
|
|
function updateQueue()
|
|
{
|
|
updateQueueOverallAction();
|
|
updateQueueCount();
|
|
updateQueueSubscriptions();
|
|
}
|
|
|
|
// Update right column: migration results
|
|
function updateResults()
|
|
{
|
|
updateResultsSubscription();
|
|
updateResultsServerSettings();
|
|
updateResultsReseller();
|
|
updateResultsCustomer();
|
|
updateResultsOverall();
|
|
updateSubscriptionCounts();
|
|
}
|
|
|
|
// Update overall action - action executed on all subscriptions
|
|
function updateQueueOverallAction()
|
|
{
|
|
if (statusData.overall.action) {
|
|
$('overall-status-text').textContent = getPropertyChain(statusData, ['overall', 'action'], '');
|
|
$('overall-status').show();
|
|
} else {
|
|
$('overall-status').hide();
|
|
}
|
|
}
|
|
|
|
// Update number of subscriptions in queue
|
|
function updateQueueCount()
|
|
{
|
|
$('queue-count').textContent = countItems(
|
|
getPropertyChain(statusData, ['subscriptions'], []), function(_, subscription) {
|
|
return inArray(subscription.status, [statuses.IN_PROGRESS, statuses.ON_HOLD])
|
|
}
|
|
);
|
|
}
|
|
|
|
function updatePreChecks()
|
|
{
|
|
var preCheckTasksCount = 0;
|
|
$$('.migration-status-pre-check-task').each(function(element) {
|
|
var taskId = getChildElementText(element, 'task-id');
|
|
var taskStatus = getPropertyChain(statusData, ['preCheckTasks', taskId, 'status'], null);
|
|
if (taskStatus == 'not-started' || taskStatus == 'pre-checks-completed') {
|
|
var link = element.select('a').first();
|
|
link.stopObserving('click');
|
|
link.observe('click', function() {
|
|
showPreChecksPopup(taskId, false);
|
|
});
|
|
element.show();
|
|
preCheckTasksCount++;
|
|
} else {
|
|
element.hide();
|
|
}
|
|
});
|
|
$('migration-status-block-pre-checks').toggle(preCheckTasksCount > 0);
|
|
}
|
|
|
|
// Update status of each subscription in queue
|
|
function updateQueueSubscriptions()
|
|
{
|
|
foreachQueueSubscription(function(subscriptionName, element) {
|
|
var subscriptionStatus = getPropertyChain(
|
|
statusData, ['subscriptions', subscriptionName, 'status'], statuses.NOT_STARTED
|
|
);
|
|
var action = getPropertyChain(
|
|
statusData, ['subscriptions', subscriptionName, 'action'], ''
|
|
);
|
|
var details = getPropertyChain(
|
|
statusData, ['subscriptions', subscriptionName, 'details'], ''
|
|
);
|
|
toggleChildElement(
|
|
element, 'image-status-in-progress', subscriptionStatus == statuses.IN_PROGRESS
|
|
);
|
|
toggleChildElement(
|
|
element, 'image-status-on-hold', subscriptionStatus == statuses.ON_HOLD
|
|
);
|
|
element.toggle(inArray(subscriptionStatus, [statuses.IN_PROGRESS, statuses.ON_HOLD]));
|
|
|
|
var statusTextElement = element.select(".status-text")[0];
|
|
var detailsTextElement = element.select(".details-text")[0];
|
|
var detailsTextContainer = element.select(".details-text-container")[0];
|
|
|
|
var showAction = (
|
|
action &&
|
|
// Show action text only if subscription is "In progress". There could be situation when
|
|
// progress file (which contains action) and subscription status files (which contains status)
|
|
// are not in sync. For example, we need such check to avoid display actions for
|
|
// subscriptions marked as "On hold".
|
|
subscriptionStatus == statuses.IN_PROGRESS
|
|
);
|
|
|
|
if (showAction) {
|
|
statusTextElement.textContent = action;
|
|
if (detailsTextElement && detailsTextContainer) {
|
|
detailsTextElement.textContent = details;
|
|
if (details) {
|
|
detailsTextContainer.show();
|
|
} else {
|
|
detailsTextContainer.hide();
|
|
}
|
|
}
|
|
} else {
|
|
statusTextElement.textContent = '';
|
|
if (detailsTextElement && detailsTextContainer) {
|
|
detailsTextElement.textContent = '';
|
|
detailsTextContainer.hide();
|
|
}
|
|
}
|
|
|
|
toggleChildElement(element, 'status-separator', showAction);
|
|
toggleChildElement(element, 'status-text', showAction);
|
|
|
|
updateSubscriptionNameColumn(element);
|
|
});
|
|
}
|
|
|
|
// Update migration results for subscriptions
|
|
function updateResultsSubscription()
|
|
{
|
|
var hasSubscriptionsDisplayed = false;
|
|
foreachResultSubscription(function(subscriptionName, element) {
|
|
var issues = getPropertyChain(
|
|
statusData, ['subscriptionIssues', subscriptionName], []
|
|
);
|
|
var status = getPropertyChain(
|
|
statusData, ['subscriptions', subscriptionName, 'status'], statuses.NOT_STARTED
|
|
);
|
|
|
|
var isStatusFinished = inArray(
|
|
status, [statuses.FINISHED_OK, statuses.FINISHED_WARNINGS, statuses.FINISHED_ERRORS]
|
|
);
|
|
var isStatusQueued = inArray(
|
|
status, [statuses.IN_PROGRESS, statuses.ON_HOLD]
|
|
);
|
|
// Show subscription in 2 cases:
|
|
// 1) There are issues for that subscription (even if migration is still running).
|
|
// 2) Migration of the subscription finished.
|
|
if (issues.length > 0 || isStatusFinished) {
|
|
// Show status of the last operation for subscription, if available - otherwise detect by issues
|
|
if (isStatusFinished) {
|
|
updateStatusImageByStatus(element, status);
|
|
} else {
|
|
updateStatusImageByIssues(element, issues)
|
|
}
|
|
toggleChildElement(
|
|
element, 'action-resync',
|
|
(
|
|
!isStatusQueued &&
|
|
status != statuses.NOT_STARTED &&
|
|
status != statuses.CANCELLED
|
|
)
|
|
);
|
|
element.show();
|
|
hasSubscriptionsDisplayed = true;
|
|
} else {
|
|
element.hide();
|
|
}
|
|
|
|
updateSubscriptionNameColumn(element);
|
|
});
|
|
$('migration-status-block-results-subscription').toggle(hasSubscriptionsDisplayed);
|
|
}
|
|
|
|
// Update migration results for resellers
|
|
function updateResultsReseller()
|
|
{
|
|
var hasResellerWithIssues = false;
|
|
foreachResultReseller(function(resellerLogin, element) {
|
|
var issues = getPropertyChain(statusData, ['resellerIssues', resellerLogin], []);
|
|
element.toggle(issues.length > 0);
|
|
hasResellerWithIssues = hasResellerWithIssues || issues.length > 0;
|
|
});
|
|
$('migration-status-block-results-reseller').toggle(hasResellerWithIssues);
|
|
}
|
|
|
|
// Update migration results for customer
|
|
function updateResultsCustomer()
|
|
{
|
|
var hasCustomerWithIssues = false;
|
|
foreachResultCustomer(function(customerLogin, element) {
|
|
var issues = getPropertyChain(statusData, ['customerIssues', customerLogin], []);
|
|
element.toggle(issues.length > 0);
|
|
hasCustomerWithIssues = hasCustomerWithIssues || issues.length > 0;
|
|
});
|
|
$('migration-status-block-results-customer').toggle(hasCustomerWithIssues);
|
|
}
|
|
|
|
// Update overall migration results
|
|
function updateResultsOverall()
|
|
{
|
|
forResultOverall(function(element) {
|
|
var issues = getPropertyChain(statusData, ['overallIssues'], []);
|
|
$('migration-status-block-results-overall').toggle(issues.length > 0);
|
|
});
|
|
}
|
|
|
|
// Update server configuration migration results
|
|
function updateResultsServerSettings()
|
|
{
|
|
forResultServerSettings(function(element) {
|
|
let migrationStatuses = getPropertyChain(statusData, ['serverSettingsStatuses'], null);
|
|
let configurationResult = $('migration-status-block-results-server-configuration');
|
|
let extensionResult = $('migration-status-block-results-extensions');
|
|
let configurationStatus = migrationStatuses.configuration;
|
|
let extensionStatus = migrationStatuses.extensions;
|
|
|
|
configurationResult.toggle(showBlock(configurationStatus));
|
|
updateStatusImageByStatus(configurationResult, configurationStatus);
|
|
extensionResult.toggle(showBlock(extensionStatus));
|
|
updateStatusImageByStatus(extensionResult, extensionStatus);
|
|
|
|
element.toggle(showBlock(configurationStatus) || showBlock(extensionStatus));
|
|
|
|
function showBlock(status) {
|
|
return inArray(status, [statuses.FINISHED_ERRORS, statuses.FINISHED_OK, statuses.FINISHED_WARNINGS])
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update counts of successful/failed subscriptions
|
|
function updateSubscriptionCounts()
|
|
{
|
|
// update right column: list of finished subscriptions
|
|
const statusCounts = [
|
|
{ status: statuses.FINISHED_OK, elementId: 'success-count' },
|
|
{ status: statuses.FINISHED_ERRORS, elementId: 'failed-count' },
|
|
{ status: statuses.FINISHED_WARNINGS, elementId: 'warning-count' }
|
|
];
|
|
|
|
statusCounts.forEach(({ status, elementId}) => {
|
|
const count = countItems(
|
|
statusData.subscriptions, function(_, subscription) {
|
|
return subscription.status === status;
|
|
}
|
|
);
|
|
const element = $(elementId);
|
|
element.textContent = count
|
|
element.parentNode.toggle(count > 0);
|
|
});
|
|
}
|
|
|
|
// Update migration status periodically with AJAX
|
|
function periodicUpdateMigrationStatus() {
|
|
if (!appState.mounted) return;
|
|
|
|
new Ajax.Request(URL_GET_MIGRATION_STATUS, {
|
|
onSuccess: function (response) {
|
|
if (!appState.mounted) return;
|
|
|
|
statusData = response.responseText.evalJSON();
|
|
updateMigrationStatus();
|
|
},
|
|
onComplete: function() {
|
|
setTimeout(function() {periodicUpdateMigrationStatus()}, 2000);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Utility function to show proper icon according to migration status
|
|
function updateStatusImageByStatus(element, status)
|
|
{
|
|
toggleChildElement(element, 'image-status-success', status == statuses.FINISHED_OK);
|
|
toggleChildElement(element, 'image-status-warning', status == statuses.FINISHED_WARNINGS);
|
|
toggleChildElement(element, 'image-status-failure', status == statuses.FINISHED_ERRORS);
|
|
}
|
|
|
|
// Utility function to show proper icon according to issues list
|
|
function updateStatusImageByIssues(element, issues) {
|
|
var hasErrors = containsElement(issues, function(issue) { return issue.severity == issueSeverity.ERROR; });
|
|
var hasWarnings = containsElement(issues, function(issue) { return issue.severity == issueSeverity.WARNING; });
|
|
toggleChildElement(element, 'image-status-success', !hasErrors && !hasWarnings);
|
|
toggleChildElement(element, 'image-status-warning', !hasErrors && hasWarnings);
|
|
toggleChildElement(element, 'image-status-failure', hasErrors);
|
|
}
|
|
|
|
function assignControlHandlers() {
|
|
foreachResultSubscription(function(subscriptionName, element) {
|
|
observeClickOnChildElement(element, 'action-resync', function() {
|
|
showResyncPopup([subscriptionName], null, SHOW_SERVER_CONFIGURATION_BLOCK, SHOW_EXTENSIONS_SETTINGS_BLOCK);
|
|
});
|
|
});
|
|
|
|
foreachResultSubscription(function(subscriptionName, element) {
|
|
observeClickOnChildElement(element, 'action-details', function() {
|
|
var issues = getPropertyChain(
|
|
statusData, ['subscriptionIssues', subscriptionName], []
|
|
);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleSubscription', {'subscription': subscriptionName}),
|
|
issues
|
|
);
|
|
});
|
|
});
|
|
|
|
foreachResultReseller(function(resellerLogin, element) {
|
|
observeClickOnChildElement(element, 'action-details', function() {
|
|
var issues = getPropertyChain(statusData, ['resellerIssues', resellerLogin], []);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleReseller', {'reseller': resellerLogin}),
|
|
issues
|
|
);
|
|
});
|
|
});
|
|
|
|
foreachResultCustomer(function(customerLogin, element) {
|
|
observeClickOnChildElement(element, 'action-details', function() {
|
|
var issues = getPropertyChain(statusData, ['customerIssues', customerLogin], []);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleCustomer', {'customer': customerLogin}),
|
|
issues
|
|
);
|
|
});
|
|
});
|
|
|
|
forResultOverall(function(element) {
|
|
observeClickOnChildElement(element, 'action-details', function() {
|
|
var issues = getPropertyChain(statusData, ['overallIssues'], []);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleOverall'),
|
|
issues
|
|
);
|
|
});
|
|
});
|
|
|
|
forResultServerSettings(function(element) {
|
|
let configurationResult = element.select('#migration-status-block-results-server-configuration').first();
|
|
let extensionResult = element.select('#migration-status-block-results-extensions').first();
|
|
observeClickOnChildElement(configurationResult, 'action-details', function() {
|
|
let issues = getPropertyChain(statusData, ['serverSettingIssues'], []);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleServerConfiguration'),
|
|
issues.Configuration || []
|
|
);
|
|
});
|
|
observeClickOnChildElement(extensionResult, 'action-details', function() {
|
|
let issues = getPropertyChain(statusData, ['serverSettingIssues'], []);
|
|
showIssuesPopupDialog(
|
|
migratorLocale.lmsg('issuesPopupTitleExtensions'),
|
|
issues.Extensions || []
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Update subscription name column - show link to subscription overview page if subscription
|
|
// exists in Plesk
|
|
function updateSubscriptionNameColumn(element)
|
|
{
|
|
var subscriptionNameNormalized = getChildElementText(element, 'subscription-name-normalized').strip();
|
|
var pleskSubscriptionUrl = getPropertyChain(
|
|
statusData, ['pleskSubscriptionUrls', subscriptionNameNormalized], null
|
|
);
|
|
var linkExists = pleskSubscriptionUrl !== null;
|
|
toggleChildElement(element, 'subscription-name-plain', !linkExists);
|
|
toggleChildElement(element, 'subscription-name-link', linkExists);
|
|
if (pleskSubscriptionUrl) {
|
|
var link = element.select('.subscription-name-link').first().select('a').first();
|
|
link.writeAttribute('href', pleskSubscriptionUrl);
|
|
}
|
|
}
|
|
|
|
// Perform initial update from data passed in HTML
|
|
updateMigrationStatus();
|
|
// Schedule run periodic updates with AJAX
|
|
periodicUpdateMigrationStatus();
|
|
// Assign handlers to various action buttons
|
|
assignControlHandlers();
|
|
});
|