#304 feat(service-details): add the ability to update a service env vars and image
parent
1bfd6bbe95
commit
8e9dd8c2df
|
@ -43,20 +43,29 @@
|
||||||
<tr ng-if="service.Mode === 'replicated'">
|
<tr ng-if="service.Mode === 'replicated'">
|
||||||
<td>Replicas</td>
|
<td>Replicas</td>
|
||||||
<td>
|
<td>
|
||||||
<span ng-if="service.Mode === 'replicated' && !service.Scale">
|
<span ng-if="service.Mode === 'replicated' && !service.EditReplicas">
|
||||||
{{ service.Replicas }}
|
{{ service.Replicas }}
|
||||||
<a class="interactive" ng-click="service.Scale = true; service.ReplicaCount = service.Replicas;"><i class="fa fa-arrows-v" aria-hidden="true"></i> Scale</a>
|
<a class="interactive" ng-click="service.EditReplicas = true;"><i class="fa fa-arrows-v" aria-hidden="true"></i> Scale</a>
|
||||||
</span>
|
</span>
|
||||||
<span ng-if="service.Mode === 'replicated' && service.Scale">
|
<span ng-if="service.Mode === 'replicated' && service.EditReplicas">
|
||||||
<input class="input-sm" type="number" ng-model="service.Replicas" />
|
<input class="input-sm" type="number" ng-model="service.newServiceReplicas" />
|
||||||
<a class="interactive" ng-click="service.Scale = false;"><i class="fa fa-times"></i></a>
|
<a class="interactive" ng-click="service.EditReplicas = false;"><i class="fa fa-times"></i></a>
|
||||||
<a class="interactive" ng-click="scaleService(service)"><i class="fa fa-check-square-o"></i></a>
|
<a class="interactive" ng-click="scaleService(service)"><i class="fa fa-check-square-o"></i></a>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Image</td>
|
<td>Image</td>
|
||||||
<td>{{ service.Image }}</td>
|
<td ng-if="!service.EditImage">
|
||||||
|
{{ service.Image }}
|
||||||
|
<a href="" data-toggle="tooltip" title="Edit service image" ng-click="service.EditImage = true;"><i class="fa fa-edit"></i></a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td ng-if="service.EditImage">
|
||||||
|
<input type="text" class="containerNameInput" ng-model="service.newServiceImage">
|
||||||
|
<a class="interactive" ng-click="service.EditImage = false;"><i class="fa fa-times"></i></a>
|
||||||
|
<a class="interactive" ng-click="changeServiceImage(service)"><i class="fa fa-check-square-o"></i></a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="service.Ports">
|
<tr ng-if="service.Ports">
|
||||||
<td>Published ports</td>
|
<td>Published ports</td>
|
||||||
|
@ -66,15 +75,35 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="service.Env">
|
<tr ng-if="service.EnvironmentVariables">
|
||||||
<td>Env</td>
|
<td>Environment Variables</td>
|
||||||
<td>
|
<td>
|
||||||
<table class="table table-bordered table-condensed">
|
<div class="form-group">
|
||||||
<tr ng-repeat="var in service.Env">
|
<div class="col-sm-11">
|
||||||
<td>{{ var|key: '=' }}</td>
|
<span class="label label-default interactive" ng-click="addEnvironmentVariable(service)">
|
||||||
<td>{{ var|value: '=' }}</td>
|
<i class="fa fa-plus-circle" aria-hidden="true"></i> environment variable
|
||||||
</tr>
|
</span>
|
||||||
</table>
|
</div>
|
||||||
|
<!-- environment-variable-input-list -->
|
||||||
|
<div class="col-sm-11 form-inline" style="margin-top: 10px;">
|
||||||
|
<div ng-repeat="var in service.EnvironmentVariables" style="margin-top: 2px;">
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">name</span>
|
||||||
|
<input type="text" class="form-control" ng-model="var.key" ng-disabled="var.added" placeholder="e.g. FOO">
|
||||||
|
</div>
|
||||||
|
<div class="input-group col-sm-5 input-group-sm">
|
||||||
|
<span class="input-group-addon">value</span>
|
||||||
|
<input type="text" class="form-control" ng-model="var.value" ng-change="updateEnvironmentVariable(service, var)" placeholder="e.g. bar">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-default" type="button" ng-click="removeEnvironmentVariable(service, $index)">
|
||||||
|
<i class="fa fa-minus" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !environment-variable-input-list -->
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="service.Labels">
|
<tr ng-if="service.Labels">
|
||||||
|
@ -91,6 +120,12 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</rd-widget-body>
|
</rd-widget-body>
|
||||||
|
<rd-widget-footer ng-if="service.hasChanges">
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-primary" ng-click="updateService(service)">Save Changes</button>
|
||||||
|
<button type="button" class="btn btn-default" ng-click="cancelChanges(service)">Reset</button>
|
||||||
|
</div>
|
||||||
|
</rd-widget-footer>
|
||||||
</rd-widget>
|
</rd-widget>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,43 +8,68 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Task, Node, Mess
|
||||||
$scope.sortType = 'Status';
|
$scope.sortType = 'Status';
|
||||||
$scope.sortReverse = false;
|
$scope.sortReverse = false;
|
||||||
|
|
||||||
|
var previousServiceValues = {};
|
||||||
|
|
||||||
$scope.order = function (sortType) {
|
$scope.order = function (sortType) {
|
||||||
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
|
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
|
||||||
$scope.sortType = sortType;
|
$scope.sortType = sortType;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.renameService = function renameService(service) {
|
$scope.renameService = function renameService(service) {
|
||||||
|
updateServiceAttribute(service, 'Name', service.newServiceName || service.name);
|
||||||
|
service.EditName = false;
|
||||||
|
};
|
||||||
|
$scope.changeServiceImage = function changeServiceImage(service) {
|
||||||
|
updateServiceAttribute(service, 'Image', service.newServiceImage || service.image);
|
||||||
|
service.EditImage = false;
|
||||||
|
};
|
||||||
|
$scope.scaleService = function scaleService(service) {
|
||||||
|
updateServiceAttribute(service, 'Replicas', service.newServiceReplicas || service.Replicas);
|
||||||
|
service.EditReplicas = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addEnvironmentVariable = function addEnvironmentVariable(service) {
|
||||||
|
service.EnvironmentVariables.push({ key: '', value: '', originalValue: '' });
|
||||||
|
service.hasChanges = true;
|
||||||
|
};
|
||||||
|
$scope.removeEnvironmentVariable = function removeEnvironmentVariable(service, index) {
|
||||||
|
var removedElement = service.EnvironmentVariables.splice(index, 1);
|
||||||
|
service.hasChanges = service.hasChanges || removedElement !== null;
|
||||||
|
};
|
||||||
|
$scope.updateEnvironmentVariable = function updateEnvironmentVariable(service, variable) {
|
||||||
|
service.hasChanges = service.hasChanges || variable.value !== variable.originalValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancelChanges = function changeServiceImage(service) {
|
||||||
|
Object.keys(previousServiceValues).forEach(function(attribute) {
|
||||||
|
service[attribute] = previousServiceValues[attribute]; // reset service values
|
||||||
|
service['newService' + attribute] = previousServiceValues[attribute]; // reset edit fields
|
||||||
|
});
|
||||||
|
previousServiceValues = {}; // clear out all changes
|
||||||
|
// clear out environment variable changes
|
||||||
|
service.EnvironmentVariables = translateEnvironmentVariables(service.Env);
|
||||||
|
|
||||||
|
service.hasChanges = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.updateService = function updateService(service) {
|
||||||
$('#loadServicesSpinner').show();
|
$('#loadServicesSpinner').show();
|
||||||
var serviceName = service.Name;
|
|
||||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||||
config.Name = service.newServiceName;
|
config.Name = service.newServiceName;
|
||||||
|
config.TaskTemplate.ContainerSpec.Env = translateEnvironmentVariablesToEnv(service.EnvironmentVariables);
|
||||||
|
config.TaskTemplate.ContainerSpec.Image = service.newServiceImage;
|
||||||
|
config.Mode.Replicated.Replicas = service.Replicas;
|
||||||
|
|
||||||
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
||||||
$('#loadServicesSpinner').hide();
|
$('#loadServicesSpinner').hide();
|
||||||
Messages.send("Service successfully renamed", "New name: " + service.newServiceName);
|
Messages.send("Service successfully updated", "Service updated");
|
||||||
$state.go('service', {id: service.Id}, {reload: true});
|
$state.go('service', {id: service.Id}, {reload: true});
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
$('#loadServicesSpinner').hide();
|
$('#loadServicesSpinner').hide();
|
||||||
service.EditName = false;
|
Messages.error("Failure", e, "Unable to update service");
|
||||||
service.Name = serviceName;
|
|
||||||
Messages.error("Failure", e, "Unable to rename service");
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.scaleService = function scaleService(service) {
|
|
||||||
$('#loadServicesSpinner').show();
|
|
||||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
|
||||||
config.Mode.Replicated.Replicas = service.Replicas;
|
|
||||||
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
|
||||||
$('#loadServicesSpinner').hide();
|
|
||||||
Messages.send("Service successfully scaled", "New replica count: " + service.Replicas);
|
|
||||||
$state.go('service', {id: service.Id}, {reload: true});
|
|
||||||
}, function (e) {
|
|
||||||
$('#loadServicesSpinner').hide();
|
|
||||||
service.Scale = false;
|
|
||||||
service.Replicas = service.ReplicaCount;
|
|
||||||
Messages.error("Failure", e, "Unable to scale service");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.removeService = function removeService() {
|
$scope.removeService = function removeService() {
|
||||||
$('#loadingViewSpinner').show();
|
$('#loadingViewSpinner').show();
|
||||||
|
@ -68,6 +93,10 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Task, Node, Mess
|
||||||
Service.get({id: $stateParams.id}, function (d) {
|
Service.get({id: $stateParams.id}, function (d) {
|
||||||
var service = new ServiceViewModel(d);
|
var service = new ServiceViewModel(d);
|
||||||
service.newServiceName = service.Name;
|
service.newServiceName = service.Name;
|
||||||
|
service.newServiceImage = service.Image;
|
||||||
|
service.newServiceReplicas = service.Replicas;
|
||||||
|
service.EnvironmentVariables = translateEnvironmentVariables(service.Env);
|
||||||
|
|
||||||
$scope.service = service;
|
$scope.service = service;
|
||||||
Task.query({filters: {service: [service.Name]}}, function (tasks) {
|
Task.query({filters: {service: [service.Name]}}, function (tasks) {
|
||||||
Node.query({}, function (nodes) {
|
Node.query({}, function (nodes) {
|
||||||
|
@ -93,5 +122,40 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Task, Node, Mess
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateServiceAttribute(service, name, newValue) {
|
||||||
|
// ensure we only capture the original previous value, in case we update the attribute multiple times
|
||||||
|
if (!previousServiceValues[name]) {
|
||||||
|
previousServiceValues[name] = service[name];
|
||||||
|
}
|
||||||
|
// update the attribute
|
||||||
|
service[name] = newValue;
|
||||||
|
service.hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateEnvironmentVariables(env) {
|
||||||
|
if (env) {
|
||||||
|
var variables = [];
|
||||||
|
env.forEach(function(variable) {
|
||||||
|
var keyValue = variable.split('=');
|
||||||
|
var originalValue = (keyValue.length > 1) ? keyValue[1] : '';
|
||||||
|
variables.push({ key: keyValue[0], value: originalValue, originalValue: originalValue, added: true});
|
||||||
|
});
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function translateEnvironmentVariablesToEnv(env) {
|
||||||
|
if (env) {
|
||||||
|
var variables = [];
|
||||||
|
env.forEach(function(variable) {
|
||||||
|
if (variable.key && variable.key !== '' && variable.value && variable.value !== '') {
|
||||||
|
variables.push(variable.key + '=' + variable.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
fetchServiceDetails();
|
fetchServiceDetails();
|
||||||
}]);
|
}]);
|
||||||
|
|
Loading…
Reference in New Issue