diff --git a/app/components/container/container.html b/app/components/container/container.html index 52e203069..90a8a6a10 100644 --- a/app/components/container/container.html +++ b/app/components/container/container.html @@ -7,68 +7,19 @@ -
-
- - -
- -
-
-
{{ container.Name|trimcontainername }}
-
- Name -
-
-
-
-
- Name - - -
-
-
-
-
-
- - -
- -
-
{{ container.State|getstatetext }}
-
State
-
-
-
-
- -
- -
-
-
- - - - - - - - -
-
- Stats - Logs - Console -
-
-
- Actions + + +
+ + + + + + +
@@ -76,44 +27,144 @@
-
+
- - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + +
Created{{ container.Created|getisodate }}Name + {{ container.Name|trimcontainername }} + + + + + +
IP address{{ container.NetworkSettings.IPAddress }}
Path{{ container.Path }}
Args{{ container.Args.join(' ') || 'None' }}
Exposed PortsStatus -
    -
  • {{ k }}
  • -
+ + {{ container.State|getstatetext }} since {{ activityTime }} with exit code {{ container.State.ExitCode }} +
Start time{{ container.State.StartedAt|getisodate }}
Finished{{ container.State.FinishedAt|getisodate }}
+
+ Stats + Logs + Console +
+
+
+
+
+
+ +
+
+ + + +
+ +
+
+ + 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. + +
+
+ + +
+ +
+ +
+ +
+ +
+
+ + +
+
+ Note: if you don't specify the tag in the image name, latest will be used. +
+
+ +
+
+ + +
+
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Image{{ container.Image }}
Port configuration +
+ {{ portMapping.container }} {{ portMapping.host }} +
Environment -
    -
  • {{ k }}
  • -
-
CMD{{ container.Config.Cmd|command }}
ENV + + + + + +
{{ var|key: '=' }}{{ var|value: '=' }}
+
Labels - +
@@ -121,77 +172,33 @@
{{ k }} {{ v }}
Publish all ports{{ container.HostConfig.PublishAllPorts }}
Ports -
    -
  • - {{ containerport }} => - {{ v.HostIp }}:{{ v.HostPort }} -
  • -
-
Hostname{{ container.Config.Hostname }}
IPAddress{{ container.NetworkSettings.IPAddress }}
Cmd{{ container.Config.Cmd }}
Entrypoint{{ container.Config.Entrypoint.join(' ') }}
Bindings -
    -
  • {{ b }}
  • -
-
Volumes{{ container.Volumes }}
SysInitpath{{ container.SysInitPath }}
Image{{ container.Image }}
-
+
+ +
+
- + + + + + + + - - - - + + +
HostContainer
{{key}}{{val|getisodate}}{{val}}
{{ vol|key: ':' }}{{ vol|value: ':' }}
-
+
diff --git a/app/components/container/containerController.js b/app/components/container/containerController.js index 49248a161..3138289d6 100644 --- a/app/components/container/containerController.js +++ b/app/components/container/containerController.js @@ -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(); }]); diff --git a/app/components/image/image.html b/app/components/image/image.html index b2474d954..b4298903b 100644 --- a/app/components/image/image.html +++ b/app/components/image/image.html @@ -148,8 +148,8 @@ - - + +
{{ var|key }}{{ var|value }}{{ var|key: '=' }}{{ var|value: '=' }}
diff --git a/app/components/image/imageController.js b/app/components/image/imageController.js index 8d2b4c598..0e8db67ab 100644 --- a/app/components/image/imageController.js +++ b/app/components/image/imageController.js @@ -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]; diff --git a/app/shared/filters.js b/app/shared/filters.js index a0afbcb41..23c1f86c3 100644 --- a/app/shared/filters.js +++ b/app/shared/filters.js @@ -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; diff --git a/app/shared/services.js b/app/shared/services.js index 7f7cd59f6..495725409 100644 --- a/app/shared/services.js +++ b/app/shared/services.js @@ -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'; diff --git a/assets/css/app.css b/assets/css/app.css index 01d4780c2..78fc44f15 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -202,3 +202,11 @@ input[type="radio"] { .interactive { cursor: pointer; } + +.action-group { + margin: 10px; +} + +.btn-ico { + margin-right: 5px; +}