Files
cloudron-box/src/views/apps.js
2019-09-13 11:29:19 +02:00

421 lines
13 KiB
JavaScript

'use strict';
/* global angular:false */
/* global $:false */
angular.module('Application').controller('AppsController', ['$scope', '$location', '$timeout', '$interval', 'Client', function ($scope, $location, $timeout, $interval, Client) {
var ALL_DOMAINS_DOMAIN = { _alldomains: true, domain: 'All Domains' }; // dummy record for the single select filter
$scope.HOST_PORT_MIN = 1024;
$scope.HOST_PORT_MAX = 65535;
$scope.installedApps = Client.getInstalledApps();
$scope.tags = Client.getAppTags();
$scope.selectedTags = [];
$scope.selectedDomain = ALL_DOMAINS_DOMAIN;
$scope.filterDomains = [ ALL_DOMAINS_DOMAIN ];
$scope.config = Client.getConfig();
$scope.user = Client.getUserInfo();
$scope.domains = [];
$scope.groups = [];
$scope.users = [];
$scope.backupsEnabled = true;
$scope.disableIndexingTemplate = '# Disable search engine indexing\n\nUser-agent: *\nDisallow: /';
$scope.appClone = {
busy: false,
error: {},
app: {},
backup: {},
// form
location: '',
domain: null,
portBindings: {},
portBindingsInfo: {},
portBindingsEnabled: {},
show: function (app, backup) {
// hide restore modal if open
$('#appRestoreModal').modal('hide');
$scope.appClone.busy = false;
$scope.appClone.error = {};
$scope.appClone.app = app;
$scope.appClone.backup = backup;
$scope.appClone.location = '';
$scope.appClone.domain = $scope.domains.find(function (d) { return app.domain === d.domain; }); // pre-select the app's domain
$scope.appClone.portBindingsInfo = angular.extend({}, $scope.appClone.app.manifest.tcpPorts, $scope.appClone.app.manifest.udpPorts); // Portbinding map only for information
// set default ports
for (var env in $scope.appClone.portBindingsInfo) {
$scope.appClone.portBindings[env] = $scope.appClone.portBindingsInfo[env].defaultValue || 0;
$scope.appClone.portBindingsEnabled[env] = true;
}
$('#appCloneModal').modal('show');
},
submit: function () {
$scope.appClone.busy = true;
// only use enabled ports from portBindings
var finalPortBindings = {};
for (var env in $scope.appClone.portBindings) {
if ($scope.appClone.portBindingsEnabled[env]) {
finalPortBindings[env] = $scope.appClone.portBindings[env];
}
}
var data = {
location: $scope.appClone.location,
domain: $scope.appClone.domain.domain,
portBindings: finalPortBindings,
backupId: $scope.appClone.backup.id
};
Client.cloneApp($scope.appClone.app.id, data, function (error, clonedApp) {
$scope.appClone.busy = false;
if (error) {
if (error.statusCode === 409) {
if (error.portName) {
$scope.appClone.error.port = error.message;
} else if (error.domain) {
$scope.appClone.error.location = 'This location is already taken.';
$('#appCloneLocationInput').focus();
} else {
Client.error(error);
}
} else {
Client.error(error);
}
return;
}
$('#appCloneModal').modal('hide');
Client.refreshAppCache(clonedApp.id); // reflect the new app state immediately
});
}
};
$scope.appRestore = {
busy: false,
busyFetching: false,
error: {},
app: {},
backups: [],
copyBackupIdDone: false,
creatingBackup: false,
copyBackupId: function (backup) {
var copyText = document.getElementById('appRestoreBackupIdHelper');
copyText.value = backup.id;
copyText.select();
document.execCommand('copy');
$scope.appRestore.copyBackupIdDone = true;
// reset after 2.5sec
$timeout(function () { $scope.appRestore.copyBackupIdDone = false; }, 2500);
},
createBackup: function () {
$scope.appRestore.creatingBackup = true;
Client.backupApp($scope.appRestore.app.id, function (error) {
if (error) Client.error(error);
function waitForBackupFinish() {
if ($scope.appRestore.app.installationState === 'pending_backup') return $timeout(waitForBackupFinish, 1000);
// we are done, refresh the backup list
Client.getAppBackups($scope.appRestore.app.id, function (error, backups) {
if (error) return Client.error(error);
$scope.appRestore.backups = backups;
$scope.appRestore.creatingBackup = false;
});
}
// reflect the new app state immediately
Client.refreshAppCache($scope.appRestore.app.id, waitForBackupFinish);
});
},
show: function (app) {
$scope.reset();
$scope.appRestore.app = app;
$scope.appRestore.busyFetching = true;
$scope.appRestore.creatingBackup = $scope.appRestore.app.installationState === 'pending_backup';
$('#appRestoreModal').modal('show');
Client.getAppBackups(app.id, function (error, backups) {
if (error) {
Client.error(error);
} else {
$scope.appRestore.backups = backups;
$scope.appRestore.busyFetching = false;
}
});
return false; // prevent propagation and default
},
restore: function (backup) {
$scope.appRestore.busy = true;
Client.restoreApp($scope.appRestore.app.id, backup.id, function (error) {
if (error) {
Client.error(error);
} else {
$('#appRestoreModal').modal('hide');
}
$scope.appRestore.busy = false;
Client.refreshAppCache($scope.appRestore.app.id); // reflect the new app state immediately
});
}
};
$scope.appCancel = {
app: {},
busy: false,
show: function (app) {
$scope.appCancel.app = app;
$scope.appCancel.busy = false;
$('#appCancelModal').modal('show');
},
submit: function () {
$scope.appCancel.busy = true;
Client.stopTask($scope.appCancel.app.taskId, function (error) {
if (error) Client.error(error);
setTimeout(function () { // small delay for UI
$scope.appCancel.busy = false;
Client.refreshAppCache($scope.appCancel.app.id); // reflect the new app state immediately
$('#appCancelModal').modal('hide');
}, 1000);
});
return false; // prevent propagation and default
}
};
$scope.appInfo = {
app: {},
message: ''
};
$scope.appPostInstallConfirm = {
app: {},
message: '',
confirmed: false,
show: function (app) {
$scope.reset();
$scope.appPostInstallConfirm.app = app;
$scope.appPostInstallConfirm.message = app.manifest.postInstallMessage;
$('#appPostInstallConfirmModal').modal('show');
return false; // prevent propagation and default
},
submit: function () {
if (!$scope.appPostInstallConfirm.confirmed) return;
$scope.appPostInstallConfirm.app.pendingPostInstallConfirmation = false;
delete localStorage['confirmPostInstall_' + $scope.appPostInstallConfirm.app.id];
$('#appPostInstallConfirmModal').modal('hide');
}
};
$scope.appError = {
app: null,
show: function (app) {
$scope.reset();
$scope.appError.app = app;
$('#appErrorModal').modal('show');
return false; // prevent propagation and default
}
};
$scope.appUpdate = {
busy: false,
error: {},
app: {},
manifest: {},
portBindings: {},
show: function (app, updateManifest) {
$scope.reset();
$scope.appUpdate.app = app;
$scope.appUpdate.manifest = angular.copy(updateManifest);
$('#appUpdateModal').modal('show');
},
submit: function () {
$scope.appUpdate.busy = true;
Client.updateApp($scope.appUpdate.app.id, $scope.appUpdate.manifest, function (error) {
if (error) {
Client.error(error);
} else {
$scope.appUpdate.app = {};
$('#appUpdateModal').modal('hide');
}
$scope.appUpdate.busy = false;
Client.refreshAppCache($scope.appUpdate.app.id); // reflect the new app state immediately
});
}
};
$scope.reset = function () {
// close all dialogs
$('#appErrorModal').modal('hide');
$('#appRestoreModal').modal('hide');
$('#appUpdateModal').modal('hide');
$('#appInfoModal').modal('hide');
$('#appPostInstallConfirmModal').modal('hide');
// reset update dialog
$scope.appUpdate.error = {};
$scope.appUpdate.app = {};
$scope.appUpdate.manifest = {};
// reset restore dialog
$scope.appRestore.error = {};
$scope.appRestore.app = {};
$scope.appRestore.backups = [];
$scope.appRestore.location = '';
$scope.appRestore.domain = null;
$scope.appRestore.portBindings = {};
$scope.appRestore.portBindingsInfo = {};
$scope.appRestore.portBindingsEnabled = {};
$scope.appRestore.action = 'restore';
// post install confirmation dialog
$scope.appPostInstallConfirm.app = {};
$scope.appPostInstallConfirm.message = '';
$scope.appPostInstallConfirm.confirmed = false;
};
$scope.showInformation = function (app) {
$scope.reset();
$scope.appInfo.app = app;
$scope.appInfo.message = app.manifest.postInstallMessage;
$('#appInfoModal').modal('show');
return false; // prevent propagation and default
};
$scope.renderAccessRestrictionUser = function (userId) {
var user = $scope.users.filter(function (u) { return u.id === userId; })[0];
// user not found
if (!user) return userId;
return user.username ? user.username : user.email;
};
$scope.cancel = function () {
window.history.back();
};
function fetchUsers() {
Client.getUsers(function (error, users) {
if (error) {
console.error(error);
return $timeout(fetchUsers, 5000);
}
// ensure we have something to work with in the access restriction dropdowns
users.forEach(function (user) { user.display = user.username || user.email; });
$scope.users = users;
});
}
function fetchGroups() {
Client.getGroups(function (error, groups) {
if (error) {
console.error(error);
return $timeout(fetchUsers, 5000);
}
$scope.groups = groups;
});
}
function getDomains() {
Client.getDomains(function (error, result) {
if (error) {
console.error(error);
return $timeout(getDomains, 5000);
}
$scope.domains = result;
$scope.filterDomains = [ALL_DOMAINS_DOMAIN].concat(result);
});
}
function getBackupConfig() {
Client.getBackupConfig(function (error, backupConfig) {
if (error) return console.error(error);
$scope.backupEnabled = backupConfig.provider !== 'noop';
});
}
function refreshInstalledApps() {
Client.refreshInstalledApps();
}
Client.onReady(function () {
refreshInstalledApps(); // refresh the new list immediately when switching from another view (appstore)
if ($scope.user.admin) {
fetchUsers();
fetchGroups();
getDomains();
getBackupConfig();
}
var refreshAppsTimer = $interval(refreshInstalledApps, 5000);
$scope.$on('$destroy', function () {
$interval.cancel(refreshAppsTimer);
});
});
// setup all the dialog focus handling
['appUpdateModal', 'appRestoreModal', 'appInfoModal', 'appErrorModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});
});
$('.modal-backdrop').remove();
}]);