feat(container): container view overhaul (#150)
parent
4d99c12215
commit
faccf2a651
|
@ -7,68 +7,19 @@
|
|||
</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<div class="widget-icon grey pull-left">
|
||||
<i class="fa fa-tasks"></i>
|
||||
</div>
|
||||
<div ng-if="!container.edit">
|
||||
<div class="title">{{ container.Name|trimcontainername }}</div>
|
||||
<div class="comment">
|
||||
Name <a href="" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="container.edit">
|
||||
<div class="title"><input type="text" class="containerNameInput" ng-model="container.newContainerName"></div>
|
||||
<div class="comment">
|
||||
Name
|
||||
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
|
||||
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<div ng-class="{true: 'widget-icon green pull-left', false: 'widget-icon red pull-left'}[container.State.Running]">
|
||||
<i class="fa fa-heartbeat"></i>
|
||||
</div>
|
||||
<div class="title">{{ container.State|getstatetext }}</div>
|
||||
<div class="comment">State</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<div class="widget-icon grey pull-left">
|
||||
<i class="fa fa-cogs"></i>
|
||||
</div>
|
||||
<div class="title">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button class="btn btn-primary" ng-click="commit()">Commit</button>
|
||||
<button class="btn btn-primary" ng-click="start()" ng-disabled="container.State.Running">Start</button>
|
||||
<button class="btn btn-primary" ng-click="stop()" ng-disabled="!container.State.Running">Stop</button>
|
||||
<button class="btn btn-primary" ng-click="kill()" ng-disabled="!container.State.Running">Kill</button>
|
||||
<button class="btn btn-primary" ng-click="restart()">Restart</button>
|
||||
<button class="btn btn-primary" ng-click="pause()" ng-disabled="!container.State.Running && !container.State.Paused">Pause</button>
|
||||
<button class="btn btn-primary" ng-click="unpause()" ng-disabled="!container.State.Paused">Unpause</button>
|
||||
<button class="btn btn-danger" ng-click="remove()" ng-disabled="container.State.Running">Remove</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a class="btn btn-default" type="button" ui-sref="stats({id: container.Id})">Stats</a>
|
||||
<a class="btn btn-default" type="button" ui-sref="logs({id: container.Id})">Logs</a>
|
||||
<a class="btn btn-default" type="button" ui-sref="console({id: container.Id})">Console</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment">
|
||||
Actions
|
||||
<rd-widget-header icon="fa-cogs" title="Actions"></rd-widget-header>
|
||||
<rd-widget-body classes="padding">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button class="btn btn-primary" ng-click="start()" ng-if="!container.State.Running"><i class="fa fa-play btn-ico" aria-hidden="true"></i>Start</button>
|
||||
<button class="btn btn-danger" ng-click="stop()" ng-if="container.State.Running"><i class="fa fa-stop btn-ico" aria-hidden="true"></i>Stop</button>
|
||||
<button class="btn btn-danger" ng-click="kill()" ng-if="container.State.Running"><i class="fa fa-bomb btn-ico" aria-hidden="true"></i>Kill</button>
|
||||
<button class="btn btn-primary" ng-click="restart()" ng-if="container.State.Running"><i class="fa fa-refresh btn-ico" aria-hidden="true"></i>Restart</button>
|
||||
<button class="btn btn-primary" ng-click="pause()" ng-if="container.State.Running && !container.State.Paused"><i class="fa fa-pause btn-ico" aria-hidden="true"></i>Pause</button>
|
||||
<button class="btn btn-primary" ng-click="unpause()" ng-if="container.State.Paused"><i class="fa fa-play btn-ico" aria-hidden="true"></i>Resume</button>
|
||||
<button class="btn btn-danger" ng-click="remove()" ng-disabled="container.State.Running"><i class="fa fa-trash btn-ico" aria-hidden="true"></i>Remove</button>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
|
@ -76,44 +27,144 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-9">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-tasks" title="Container status"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Created</td>
|
||||
<td>{{ container.Created|getisodate }}</td>
|
||||
<td>Name</td>
|
||||
<td ng-if="!container.edit">
|
||||
{{ container.Name|trimcontainername }}
|
||||
<a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
|
||||
</td>
|
||||
<td ng-if="container.edit">
|
||||
<input type="text" class="containerNameInput" ng-model="container.newContainerName">
|
||||
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
|
||||
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.NetworkSettings.IPAddress">
|
||||
<td>IP address</td>
|
||||
<td>{{ container.NetworkSettings.IPAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Path</td>
|
||||
<td>{{ container.Path }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Args</td>
|
||||
<td>{{ container.Args.join(' ') || 'None' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Exposed Ports</td>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li ng-repeat="(k, v) in container.Config.ExposedPorts">{{ k }}</li>
|
||||
</ul>
|
||||
<i ng-class="{true: 'fa fa-heartbeat text-icon green-icon', false: 'fa fa-heartbeat text-icon red-icon'}[container.State.Running]"></i>
|
||||
{{ container.State|getstatetext }} since {{ activityTime }}<span ng-if="!container.State.Running"> with exit code {{ container.State.ExitCode }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.State.Running">
|
||||
<td>Start time</td>
|
||||
<td>{{ container.State.StartedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr ng-if="!container.State.Running">
|
||||
<td>Finished</td>
|
||||
<td>{{ container.State.FinishedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="stats({id: container.Id})"><i class="fa fa-area-chart btn-ico" aria-hidden="true"></i>Stats</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="logs({id: container.Id})"><i class="fa fa-exclamation-circle btn-ico" aria-hidden="true"></i>Logs</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="console({id: container.Id})"><i class="fa fa-terminal btn-ico" aria-hidden="true"></i>Console</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<!-- tag-description -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">
|
||||
You can create an image from this container, this allows you to backup important data or save
|
||||
helpful configurations. You'll be able to spin up another container based on this image afterward.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !tag-description -->
|
||||
<!-- name-and-registry-inputs -->
|
||||
<div class="form-group">
|
||||
<label for="image_name" class="col-sm-1 control-label text-left">Name</label>
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" ng-model="config.Image" id="image_name" placeholder="e.g. myImage:myTag">
|
||||
</div>
|
||||
<label for="image_registry" class="col-sm-1 control-label text-left">Registry</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" class="form-control" ng-model="config.Registry" id="image_registry" placeholder="optional">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !name-and-registry-inputs -->
|
||||
<!-- tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-default btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button>
|
||||
<i id="createImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-tasks" title="Container details"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
|
||||
</tr>
|
||||
<tr ng-if="portBindings.length > 0">
|
||||
<td>Port configuration</td>
|
||||
<td>
|
||||
<div ng-repeat="portMapping in portBindings">
|
||||
{{ portMapping.container }} <i class="fa fa-long-arrow-right"></i> {{ portMapping.host }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Environment</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li ng-repeat="k in container.Config.Env">{{ k }}</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>CMD</td>
|
||||
<td><code>{{ container.Config.Cmd|command }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENV</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="var in container.Config.Env">
|
||||
<td>{{ var|key: '=' }}</td>
|
||||
<td>{{ var|value: '=' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="!(container.Config.Labels | emptyobject)">
|
||||
<td>Labels</td>
|
||||
<td>
|
||||
<table role="table" class="table">
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="(k, v) in container.Config.Labels">
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ v }}</td>
|
||||
|
@ -121,77 +172,33 @@
|
|||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Publish all ports</td>
|
||||
<td>{{ container.HostConfig.PublishAllPorts }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ports</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li ng-repeat="(containerport, hostports) in container.NetworkSettings.Ports">
|
||||
{{ containerport }} =>
|
||||
<span class="label label-default" style="margin-right: 5px;" ng-repeat="(k,v) in hostports">{{ v.HostIp }}:{{ v.HostPort }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hostname</td>
|
||||
<td>{{ container.Config.Hostname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IPAddress</td>
|
||||
<td>{{ container.NetworkSettings.IPAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cmd</td>
|
||||
<td>{{ container.Config.Cmd }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Entrypoint</td>
|
||||
<td>{{ container.Config.Entrypoint.join(' ') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bindings</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li ng-repeat="b in container.HostConfig.Binds">{{ b }}</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Volumes</td>
|
||||
<td>{{ container.Volumes }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>SysInitpath</td>
|
||||
<td>{{ container.SysInitPath }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="container.HostConfig.Binds.length > 0">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-tasks" title="Container state details"></rd-widget-header>
|
||||
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<th>Container</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(key, val) in container.State">
|
||||
<td>{{key}}</td>
|
||||
<td ng-if="key === 'StartedAt' || key === 'FinishedAt'">{{val|getisodate}}</td>
|
||||
<td ng-if="key !== 'StartedAt' && key !== 'FinishedAt'">{{val}}</td>
|
||||
<tr ng-repeat="vol in container.HostConfig.Binds">
|
||||
<td>{{ vol|key: ':' }}</td>
|
||||
<td>{{ vol|value: ':' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
angular.module('container', [])
|
||||
.controller('ContainerController', ['$scope', '$stateParams', '$state', '$filter', 'Container', 'ContainerCommit', 'Image', 'Messages', '$timeout',
|
||||
function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Image, Messages, $timeout) {
|
||||
$scope.changes = [];
|
||||
$scope.editEnv = false;
|
||||
$scope.editPorts = false;
|
||||
$scope.editBinds = false;
|
||||
$scope.newCfg = {
|
||||
Env: [],
|
||||
Ports: {}
|
||||
.controller('ContainerController', ['$scope', '$state','$stateParams', '$filter', 'Container', 'ContainerCommit', 'Messages', 'errorMsgFilter',
|
||||
function ($scope, $state, $stateParams, $filter, Container, ContainerCommit, Messages, errorMsgFilter) {
|
||||
$scope.activityTime = 0;
|
||||
$scope.portBindings = [];
|
||||
$scope.config = {
|
||||
Image: '',
|
||||
Registry: ''
|
||||
};
|
||||
|
||||
var update = function () {
|
||||
|
@ -17,50 +15,23 @@ function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Ima
|
|||
$scope.container.edit = false;
|
||||
$scope.container.newContainerName = $filter('trimcontainername')(d.Name);
|
||||
|
||||
// fill up env
|
||||
if (d.Config.Env) {
|
||||
$scope.newCfg.Env = d.Config.Env.map(function (entry) {
|
||||
return {name: entry.split('=')[0], value: entry.split('=')[1]};
|
||||
});
|
||||
if (d.State.Running) {
|
||||
$scope.activityTime = moment.duration(moment(d.State.StartedAt).utc().diff(moment().utc())).humanize();
|
||||
} else {
|
||||
$scope.activityTime = moment.duration(moment().utc().diff(moment(d.State.FinishedAt).utc())).humanize();
|
||||
}
|
||||
|
||||
// fill up ports
|
||||
$scope.newCfg.Ports = {};
|
||||
angular.forEach(d.Config.ExposedPorts, function(i, port) {
|
||||
if (d.HostConfig.PortBindings && port in d.HostConfig.PortBindings) {
|
||||
$scope.newCfg.Ports[port] = d.HostConfig.PortBindings[port];
|
||||
}
|
||||
else {
|
||||
$scope.newCfg.Ports[port] = [];
|
||||
}
|
||||
});
|
||||
|
||||
// fill up bindings
|
||||
$scope.newCfg.Binds = [];
|
||||
var defaultBinds = {};
|
||||
angular.forEach(d.Config.Volumes, function(value, vol) {
|
||||
defaultBinds[vol] = { ContPath: vol, HostPath: '', ReadOnly: false, DefaultBind: true };
|
||||
});
|
||||
angular.forEach(d.HostConfig.Binds, function(binding, i) {
|
||||
var mountpoint = binding.split(':')[0];
|
||||
var vol = binding.split(':')[1] || '';
|
||||
var ro = binding.split(':').length > 2 && binding.split(':')[2] === 'ro';
|
||||
var defaultBind = false;
|
||||
if (vol === '') {
|
||||
vol = mountpoint;
|
||||
mountpoint = '';
|
||||
}
|
||||
|
||||
if (vol in defaultBinds) {
|
||||
delete defaultBinds[vol];
|
||||
defaultBind = true;
|
||||
}
|
||||
$scope.newCfg.Binds.push({ ContPath: vol, HostPath: mountpoint, ReadOnly: ro, DefaultBind: defaultBind });
|
||||
});
|
||||
angular.forEach(defaultBinds, function(bind) {
|
||||
$scope.newCfg.Binds.push(bind);
|
||||
});
|
||||
|
||||
$scope.portBindings = [];
|
||||
if (d.NetworkSettings.Ports) {
|
||||
angular.forEach(Object.keys(d.NetworkSettings.Ports), function(portMapping) {
|
||||
if (d.NetworkSettings.Ports[portMapping]) {
|
||||
var mapping = {};
|
||||
mapping.container = portMapping;
|
||||
mapping.host = d.NetworkSettings.Ports[portMapping][0].HostIp + ':' + d.NetworkSettings.Ports[portMapping][0].HostPort;
|
||||
$scope.portBindings.push(mapping);
|
||||
}
|
||||
});
|
||||
}
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function (e) {
|
||||
if (e.status === 404) {
|
||||
|
@ -71,7 +42,6 @@ function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Ima
|
|||
}
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.start = function () {
|
||||
|
@ -110,16 +80,37 @@ function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Ima
|
|||
});
|
||||
};
|
||||
|
||||
//TODO: centralize createImageConfig (also used in imageController)
|
||||
function createImageConfig(imageName, registry) {
|
||||
var imageNameAndTag = imageName.split(':');
|
||||
var image = imageNameAndTag[0];
|
||||
if (registry) {
|
||||
image = registry + '/' + imageNameAndTag[0];
|
||||
}
|
||||
var imageConfig = {
|
||||
repo: image,
|
||||
tag: imageNameAndTag[1] ? imageNameAndTag[1] : 'latest'
|
||||
};
|
||||
return imageConfig;
|
||||
}
|
||||
|
||||
$scope.commit = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
ContainerCommit.commit({id: $stateParams.id, repo: $scope.container.Config.Image}, function (d) {
|
||||
$('#createImageSpinner').show();
|
||||
var image = _.toLower($scope.config.Image);
|
||||
var registry = _.toLower($scope.config.Registry);
|
||||
var imageConfig = createImageConfig(image, registry);
|
||||
ContainerCommit.commit({id: $stateParams.id, tag: imageConfig.tag, repo: imageConfig.repo}, function (d) {
|
||||
console.log(JSON.stringify(d, null, 4));
|
||||
update();
|
||||
$('#createImageSpinner').hide();
|
||||
Messages.send("Container commited", $stateParams.id);
|
||||
}, function (e) {
|
||||
update();
|
||||
$('#createImageSpinner').hide();
|
||||
Messages.error("Failure", "Container failed to commit." + e.data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.pause = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.pause({id: $stateParams.id}, function (d) {
|
||||
|
@ -145,7 +136,6 @@ function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Ima
|
|||
$scope.remove = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.remove({id: $stateParams.id}, function (d) {
|
||||
update();
|
||||
$state.go('containers', {}, {reload: true});
|
||||
Messages.send("Container removed", $stateParams.id);
|
||||
}, function (e) {
|
||||
|
@ -165,44 +155,19 @@ function ($scope, $stateParams, $state, $filter, Container, ContainerCommit, Ima
|
|||
});
|
||||
};
|
||||
|
||||
$scope.hasContent = function (data) {
|
||||
return data !== null && data !== undefined;
|
||||
};
|
||||
|
||||
$scope.getChanges = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.changes({id: $stateParams.id}, function (d) {
|
||||
$scope.changes = d;
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.renameContainer = function () {
|
||||
// #FIXME fix me later to handle http status to show the correct error message
|
||||
Container.rename({id: $stateParams.id, 'name': $scope.container.newContainerName}, function (data) {
|
||||
if (data.name) {
|
||||
$scope.container.Name = data.name;
|
||||
Messages.send("Container renamed", $stateParams.id);
|
||||
Container.rename({id: $stateParams.id, 'name': $scope.container.newContainerName}, function (d) {
|
||||
if (d.name) {
|
||||
$scope.container.Name = d.name;
|
||||
Messages.send("Container successfully renamed", d.name);
|
||||
} else {
|
||||
var error = errorMsgFilter(d);
|
||||
$scope.container.newContainerName = $scope.container.Name;
|
||||
Messages.error("Failure", "Container failed to rename.");
|
||||
Messages.error("Unable to rename container", error);
|
||||
}
|
||||
});
|
||||
$scope.container.edit = false;
|
||||
};
|
||||
|
||||
$scope.addEntry = function (array, entry) {
|
||||
array.push(entry);
|
||||
};
|
||||
$scope.rmEntry = function (array, entry) {
|
||||
var idx = array.indexOf(entry);
|
||||
array.splice(idx, 1);
|
||||
};
|
||||
|
||||
$scope.toggleEdit = function() {
|
||||
$scope.edit = !$scope.edit;
|
||||
};
|
||||
|
||||
update();
|
||||
$scope.getChanges();
|
||||
}]);
|
||||
|
|
|
@ -148,8 +148,8 @@
|
|||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="var in image.ContainerConfig.Env">
|
||||
<td>{{ var|key }}</td>
|
||||
<td>{{ var|value }}</td>
|
||||
<td>{{ var|key: '=' }}</td>
|
||||
<td>{{ var|value: '=' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
|
|
|
@ -2,7 +2,6 @@ angular.module('image', [])
|
|||
.controller('ImageController', ['$scope', '$stateParams', '$state', 'Image', 'Messages',
|
||||
function ($scope, $stateParams, $state, Image, Messages) {
|
||||
$scope.RepoTags = [];
|
||||
|
||||
$scope.config = {
|
||||
Image: '',
|
||||
Registry: ''
|
||||
|
@ -20,6 +19,7 @@ function ($scope, $stateParams, $state, Image, Messages) {
|
|||
});
|
||||
}
|
||||
|
||||
//TODO: centralize createImageConfig (also used in containerController)
|
||||
function createImageConfig(imageName, registry) {
|
||||
var imageNameAndTag = imageName.split(':');
|
||||
var image = imageNameAndTag[0];
|
||||
|
|
|
@ -176,16 +176,23 @@ angular.module('uifordocker.filters', [])
|
|||
})
|
||||
.filter('key', function () {
|
||||
'use strict';
|
||||
return function (pair) {
|
||||
return pair.slice(0, pair.indexOf('='));
|
||||
return function (pair, separator) {
|
||||
return pair.slice(0, pair.indexOf(separator));
|
||||
};
|
||||
})
|
||||
.filter('value', function () {
|
||||
'use strict';
|
||||
return function (pair) {
|
||||
return pair.slice(pair.indexOf('=') + 1);
|
||||
return function (pair, separator) {
|
||||
return pair.slice(pair.indexOf(separator) + 1);
|
||||
};
|
||||
})
|
||||
.filter('emptyobject', function () {
|
||||
'use strict';
|
||||
return function (obj) {
|
||||
return _.isEmpty(obj);
|
||||
};
|
||||
})
|
||||
|
||||
.filter('errorMsg', function () {
|
||||
return function (object) {
|
||||
var idx = 0;
|
||||
|
|
|
@ -17,7 +17,7 @@ angular.module('uifordocker.services', ['ngResource', 'ngSanitize'])
|
|||
changes: {method: 'GET', params: {action: 'changes'}, isArray: true},
|
||||
create: {method: 'POST', params: {action: 'create'}},
|
||||
remove: {method: 'DELETE', params: {id: '@id', v: 0}},
|
||||
rename: {method: 'POST', params: {id: '@id', action: 'rename'}, isArray: false},
|
||||
rename: {method: 'POST', params: {id: '@id', action: 'rename', name: '@name'}},
|
||||
stats: {method: 'GET', params: {id: '@id', stream: false, action: 'stats'}, timeout: 5000},
|
||||
exec: {method: 'POST', params: {id: '@id', action: 'exec'}}
|
||||
});
|
||||
|
@ -32,22 +32,9 @@ angular.module('uifordocker.services', ['ngResource', 'ngSanitize'])
|
|||
.factory('ContainerCommit', ['$resource', '$http', 'Settings', function ContainerCommitFactory($resource, $http, Settings) {
|
||||
'use strict';
|
||||
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#create-a-new-image-from-a-container-s-changes
|
||||
return {
|
||||
commit: function (params, callback) {
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: Settings.url + '/commit',
|
||||
params: {
|
||||
'container': params.id,
|
||||
'tag': params.tag || null,
|
||||
'repo': params.repo || null
|
||||
},
|
||||
data: params.config
|
||||
}).success(callback).error(function (data, status, headers, config) {
|
||||
console.log(error, data);
|
||||
});
|
||||
}
|
||||
};
|
||||
return $resource(Settings.url + '/commit', {}, {
|
||||
commit: {method: 'POST', params: {container: '@id', repo: '@repo', tag: '@tag'}}
|
||||
});
|
||||
}])
|
||||
.factory('ContainerLogs', ['$resource', '$http', 'Settings', function ContainerLogsFactory($resource, $http, Settings) {
|
||||
'use strict';
|
||||
|
|
|
@ -202,3 +202,11 @@ input[type="radio"] {
|
|||
.interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action-group {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.btn-ico {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue