Move app clone into app view
This commit is contained in:
@@ -50,6 +50,69 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal clone app -->
|
||||
<div class="modal fade" id="cloneModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">
|
||||
Clone - {{ app.fqdn }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="padding: 0 15px">
|
||||
<p>Using backup from <b>{{ clone.backup.creationTime | prettyDate }}</b> and version <b>v{{ clone.backup.version }}</b></p>
|
||||
<fieldset>
|
||||
<form role="form" ng-submit="clone.submit()" autocomplete="off">
|
||||
<div class="form-group" ng-class="{ 'has-error': clone.error.location }">
|
||||
<label class="control-label" for="cloneLocationInput">Location</label>
|
||||
<div ng-show="clone.error.location"><small>{{ clone.error.location }}</small></div>
|
||||
<div class="input-group form-inline">
|
||||
<input type="text" class="form-control" ng-model="clone.location" id="cloneLocationInput" name="location" placeholder="Leave empty to use bare domain" autofocus>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span>{{ (!clone.location ? '' : (clone.domain.config.hyphenatedSubdomains ? '-' : '.')) + clone.domain.domain }}</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li ng-repeat="domain in domains">
|
||||
<a href="" ng-click="clone.domain = domain">{{ domain.domain }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center" ng-show="appClone.location && appClone.domain.provider === 'manual'">
|
||||
<b>Add an A record manually for {{ appClone.location }} to this Cloudron's public IP</b>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<div class="has-error text-center" ng-show="appClone.error.port">{{ appClone.error.port }}</div>
|
||||
<div ng-repeat="(env, info) in appClone.portBindingsInfo">
|
||||
<ng-form name="portInfo_form">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!appClone.itemName{{$index}}.$dirty && appClone.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
|
||||
<label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="appClone.portBindingsEnabled[env]">
|
||||
{{ info.title }}
|
||||
<sup>
|
||||
<a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{info.description}} ({{ HOST_PORT_MIN }} - {{ HOST_PORT_MAX }})"><i class="fa fa-question-circle"></i></a>
|
||||
</sup>
|
||||
</label>
|
||||
<input type="number" class="form-control" ng-model="appClone.portBindings[env]" ng-disabled="!appClone.portBindingsEnabled[env]" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-success" ng-click="appClone.submit()"><i class="far fa-clone"></i> Clone</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="content">
|
||||
|
||||
|
||||
@@ -515,6 +515,76 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clone = {
|
||||
busy: true,
|
||||
error: {},
|
||||
|
||||
backup: null,
|
||||
location: '',
|
||||
domain: null,
|
||||
portBindings: {},
|
||||
portBindingsInfo: {},
|
||||
portBindingsEnabled: {},
|
||||
|
||||
show: function (backup) {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.clone.backup = backup;
|
||||
$scope.clone.domain = $scope.domains.find(function (d) { return app.domain === d.domain; }); // pre-select the app's domain
|
||||
$scope.clone.portBindingsInfo = angular.extend({}, app.manifest.tcpPorts, app.manifest.udpPorts); // Portbinding map only for information
|
||||
// set default ports
|
||||
for (var env in $scope.clone.portBindingsInfo) {
|
||||
$scope.clone.portBindings[env] = $scope.clone.portBindingsInfo[env].defaultValue || 0;
|
||||
$scope.clone.portBindingsEnabled[env] = true;
|
||||
}
|
||||
|
||||
$('#cloneModal').modal('show');
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.clone.busy = true;
|
||||
|
||||
// only use enabled ports from portBindings
|
||||
var finalPortBindings = {};
|
||||
for (var env in $scope.clone.portBindings) {
|
||||
if ($scope.clone.portBindingsEnabled[env]) {
|
||||
finalPortBindings[env] = $scope.clone.portBindings[env];
|
||||
}
|
||||
}
|
||||
|
||||
var data = {
|
||||
location: $scope.clone.location,
|
||||
domain: $scope.clone.domain.domain,
|
||||
portBindings: finalPortBindings,
|
||||
backupId: $scope.clone.backup.id
|
||||
};
|
||||
|
||||
Client.cloneApp($scope.app.id, data, function (error, clonedApp) {
|
||||
$scope.clone.busy = false;
|
||||
|
||||
if (error) {
|
||||
if (error.statusCode === 409) {
|
||||
if (error.portName) {
|
||||
$scope.clone.error.port = error.message;
|
||||
} else if (error.domain) {
|
||||
$scope.clone.error.location = 'This location is already taken.';
|
||||
$('#cloneLocationInput').focus();
|
||||
} else {
|
||||
Client.error(error);
|
||||
}
|
||||
} else {
|
||||
Client.error(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$('#cloneModal').modal('hide');
|
||||
|
||||
$location.path('/apps');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function fetchUsers(callback) {
|
||||
Client.getUsers(function (error, users) {
|
||||
if (error) return callback(error);
|
||||
|
||||
@@ -1,67 +1,3 @@
|
||||
|
||||
<!-- Modal clone app -->
|
||||
<div class="modal fade" id="appCloneModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">
|
||||
Clone - {{ appClone.app.fqdn }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="padding: 0 15px">
|
||||
<p>Using backup from <b>{{ appClone.backup.creationTime | prettyDate }}</b> and version <b>v{{ appClone.backup.version }}</b></p>
|
||||
<fieldset>
|
||||
<form role="form" ng-submit="appClone.submit()" autocomplete="off">
|
||||
<div class="form-group" ng-class="{ 'has-error': appClone.error.location }">
|
||||
<label class="control-label" for="appCloneLocationInput">Location</label>
|
||||
<div ng-show="appClone.error.location"><small>{{ appClone.error.location }}</small></div>
|
||||
<div class="input-group form-inline">
|
||||
<input type="text" class="form-control" ng-model="appClone.location" id="appCloneLocationInput" name="location" placeholder="Leave empty to use bare domain" autofocus>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span>{{ (!appClone.location ? '' : (appClone.domain.config.hyphenatedSubdomains ? '-' : '.')) + appClone.domain.domain }}</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li ng-repeat="domain in domains">
|
||||
<a href="" ng-click="appClone.domain = domain">{{ domain.domain }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center" ng-show="appClone.location && appClone.domain.provider === 'manual'">
|
||||
<b>Add an A record manually for {{ appClone.location }} to this Cloudron's public IP</b>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
<div class="has-error text-center" ng-show="appClone.error.port">{{ appClone.error.port }}</div>
|
||||
<div ng-repeat="(env, info) in appClone.portBindingsInfo">
|
||||
<ng-form name="portInfo_form">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!appClone.itemName{{$index}}.$dirty && appClone.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
|
||||
<label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="appClone.portBindingsEnabled[env]">
|
||||
{{ info.title }}
|
||||
<sup>
|
||||
<a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{info.description}} ({{ HOST_PORT_MIN }} - {{ HOST_PORT_MAX }})"><i class="fa fa-question-circle"></i></a>
|
||||
</sup>
|
||||
</label>
|
||||
<input type="number" class="form-control" ng-model="appClone.portBindings[env]" ng-disabled="!appClone.portBindingsEnabled[env]" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-success" ng-click="appClone.submit()"><i class="far fa-clone"></i> Clone</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal postinstall confirm -->
|
||||
<div class="modal fade" id="appPostInstallConfirmModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
@@ -21,80 +21,6 @@ angular.module('Application').controller('AppsController', ['$scope', '$location
|
||||
$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) {
|
||||
$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.appPostInstallConfirm = {
|
||||
app: {},
|
||||
message: '',
|
||||
|
||||
Reference in New Issue
Block a user