mirror of https://github.com/portainer/portainer
				
				
				
			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
	
	 Anthony Lapenna
						Anthony Lapenna