mirror of https://github.com/portainer/portainer
Whitespace diff, ran everything through the formatter.
parent
b7daf91723
commit
8a7f8f7c37
|
@ -38,7 +38,10 @@ angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services'
|
||||||
controller: 'ImageController'
|
controller: 'ImageController'
|
||||||
});
|
});
|
||||||
$routeProvider.when('/info', {templateUrl: 'app/components/info/info.html', controller: 'InfoController'});
|
$routeProvider.when('/info', {templateUrl: 'app/components/info/info.html', controller: 'InfoController'});
|
||||||
$routeProvider.when('/events', {templateUrl: 'app/components/events/events.html', controller: 'EventsController'});
|
$routeProvider.when('/events', {
|
||||||
|
templateUrl: 'app/components/events/events.html',
|
||||||
|
controller: 'EventsController'
|
||||||
|
});
|
||||||
$routeProvider.otherwise({redirectTo: '/'});
|
$routeProvider.otherwise({redirectTo: '/'});
|
||||||
}])
|
}])
|
||||||
// This is your docker url that the api will use to make requests
|
// This is your docker url that the api will use to make requests
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
angular.module('builder', [])
|
angular.module('builder', [])
|
||||||
.controller('BuilderController', ['$scope', 'Dockerfile', 'Messages',
|
.controller('BuilderController', ['$scope', 'Dockerfile', 'Messages',
|
||||||
function($scope, Dockerfile, Messages) {
|
function ($scope, Dockerfile, Messages) {
|
||||||
$scope.template = 'app/components/builder/builder.html';
|
$scope.template = 'app/components/builder/builder.html';
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,143 +1,143 @@
|
||||||
angular.module('container', [])
|
angular.module('container', [])
|
||||||
.controller('ContainerController', ['$scope', '$routeParams', '$location', 'Container', 'ContainerCommit', 'Messages', 'ViewSpinner',
|
.controller('ContainerController', ['$scope', '$routeParams', '$location', 'Container', 'ContainerCommit', 'Messages', 'ViewSpinner',
|
||||||
function($scope, $routeParams, $location, Container, ContainerCommit, Messages, ViewSpinner) {
|
function ($scope, $routeParams, $location, Container, ContainerCommit, Messages, ViewSpinner) {
|
||||||
$scope.changes = [];
|
$scope.changes = [];
|
||||||
$scope.edit = false;
|
$scope.edit = false;
|
||||||
|
|
||||||
var update = function() {
|
var update = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.get({id: $routeParams.id}, function(d) {
|
Container.get({id: $routeParams.id}, function (d) {
|
||||||
$scope.container = d;
|
$scope.container = d;
|
||||||
$scope.container.edit = false;
|
$scope.container.edit = false;
|
||||||
$scope.container.newContainerName = d.Name;
|
$scope.container.newContainerName = d.Name;
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
if (e.status === 404) {
|
if (e.status === 404) {
|
||||||
$('.detail').hide();
|
$('.detail').hide();
|
||||||
Messages.error("Not found", "Container not found.");
|
Messages.error("Not found", "Container not found.");
|
||||||
} else {
|
} else {
|
||||||
Messages.error("Failure", e.data);
|
Messages.error("Failure", e.data);
|
||||||
}
|
}
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.start = function(){
|
$scope.start = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.start({
|
Container.start({
|
||||||
id: $scope.container.Id,
|
id: $scope.container.Id,
|
||||||
HostConfig: $scope.container.HostConfig
|
HostConfig: $scope.container.HostConfig
|
||||||
}, function(d) {
|
}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container started", $routeParams.id);
|
Messages.send("Container started", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to start." + e.data);
|
Messages.error("Failure", "Container failed to start." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.stop = function() {
|
$scope.stop = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.stop({id: $routeParams.id}, function(d) {
|
Container.stop({id: $routeParams.id}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container stopped", $routeParams.id);
|
Messages.send("Container stopped", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to stop." + e.data);
|
Messages.error("Failure", "Container failed to stop." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.kill = function() {
|
$scope.kill = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.kill({id: $routeParams.id}, function(d) {
|
Container.kill({id: $routeParams.id}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container killed", $routeParams.id);
|
Messages.send("Container killed", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to die." + e.data);
|
Messages.error("Failure", "Container failed to die." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.commit = function() {
|
$scope.commit = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
ContainerCommit.commit({id: $routeParams.id, repo: $scope.container.Config.Image}, function(d) {
|
ContainerCommit.commit({id: $routeParams.id, repo: $scope.container.Config.Image}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container commited", $routeParams.id);
|
Messages.send("Container commited", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to commit." + e.data);
|
Messages.error("Failure", "Container failed to commit." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$scope.pause = function() {
|
$scope.pause = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.pause({id: $routeParams.id}, function(d) {
|
Container.pause({id: $routeParams.id}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container paused", $routeParams.id);
|
Messages.send("Container paused", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to pause." + e.data);
|
Messages.error("Failure", "Container failed to pause." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.unpause = function() {
|
$scope.unpause = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.unpause({id: $routeParams.id}, function(d) {
|
Container.unpause({id: $routeParams.id}, function (d) {
|
||||||
update();
|
update();
|
||||||
Messages.send("Container unpaused", $routeParams.id);
|
Messages.send("Container unpaused", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
update();
|
update();
|
||||||
Messages.error("Failure", "Container failed to unpause." + e.data);
|
Messages.error("Failure", "Container failed to unpause." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.remove = function () {
|
||||||
|
ViewSpinner.spin();
|
||||||
|
Container.remove({id: $routeParams.id}, function (d) {
|
||||||
|
update();
|
||||||
|
Messages.send("Container removed", $routeParams.id);
|
||||||
|
}, function (e) {
|
||||||
|
update();
|
||||||
|
Messages.error("Failure", "Container failed to remove." + e.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.restart = function () {
|
||||||
|
ViewSpinner.spin();
|
||||||
|
Container.restart({id: $routeParams.id}, function (d) {
|
||||||
|
update();
|
||||||
|
Messages.send("Container restarted", $routeParams.id);
|
||||||
|
}, function (e) {
|
||||||
|
update();
|
||||||
|
Messages.error("Failure", "Container failed to restart." + e.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.hasContent = function (data) {
|
||||||
|
return data !== null && data !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getChanges = function () {
|
||||||
|
ViewSpinner.spin();
|
||||||
|
Container.changes({id: $routeParams.id}, function (d) {
|
||||||
|
$scope.changes = d;
|
||||||
|
ViewSpinner.stop();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.renameContainer = function () {
|
||||||
|
// #FIXME fix me later to handle http status to show the correct error message
|
||||||
|
Container.rename({id: $routeParams.id, 'name': $scope.container.newContainerName}, function (data) {
|
||||||
|
if (data.name) {
|
||||||
|
$scope.container.Name = data.name;
|
||||||
|
Messages.send("Container renamed", $routeParams.id);
|
||||||
|
} else {
|
||||||
|
$scope.container.newContainerName = $scope.container.Name;
|
||||||
|
Messages.error("Failure", "Container failed to rename.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$scope.container.edit = false;
|
||||||
|
};
|
||||||
|
|
||||||
$scope.remove = function() {
|
|
||||||
ViewSpinner.spin();
|
|
||||||
Container.remove({id: $routeParams.id}, function(d) {
|
|
||||||
update();
|
update();
|
||||||
Messages.send("Container removed", $routeParams.id);
|
$scope.getChanges();
|
||||||
}, function(e){
|
}]);
|
||||||
update();
|
|
||||||
Messages.error("Failure", "Container failed to remove." + e.data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.restart = function() {
|
|
||||||
ViewSpinner.spin();
|
|
||||||
Container.restart({id: $routeParams.id}, function(d) {
|
|
||||||
update();
|
|
||||||
Messages.send("Container restarted", $routeParams.id);
|
|
||||||
}, function(e){
|
|
||||||
update();
|
|
||||||
Messages.error("Failure", "Container failed to restart." + e.data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.hasContent = function(data) {
|
|
||||||
return data !== null && data !== undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.getChanges = function() {
|
|
||||||
ViewSpinner.spin();
|
|
||||||
Container.changes({id: $routeParams.id}, function(d) {
|
|
||||||
$scope.changes = d;
|
|
||||||
ViewSpinner.stop();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.renameContainer = function () {
|
|
||||||
// #FIXME fix me later to handle http status to show the correct error message
|
|
||||||
Container.rename({id: $routeParams.id, 'name': $scope.container.newContainerName}, function(data){
|
|
||||||
if (data.name){
|
|
||||||
$scope.container.Name = data.name;
|
|
||||||
Messages.send("Container renamed", $routeParams.id);
|
|
||||||
}else {
|
|
||||||
$scope.container.newContainerName = $scope.container.Name;
|
|
||||||
Messages.error("Failure", "Container failed to rename.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$scope.container.edit = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
update();
|
|
||||||
$scope.getChanges();
|
|
||||||
}]);
|
|
||||||
|
|
|
@ -1,76 +1,76 @@
|
||||||
angular.module('containerLogs', [])
|
angular.module('containerLogs', [])
|
||||||
.controller('ContainerLogsController', ['$scope', '$routeParams', '$location', '$anchorScroll', 'ContainerLogs', 'Container', 'ViewSpinner',
|
.controller('ContainerLogsController', ['$scope', '$routeParams', '$location', '$anchorScroll', 'ContainerLogs', 'Container', 'ViewSpinner',
|
||||||
function($scope, $routeParams, $location, $anchorScroll, ContainerLogs, Container, ViewSpinner) {
|
function ($scope, $routeParams, $location, $anchorScroll, ContainerLogs, Container, ViewSpinner) {
|
||||||
$scope.stdout = '';
|
$scope.stdout = '';
|
||||||
$scope.stderr = '';
|
$scope.stderr = '';
|
||||||
$scope.showTimestamps = false;
|
$scope.showTimestamps = false;
|
||||||
$scope.tailLines = 2000;
|
$scope.tailLines = 2000;
|
||||||
|
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.get({id: $routeParams.id}, function(d) {
|
Container.get({id: $routeParams.id}, function (d) {
|
||||||
$scope.container = d;
|
$scope.container = d;
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
if (e.status === 404) {
|
if (e.status === 404) {
|
||||||
Messages.error("Not found", "Container not found.");
|
Messages.error("Not found", "Container not found.");
|
||||||
} else {
|
} else {
|
||||||
Messages.error("Failure", e.data);
|
Messages.error("Failure", e.data);
|
||||||
}
|
}
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
function getLogs() {
|
function getLogs() {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
ContainerLogs.get($routeParams.id, {
|
ContainerLogs.get($routeParams.id, {
|
||||||
stdout: 1,
|
stdout: 1,
|
||||||
stderr: 0,
|
stderr: 0,
|
||||||
timestamps: $scope.showTimestamps,
|
timestamps: $scope.showTimestamps,
|
||||||
tail: $scope.tailLines
|
tail: $scope.tailLines
|
||||||
}, function(data, status, headers, config) {
|
}, function (data, status, headers, config) {
|
||||||
// Replace carriage returns with newlines to clean up output
|
// Replace carriage returns with newlines to clean up output
|
||||||
data = data.replace(/[\r]/g, '\n');
|
data = data.replace(/[\r]/g, '\n');
|
||||||
// Strip 8 byte header from each line of output
|
// Strip 8 byte header from each line of output
|
||||||
data = data.substring(8);
|
data = data.substring(8);
|
||||||
data = data.replace(/\n(.{8})/g, '\n');
|
data = data.replace(/\n(.{8})/g, '\n');
|
||||||
$scope.stdout = data;
|
$scope.stdout = data;
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
ContainerLogs.get($routeParams.id, {
|
ContainerLogs.get($routeParams.id, {
|
||||||
stdout: 0,
|
stdout: 0,
|
||||||
stderr: 1,
|
stderr: 1,
|
||||||
timestamps: $scope.showTimestamps,
|
timestamps: $scope.showTimestamps,
|
||||||
tail: $scope.tailLines
|
tail: $scope.tailLines
|
||||||
}, function(data, status, headers, config) {
|
}, function (data, status, headers, config) {
|
||||||
// Replace carriage returns with newlines to clean up output
|
// Replace carriage returns with newlines to clean up output
|
||||||
data = data.replace(/[\r]/g, '\n');
|
data = data.replace(/[\r]/g, '\n');
|
||||||
// Strip 8 byte header from each line of output
|
// Strip 8 byte header from each line of output
|
||||||
data = data.substring(8);
|
data = data.substring(8);
|
||||||
data = data.replace(/\n(.{8})/g, '\n');
|
data = data.replace(/\n(.{8})/g, '\n');
|
||||||
$scope.stderr = data;
|
$scope.stderr = data;
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial call
|
// initial call
|
||||||
getLogs();
|
getLogs();
|
||||||
var logIntervalId = window.setInterval(getLogs, 5000);
|
var logIntervalId = window.setInterval(getLogs, 5000);
|
||||||
|
|
||||||
$scope.$on("$destroy", function(){
|
$scope.$on("$destroy", function () {
|
||||||
// clearing interval when view changes
|
// clearing interval when view changes
|
||||||
clearInterval(logIntervalId);
|
clearInterval(logIntervalId);
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.scrollTo = function(id) {
|
$scope.scrollTo = function (id) {
|
||||||
$location.hash(id);
|
$location.hash(id);
|
||||||
$anchorScroll();
|
$anchorScroll();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.toggleTimestamps = function() {
|
$scope.toggleTimestamps = function () {
|
||||||
getLogs();
|
getLogs();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.toggleTail = function() {
|
$scope.toggleTail = function () {
|
||||||
getLogs();
|
getLogs();
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div class="row logs">
|
<div class="row logs">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h4>Logs for container: <a href="#/containers/{{ container.Id }}/">{{ container.Name }}</a></td></h4>
|
<h4>Logs for container: <a href="#/containers/{{ container.Id }}/">{{ container.Name }}</a></td></h4>
|
||||||
|
|
||||||
<div class="btn-group detail">
|
<div class="btn-group detail">
|
||||||
<button class="btn btn-info" ng-click="scrollTo('stdout')">stdout</button>
|
<button class="btn btn-info" ng-click="scrollTo('stdout')">stdout</button>
|
||||||
<button class="btn btn-warning" ng-click="scrollTo('stderr')">stderr</button>
|
<button class="btn btn-warning" ng-click="scrollTo('stderr')">stderr</button>
|
||||||
|
@ -9,12 +10,12 @@
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<a class="btn btn-primary" ng-click="toggleTail()" role="button">Reload logs</a>
|
<a class="btn btn-primary" ng-click="toggleTail()" role="button">Reload logs</a>
|
||||||
<input id="tailLines" type="number" ng-style="{width: '45px'}"
|
<input id="tailLines" type="number" ng-style="{width: '45px'}"
|
||||||
ng-model="tailLines" ng-keypress="($event.which === 13)? toggleTail() : 0"/>
|
ng-model="tailLines" ng-keypress="($event.which === 13)? toggleTail() : 0"/>
|
||||||
<label for="tailLines">lines</label>
|
<label for="tailLines">lines</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-4">
|
<div class="col-xs-4">
|
||||||
<input id="timestampToggle" type="checkbox" ng-model="showTimestamps"
|
<input id="timestampToggle" type="checkbox" ng-model="showTimestamps"
|
||||||
ng-change="toggleTimestamps()"/> <label for="timestampToggle">Timestamps</label>
|
ng-change="toggleTimestamps()"/> <label for="timestampToggle">Timestamps</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
|
||||||
<h2>Containers:</h2>
|
<h2>Containers:</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ul class="nav nav-pills pull-left">
|
<ul class="nav nav-pills pull-left">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a class="dropdown-toggle" id="drop4" role="button" data-toggle="dropdown" data-target="#">Actions <b class="caret"></b></a>
|
<a class="dropdown-toggle" id="drop4" role="button" data-toggle="dropdown" data-target="#">Actions <b
|
||||||
|
class="caret"></b></a>
|
||||||
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
|
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
|
||||||
<li><a tabindex="-1" href="" ng-click="startAction()">Start</a></li>
|
<li><a tabindex="-1" href="" ng-click="startAction()">Start</a></li>
|
||||||
<li><a tabindex="-1" href="" ng-click="stopAction()">Stop</a></li>
|
<li><a tabindex="-1" href="" ng-click="stopAction()">Stop</a></li>
|
||||||
|
@ -18,28 +18,29 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<input type="checkbox" ng-model="displayAll" id="displayAll" ng-change="toggleGetAll()"/> <label for="displayAll">Display All</label>
|
<input type="checkbox" ng-model="displayAll" id="displayAll" ng-change="toggleGetAll()"/> <label
|
||||||
|
for="displayAll">Display All</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><input type="checkbox" ng-model="toggle" ng-change="toggleSelectAll()" /> Action</th>
|
<th><input type="checkbox" ng-model="toggle" ng-change="toggleSelectAll()"/> Action</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Image</th>
|
<th>Image</th>
|
||||||
<th>Command</th>
|
<th>Command</th>
|
||||||
<th>Created</th>
|
<th>Created</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="container in containers|orderBy:predicate">
|
<tr ng-repeat="container in containers|orderBy:predicate">
|
||||||
<td><input type="checkbox" ng-model="container.Checked" /></td>
|
<td><input type="checkbox" ng-model="container.Checked"/></td>
|
||||||
<td><a href="#/containers/{{ container.Id }}/">{{ container|containername}}</a></td>
|
<td><a href="#/containers/{{ container.Id }}/">{{ container|containername}}</a></td>
|
||||||
<td><a href="#/images/{{ container.Image }}/">{{ container.Image }}</a></td>
|
<td><a href="#/images/{{ container.Image }}/">{{ container.Image }}</a></td>
|
||||||
<td>{{ container.Command|truncate:40 }}</td>
|
<td>{{ container.Command|truncate:40 }}</td>
|
||||||
<td>{{ container.Created|getdate }}</td>
|
<td>{{ container.Created|getdate }}</td>
|
||||||
<td><span class="label label-{{ container.Status|statusbadge }}">{{ container.Status }}</span></td>
|
<td><span class="label label-{{ container.Status|statusbadge }}">{{ container.Status }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -1,111 +1,112 @@
|
||||||
angular.module('containers', [])
|
angular.module('containers', [])
|
||||||
.controller('ContainersController', ['$scope', 'Container', 'Settings', 'Messages', 'ViewSpinner',
|
.controller('ContainersController', ['$scope', 'Container', 'Settings', 'Messages', 'ViewSpinner',
|
||||||
function($scope, Container, Settings, Messages, ViewSpinner) {
|
function ($scope, Container, Settings, Messages, ViewSpinner) {
|
||||||
$scope.predicate = '-Created';
|
$scope.predicate = '-Created';
|
||||||
$scope.toggle = false;
|
$scope.toggle = false;
|
||||||
$scope.displayAll = Settings.displayAll;
|
$scope.displayAll = Settings.displayAll;
|
||||||
|
|
||||||
var update = function(data) {
|
var update = function (data) {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.query(data, function(d) {
|
Container.query(data, function (d) {
|
||||||
$scope.containers = d.map(function(item) {
|
$scope.containers = d.map(function (item) {
|
||||||
return new ContainerViewModel(item); });
|
return new ContainerViewModel(item);
|
||||||
ViewSpinner.stop();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var batch = function(items, action, msg) {
|
|
||||||
ViewSpinner.spin();
|
|
||||||
var counter = 0;
|
|
||||||
var complete = function() {
|
|
||||||
counter = counter -1;
|
|
||||||
if (counter === 0) {
|
|
||||||
ViewSpinner.stop();
|
|
||||||
update({all: Settings.displayAll ? 1 : 0});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
angular.forEach(items, function(c) {
|
|
||||||
if (c.Checked) {
|
|
||||||
if(action === Container.start){
|
|
||||||
Container.get({id: c.Id}, function(d) {
|
|
||||||
c = d;
|
|
||||||
counter = counter + 1;
|
|
||||||
action({id: c.Id, HostConfig: c.HostConfig || {}}, function(d) {
|
|
||||||
Messages.send("Container " + msg, c.Id);
|
|
||||||
var index = $scope.containers.indexOf(c);
|
|
||||||
complete();
|
|
||||||
}, function(e) {
|
|
||||||
Messages.error("Failure", e.data);
|
|
||||||
complete();
|
|
||||||
});
|
});
|
||||||
}, function(e) {
|
ViewSpinner.stop();
|
||||||
if (e.status === 404) {
|
});
|
||||||
$('.detail').hide();
|
};
|
||||||
Messages.error("Not found", "Container not found.");
|
|
||||||
} else {
|
var batch = function (items, action, msg) {
|
||||||
Messages.error("Failure", e.data);
|
ViewSpinner.spin();
|
||||||
}
|
var counter = 0;
|
||||||
complete();
|
var complete = function () {
|
||||||
});
|
counter = counter - 1;
|
||||||
|
if (counter === 0) {
|
||||||
|
ViewSpinner.stop();
|
||||||
|
update({all: Settings.displayAll ? 1 : 0});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
angular.forEach(items, function (c) {
|
||||||
|
if (c.Checked) {
|
||||||
|
if (action === Container.start) {
|
||||||
|
Container.get({id: c.Id}, function (d) {
|
||||||
|
c = d;
|
||||||
|
counter = counter + 1;
|
||||||
|
action({id: c.Id, HostConfig: c.HostConfig || {}}, function (d) {
|
||||||
|
Messages.send("Container " + msg, c.Id);
|
||||||
|
var index = $scope.containers.indexOf(c);
|
||||||
|
complete();
|
||||||
|
}, function (e) {
|
||||||
|
Messages.error("Failure", e.data);
|
||||||
|
complete();
|
||||||
|
});
|
||||||
|
}, function (e) {
|
||||||
|
if (e.status === 404) {
|
||||||
|
$('.detail').hide();
|
||||||
|
Messages.error("Not found", "Container not found.");
|
||||||
|
} else {
|
||||||
|
Messages.error("Failure", e.data);
|
||||||
|
}
|
||||||
|
complete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
counter = counter + 1;
|
||||||
|
action({id: c.Id}, function (d) {
|
||||||
|
Messages.send("Container " + msg, c.Id);
|
||||||
|
var index = $scope.containers.indexOf(c);
|
||||||
|
complete();
|
||||||
|
}, function (e) {
|
||||||
|
Messages.error("Failure", e.data);
|
||||||
|
complete();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (counter === 0) {
|
||||||
|
ViewSpinner.stop();
|
||||||
}
|
}
|
||||||
else{
|
};
|
||||||
counter = counter + 1;
|
|
||||||
action({id: c.Id}, function(d) {
|
|
||||||
Messages.send("Container " + msg, c.Id);
|
|
||||||
var index = $scope.containers.indexOf(c);
|
|
||||||
complete();
|
|
||||||
}, function(e) {
|
|
||||||
Messages.error("Failure", e.data);
|
|
||||||
complete();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
$scope.toggleSelectAll = function () {
|
||||||
|
angular.forEach($scope.containers, function (i) {
|
||||||
|
i.Checked = $scope.toggle;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
$scope.toggleGetAll = function () {
|
||||||
});
|
Settings.displayAll = $scope.displayAll;
|
||||||
if (counter === 0) {
|
update({all: Settings.displayAll ? 1 : 0});
|
||||||
ViewSpinner.stop();
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.toggleSelectAll = function() {
|
$scope.startAction = function () {
|
||||||
angular.forEach($scope.containers, function(i) {
|
batch($scope.containers, Container.start, "Started");
|
||||||
i.Checked = $scope.toggle;
|
};
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.toggleGetAll = function() {
|
$scope.stopAction = function () {
|
||||||
Settings.displayAll = $scope.displayAll;
|
batch($scope.containers, Container.stop, "Stopped");
|
||||||
update({all: Settings.displayAll ? 1 : 0});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
$scope.startAction = function() {
|
$scope.restartAction = function () {
|
||||||
batch($scope.containers, Container.start, "Started");
|
batch($scope.containers, Container.restart, "Restarted");
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.stopAction = function() {
|
$scope.killAction = function () {
|
||||||
batch($scope.containers, Container.stop, "Stopped");
|
batch($scope.containers, Container.kill, "Killed");
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.restartAction = function() {
|
$scope.pauseAction = function () {
|
||||||
batch($scope.containers, Container.restart, "Restarted");
|
batch($scope.containers, Container.pause, "Paused");
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.killAction = function() {
|
$scope.unpauseAction = function () {
|
||||||
batch($scope.containers, Container.kill, "Killed");
|
batch($scope.containers, Container.unpause, "Unpaused");
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.pauseAction = function() {
|
$scope.removeAction = function () {
|
||||||
batch($scope.containers, Container.pause, "Paused");
|
batch($scope.containers, Container.remove, "Removed");
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.unpauseAction = function() {
|
update({all: Settings.displayAll ? 1 : 0});
|
||||||
batch($scope.containers, Container.unpause, "Unpaused");
|
}]);
|
||||||
};
|
|
||||||
|
|
||||||
$scope.removeAction = function() {
|
|
||||||
batch($scope.containers, Container.remove, "Removed");
|
|
||||||
};
|
|
||||||
|
|
||||||
update({all: Settings.displayAll ? 1 : 0});
|
|
||||||
}]);
|
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
<button class="btn btn-info" ng-click="network.showSelectedUpstream()">Show Selected Upstream</button>
|
<button class="btn btn-info" ng-click="network.showSelectedUpstream()">Show Selected Upstream</button>
|
||||||
<button class="btn btn-success" ng-click="network.showAll()">Show All</button>
|
<button class="btn btn-success" ng-click="network.showAll()">Show All</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="checkbox" ng-model="includeStopped" id="includeStopped" ng-change="toggleIncludeStopped()"/> <label for="includeStopped">Include stopped containers</label>
|
<input type="checkbox" ng-model="includeStopped" id="includeStopped" ng-change="toggleIncludeStopped()"/> <label
|
||||||
|
for="includeStopped">Include stopped containers</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<vis-network data="network.data" options="network.options" events="network.events"
|
<vis-network data="network.data" options="network.options" events="network.events"
|
||||||
|
|
|
@ -1,268 +1,271 @@
|
||||||
angular.module('containersNetwork', ['ngVis'])
|
angular.module('containersNetwork', ['ngVis'])
|
||||||
.controller('ContainersNetworkController', ['$scope', '$location', 'Container', 'Messages', 'VisDataSet', function($scope, $location, Container, Messages, VisDataSet) {
|
.controller('ContainersNetworkController', ['$scope', '$location', 'Container', 'Messages', 'VisDataSet', function ($scope, $location, Container, Messages, VisDataSet) {
|
||||||
|
|
||||||
function ContainerNode(data) {
|
function ContainerNode(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
// names have the following format: /Name
|
// names have the following format: /Name
|
||||||
this.Name = data.Name.substring(1);
|
this.Name = data.Name.substring(1);
|
||||||
this.Image = data.Config.Image;
|
this.Image = data.Config.Image;
|
||||||
this.Running = data.State.Running;
|
this.Running = data.State.Running;
|
||||||
var dataLinks = data.HostConfig.Links;
|
var dataLinks = data.HostConfig.Links;
|
||||||
if (dataLinks != null) {
|
if (dataLinks != null) {
|
||||||
this.Links = {};
|
this.Links = {};
|
||||||
for (var i = 0; i < dataLinks.length; i++) {
|
for (var i = 0; i < dataLinks.length; i++) {
|
||||||
// links have the following format: /TargetContainerName:/SourceContainerName/LinkAlias
|
// links have the following format: /TargetContainerName:/SourceContainerName/LinkAlias
|
||||||
var link = dataLinks[i].split(":");
|
var link = dataLinks[i].split(":");
|
||||||
var target = link[0].substring(1);
|
var target = link[0].substring(1);
|
||||||
var alias = link[1].substring(link[1].lastIndexOf("/") + 1);
|
var alias = link[1].substring(link[1].lastIndexOf("/") + 1);
|
||||||
// only keep shortest alias
|
// only keep shortest alias
|
||||||
if (this.Links[target] == null || alias.length < this.Links[target].length) {
|
if (this.Links[target] == null || alias.length < this.Links[target].length) {
|
||||||
this.Links[target] = alias;
|
this.Links[target] = alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dataVolumes = data.HostConfig.VolumesFrom;
|
||||||
|
//converting array into properties for simpler and faster access
|
||||||
|
if (dataVolumes != null) {
|
||||||
|
this.VolumesFrom = {};
|
||||||
|
for (var j = 0; j < dataVolumes.length; j++) {
|
||||||
|
this.VolumesFrom[dataVolumes[j]] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dataVolumes = data.HostConfig.VolumesFrom;
|
|
||||||
//converting array into properties for simpler and faster access
|
|
||||||
if (dataVolumes != null) {
|
|
||||||
this.VolumesFrom = {};
|
|
||||||
for (var j = 0; j < dataVolumes.length; j++) {
|
|
||||||
this.VolumesFrom[dataVolumes[j]] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContainersNetworkData() {
|
function ContainersNetworkData() {
|
||||||
this.nodes = new VisDataSet();
|
this.nodes = new VisDataSet();
|
||||||
this.edges = new VisDataSet();
|
this.edges = new VisDataSet();
|
||||||
|
|
||||||
this.addContainerNode = function(container) {
|
this.addContainerNode = function (container) {
|
||||||
this.nodes.add({
|
this.nodes.add({
|
||||||
id: container.Id,
|
id: container.Id,
|
||||||
label: container.Name,
|
label: container.Name,
|
||||||
title: "<ul style=\"list-style-type:none; padding: 0px; margin: 0px\">" +
|
title: "<ul style=\"list-style-type:none; padding: 0px; margin: 0px\">" +
|
||||||
"<li><strong>ID:</strong> " + container.Id + "</li>" +
|
"<li><strong>ID:</strong> " + container.Id + "</li>" +
|
||||||
"<li><strong>Image:</strong> " + container.Image + "</li>" +
|
"<li><strong>Image:</strong> " + container.Image + "</li>" +
|
||||||
"</ul>",
|
"</ul>",
|
||||||
color: (container.Running ? "#8888ff" : "#cccccc")
|
color: (container.Running ? "#8888ff" : "#cccccc")
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hasEdge = function(from, to) {
|
|
||||||
return this.edges.getIds({
|
|
||||||
filter: function (item) {
|
|
||||||
return item.from == from.Id && item.to == to.Id;
|
|
||||||
} }).length > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addLinkEdgeIfExists = function(from, to) {
|
|
||||||
if (from.Links != null && from.Links[to.Name] != null && !this.hasEdge(from, to)) {
|
|
||||||
this.edges.add({
|
|
||||||
from: from.Id,
|
|
||||||
to: to.Id,
|
|
||||||
label: from.Links[to.Name] });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addVolumeEdgeIfExists = function(from, to) {
|
|
||||||
if (from.VolumesFrom != null && (from.VolumesFrom[to.Id] != null || from.VolumesFrom[to.Name] != null) && !this.hasEdge(from, to)) {
|
|
||||||
this.edges.add({
|
|
||||||
from: from.Id,
|
|
||||||
to: to.Id,
|
|
||||||
color: { color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.removeContainersNodes = function(containersIds) {
|
|
||||||
this.nodes.remove(containersIds);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function ContainersNetwork() {
|
|
||||||
this.data = new ContainersNetworkData();
|
|
||||||
this.containers = {};
|
|
||||||
this.selectedContainersIds = [];
|
|
||||||
this.shownContainersIds = [];
|
|
||||||
this.events = {
|
|
||||||
select : function(event) {
|
|
||||||
$scope.network.selectedContainersIds = event.nodes;
|
|
||||||
$scope.$apply( function() {
|
|
||||||
$scope.query = '';
|
|
||||||
});
|
});
|
||||||
},
|
};
|
||||||
doubleClick : function(event) {
|
|
||||||
$scope.$apply( function() {
|
this.hasEdge = function (from, to) {
|
||||||
$location.path('/containers/' + event.nodes[0]);
|
return this.edges.getIds({
|
||||||
});
|
filter: function (item) {
|
||||||
}
|
return item.from == from.Id && item.to == to.Id;
|
||||||
};
|
}
|
||||||
this.options = {
|
}).length > 0;
|
||||||
navigation: true,
|
};
|
||||||
keyboard: true,
|
|
||||||
height: '500px', width: '700px',
|
this.addLinkEdgeIfExists = function (from, to) {
|
||||||
nodes: {
|
if (from.Links != null && from.Links[to.Name] != null && !this.hasEdge(from, to)) {
|
||||||
shape: 'box'
|
this.edges.add({
|
||||||
},
|
from: from.Id,
|
||||||
edges: {
|
to: to.Id,
|
||||||
style: 'arrow'
|
label: from.Links[to.Name]
|
||||||
},
|
});
|
||||||
physics: {
|
|
||||||
barnesHut : {
|
|
||||||
springLength: 200
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this.addContainer = function(data) {
|
this.addVolumeEdgeIfExists = function (from, to) {
|
||||||
var container = new ContainerNode(data);
|
if (from.VolumesFrom != null && (from.VolumesFrom[to.Id] != null || from.VolumesFrom[to.Name] != null) && !this.hasEdge(from, to)) {
|
||||||
this.containers[container.Id] = container;
|
this.edges.add({
|
||||||
this.shownContainersIds.push(container.Id);
|
from: from.Id,
|
||||||
this.data.addContainerNode(container);
|
to: to.Id,
|
||||||
for (var otherContainerId in this.containers) {
|
color: {color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}
|
||||||
var otherContainer = this.containers[otherContainerId];
|
});
|
||||||
this.data.addLinkEdgeIfExists(container, otherContainer);
|
|
||||||
this.data.addLinkEdgeIfExists(otherContainer, container);
|
|
||||||
this.data.addVolumeEdgeIfExists(container, otherContainer);
|
|
||||||
this.data.addVolumeEdgeIfExists(otherContainer, container);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.selectContainers = function(query) {
|
|
||||||
if (this.component != null) {
|
|
||||||
this.selectedContainersIds = this.searchContainers(query);
|
|
||||||
this.component.selectNodes(this.selectedContainersIds);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.searchContainers = function(query) {
|
|
||||||
if (query.trim() === "") {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
var selectedContainersIds = [];
|
|
||||||
for (var i=0; i < this.shownContainersIds.length; i++) {
|
|
||||||
var container = this.containers[this.shownContainersIds[i]];
|
|
||||||
if (container.Name.indexOf(query) > -1 ||
|
|
||||||
container.Image.indexOf(query) > -1 ||
|
|
||||||
container.Id.indexOf(query) > -1) {
|
|
||||||
selectedContainersIds.push(container.Id);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return selectedContainersIds;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hideSelected = function() {
|
this.removeContainersNodes = function (containersIds) {
|
||||||
var i=0;
|
this.nodes.remove(containersIds);
|
||||||
while ( i < this.shownContainersIds.length ) {
|
};
|
||||||
if (this.selectedContainersIds.indexOf(this.shownContainersIds[i]) > -1) {
|
}
|
||||||
this.shownContainersIds.splice(i, 1);
|
|
||||||
} else {
|
function ContainersNetwork() {
|
||||||
i++;
|
this.data = new ContainersNetworkData();
|
||||||
}
|
this.containers = {};
|
||||||
}
|
|
||||||
this.data.removeContainersNodes(this.selectedContainersIds);
|
|
||||||
$scope.query = '';
|
|
||||||
this.selectedContainersIds = [];
|
this.selectedContainersIds = [];
|
||||||
};
|
this.shownContainersIds = [];
|
||||||
|
this.events = {
|
||||||
|
select: function (event) {
|
||||||
|
$scope.network.selectedContainersIds = event.nodes;
|
||||||
|
$scope.$apply(function () {
|
||||||
|
$scope.query = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
doubleClick: function (event) {
|
||||||
|
$scope.$apply(function () {
|
||||||
|
$location.path('/containers/' + event.nodes[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.options = {
|
||||||
|
navigation: true,
|
||||||
|
keyboard: true,
|
||||||
|
height: '500px', width: '700px',
|
||||||
|
nodes: {
|
||||||
|
shape: 'box'
|
||||||
|
},
|
||||||
|
edges: {
|
||||||
|
style: 'arrow'
|
||||||
|
},
|
||||||
|
physics: {
|
||||||
|
barnesHut: {
|
||||||
|
springLength: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
this.searchDownstream = function(containerId, downstreamContainersIds) {
|
this.addContainer = function (data) {
|
||||||
if (downstreamContainersIds.indexOf(containerId) > -1) {
|
var container = new ContainerNode(data);
|
||||||
return;
|
this.containers[container.Id] = container;
|
||||||
}
|
this.shownContainersIds.push(container.Id);
|
||||||
downstreamContainersIds.push(containerId);
|
this.data.addContainerNode(container);
|
||||||
var container = this.containers[containerId];
|
for (var otherContainerId in this.containers) {
|
||||||
if (container.Links == null && container.VolumesFrom == null) {
|
var otherContainer = this.containers[otherContainerId];
|
||||||
return;
|
this.data.addLinkEdgeIfExists(container, otherContainer);
|
||||||
}
|
this.data.addLinkEdgeIfExists(otherContainer, container);
|
||||||
for (var otherContainerId in this.containers) {
|
this.data.addVolumeEdgeIfExists(container, otherContainer);
|
||||||
var otherContainer = this.containers[otherContainerId];
|
this.data.addVolumeEdgeIfExists(otherContainer, container);
|
||||||
if (container.Links != null && container.Links[otherContainer.Name] != null) {
|
}
|
||||||
this.searchDownstream(otherContainer.Id, downstreamContainersIds);
|
};
|
||||||
} else if (container.VolumesFrom != null &&
|
|
||||||
|
this.selectContainers = function (query) {
|
||||||
|
if (this.component != null) {
|
||||||
|
this.selectedContainersIds = this.searchContainers(query);
|
||||||
|
this.component.selectNodes(this.selectedContainersIds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.searchContainers = function (query) {
|
||||||
|
if (query.trim() === "") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var selectedContainersIds = [];
|
||||||
|
for (var i = 0; i < this.shownContainersIds.length; i++) {
|
||||||
|
var container = this.containers[this.shownContainersIds[i]];
|
||||||
|
if (container.Name.indexOf(query) > -1 ||
|
||||||
|
container.Image.indexOf(query) > -1 ||
|
||||||
|
container.Id.indexOf(query) > -1) {
|
||||||
|
selectedContainersIds.push(container.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedContainersIds;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hideSelected = function () {
|
||||||
|
var i = 0;
|
||||||
|
while (i < this.shownContainersIds.length) {
|
||||||
|
if (this.selectedContainersIds.indexOf(this.shownContainersIds[i]) > -1) {
|
||||||
|
this.shownContainersIds.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.data.removeContainersNodes(this.selectedContainersIds);
|
||||||
|
$scope.query = '';
|
||||||
|
this.selectedContainersIds = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.searchDownstream = function (containerId, downstreamContainersIds) {
|
||||||
|
if (downstreamContainersIds.indexOf(containerId) > -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downstreamContainersIds.push(containerId);
|
||||||
|
var container = this.containers[containerId];
|
||||||
|
if (container.Links == null && container.VolumesFrom == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var otherContainerId in this.containers) {
|
||||||
|
var otherContainer = this.containers[otherContainerId];
|
||||||
|
if (container.Links != null && container.Links[otherContainer.Name] != null) {
|
||||||
|
this.searchDownstream(otherContainer.Id, downstreamContainersIds);
|
||||||
|
} else if (container.VolumesFrom != null &&
|
||||||
container.VolumesFrom[otherContainer.Id] != null) {
|
container.VolumesFrom[otherContainer.Id] != null) {
|
||||||
this.searchDownstream(otherContainer.Id, downstreamContainersIds);
|
this.searchDownstream(otherContainer.Id, downstreamContainersIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this.updateShownContainers = function(newShownContainersIds) {
|
this.updateShownContainers = function (newShownContainersIds) {
|
||||||
for (var containerId in this.containers) {
|
for (var containerId in this.containers) {
|
||||||
if (newShownContainersIds.indexOf(containerId) > -1 &&
|
if (newShownContainersIds.indexOf(containerId) > -1 &&
|
||||||
this.shownContainersIds.indexOf(containerId) === -1) {
|
this.shownContainersIds.indexOf(containerId) === -1) {
|
||||||
this.data.addContainerNode(this.containers[containerId]);
|
this.data.addContainerNode(this.containers[containerId]);
|
||||||
} else if (newShownContainersIds.indexOf(containerId) === -1 &&
|
} else if (newShownContainersIds.indexOf(containerId) === -1 &&
|
||||||
this.shownContainersIds.indexOf(containerId) > -1) {
|
this.shownContainersIds.indexOf(containerId) > -1) {
|
||||||
this.data.removeContainersNodes(containerId);
|
this.data.removeContainersNodes(containerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
this.shownContainersIds = newShownContainersIds;
|
||||||
this.shownContainersIds = newShownContainersIds;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this.showSelectedDownstream = function() {
|
this.showSelectedDownstream = function () {
|
||||||
var downstreamContainersIds = [];
|
var downstreamContainersIds = [];
|
||||||
for (var i=0; i < this.selectedContainersIds.length; i++) {
|
for (var i = 0; i < this.selectedContainersIds.length; i++) {
|
||||||
this.searchDownstream(this.selectedContainersIds[i], downstreamContainersIds);
|
this.searchDownstream(this.selectedContainersIds[i], downstreamContainersIds);
|
||||||
}
|
}
|
||||||
this.updateShownContainers(downstreamContainersIds);
|
this.updateShownContainers(downstreamContainersIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.searchUpstream = function(containerId, upstreamContainersIds) {
|
this.searchUpstream = function (containerId, upstreamContainersIds) {
|
||||||
if (upstreamContainersIds.indexOf(containerId) > -1) {
|
if (upstreamContainersIds.indexOf(containerId) > -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
upstreamContainersIds.push(containerId);
|
upstreamContainersIds.push(containerId);
|
||||||
var container = this.containers[containerId];
|
var container = this.containers[containerId];
|
||||||
for (var otherContainerId in this.containers) {
|
for (var otherContainerId in this.containers) {
|
||||||
var otherContainer = this.containers[otherContainerId];
|
var otherContainer = this.containers[otherContainerId];
|
||||||
if (otherContainer.Links != null && otherContainer.Links[container.Name] != null) {
|
if (otherContainer.Links != null && otherContainer.Links[container.Name] != null) {
|
||||||
this.searchUpstream(otherContainer.Id, upstreamContainersIds);
|
this.searchUpstream(otherContainer.Id, upstreamContainersIds);
|
||||||
} else if (otherContainer.VolumesFrom != null &&
|
} else if (otherContainer.VolumesFrom != null &&
|
||||||
otherContainer.VolumesFrom[container.Id] != null) {
|
otherContainer.VolumesFrom[container.Id] != null) {
|
||||||
this.searchUpstream(otherContainer.Id, upstreamContainersIds);
|
this.searchUpstream(otherContainer.Id, upstreamContainersIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
this.showSelectedUpstream = function() {
|
this.showSelectedUpstream = function () {
|
||||||
var upstreamContainersIds = [];
|
var upstreamContainersIds = [];
|
||||||
for (var i=0; i < this.selectedContainersIds.length; i++) {
|
for (var i = 0; i < this.selectedContainersIds.length; i++) {
|
||||||
this.searchUpstream(this.selectedContainersIds[i], upstreamContainersIds);
|
this.searchUpstream(this.selectedContainersIds[i], upstreamContainersIds);
|
||||||
}
|
|
||||||
this.updateShownContainers(upstreamContainersIds);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.showAll = function() {
|
|
||||||
for (var containerId in this.containers) {
|
|
||||||
if (this.shownContainersIds.indexOf(containerId) === -1) {
|
|
||||||
this.data.addContainerNode(this.containers[containerId]);
|
|
||||||
this.shownContainersIds.push(containerId);
|
|
||||||
}
|
}
|
||||||
}
|
this.updateShownContainers(upstreamContainersIds);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.showAll = function () {
|
||||||
|
for (var containerId in this.containers) {
|
||||||
|
if (this.shownContainersIds.indexOf(containerId) === -1) {
|
||||||
|
this.data.addContainerNode(this.containers[containerId]);
|
||||||
|
this.shownContainersIds.push(containerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.network = new ContainersNetwork();
|
||||||
|
|
||||||
|
var showFailure = function (event) {
|
||||||
|
Messages.error('Failure', e.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
var addContainer = function (container) {
|
||||||
|
$scope.network.addContainer(container);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.network = new ContainersNetwork();
|
var update = function (data) {
|
||||||
|
Container.query(data, function (d) {
|
||||||
|
for (var i = 0; i < d.length; i++) {
|
||||||
|
Container.get({id: d[i].Id}, addContainer, showFailure);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
update({all: 0});
|
||||||
|
|
||||||
var showFailure = function (event) {
|
$scope.includeStopped = false;
|
||||||
Messages.error('Failure', e.data);
|
$scope.toggleIncludeStopped = function () {
|
||||||
};
|
$scope.network.updateShownContainers([]);
|
||||||
|
update({all: $scope.includeStopped ? 1 : 0});
|
||||||
|
};
|
||||||
|
|
||||||
var addContainer = function (container) {
|
}]);
|
||||||
$scope.network.addContainer(container);
|
|
||||||
};
|
|
||||||
|
|
||||||
var update = function (data) {
|
|
||||||
Container.query(data, function(d) {
|
|
||||||
for (var i = 0; i < d.length; i++) {
|
|
||||||
Container.get({id: d[i].Id}, addContainer, showFailure);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
update({all: 0});
|
|
||||||
|
|
||||||
$scope.includeStopped = false;
|
|
||||||
$scope.toggleIncludeStopped = function() {
|
|
||||||
$scope.network.updateShownContainers([]);
|
|
||||||
update({all: $scope.includeStopped ? 1 : 0});
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
<div class="col-xs-offset-1">
|
<div class="col-xs-offset-1">
|
||||||
<!--<div class="sidebar span4">
|
<!--<div class="sidebar span4">
|
||||||
<div ng-include="template" ng-controller="SideBarController"></div>
|
<div ng-include="template" ng-controller="SideBarController"></div>
|
||||||
|
@ -7,12 +6,13 @@
|
||||||
<div class="col-xs-10" id="masthead" style="display:none">
|
<div class="col-xs-10" id="masthead" style="display:none">
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>DockerUI</h1>
|
<h1>DockerUI</h1>
|
||||||
|
|
||||||
<p class="lead">The Linux container engine</p>
|
<p class="lead">The Linux container engine</p>
|
||||||
<a class="btn btn-large btn-success" href="http://docker.io">Learn more.</a>
|
<a class="btn btn-large btn-success" href="http://docker.io">Learn more.</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-10">
|
<div class="col-xs-10">
|
||||||
<div class="col-xs-5">
|
<div class="col-xs-5">
|
||||||
|
@ -27,7 +27,8 @@
|
||||||
<div class="col-xs-5 text-right">
|
<div class="col-xs-5 text-right">
|
||||||
<h3>Status</h3>
|
<h3>Status</h3>
|
||||||
<canvas id="containers-chart" class="pull-right">
|
<canvas id="containers-chart" class="pull-right">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
</canvas>
|
</canvas>
|
||||||
<div id="chart-legend"></div>
|
<div id="chart-legend"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,13 +38,15 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-10" id="stats">
|
<div class="col-xs-10" id="stats">
|
||||||
<h4>Containers created</h4>
|
<h4>Containers created</h4>
|
||||||
<canvas id="containers-started-chart" width="700">
|
<canvas id="containers-started-chart" width="700">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
</canvas>
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
|
</canvas>
|
||||||
<h4>Images created</h4>
|
<h4>Images created</h4>
|
||||||
<canvas id="images-created-chart" width="700">
|
<canvas id="images-created-chart" width="700">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
</canvas>
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,72 +1,76 @@
|
||||||
angular.module('dashboard', [])
|
angular.module('dashboard', [])
|
||||||
.controller('DashboardController', ['$scope', 'Container', 'Image', 'Settings', 'LineChart', function($scope, Container, Image, Settings, LineChart) {
|
.controller('DashboardController', ['$scope', 'Container', 'Image', 'Settings', 'LineChart', function ($scope, Container, Image, Settings, LineChart) {
|
||||||
$scope.predicate = '-Created';
|
$scope.predicate = '-Created';
|
||||||
$scope.containers = [];
|
$scope.containers = [];
|
||||||
|
|
||||||
var getStarted = function(data) {
|
var getStarted = function (data) {
|
||||||
$scope.totalContainers = data.length;
|
$scope.totalContainers = data.length;
|
||||||
LineChart.build('#containers-started-chart', data, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
LineChart.build('#containers-started-chart', data, function (c) {
|
||||||
var s = $scope;
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
Image.query({}, function(d) {
|
});
|
||||||
s.totalImages = d.length;
|
var s = $scope;
|
||||||
LineChart.build('#images-created-chart', d, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
Image.query({}, function (d) {
|
||||||
|
s.totalImages = d.length;
|
||||||
|
LineChart.build('#images-created-chart', d, function (c) {
|
||||||
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var opts = {animation: false};
|
||||||
|
if (Settings.firstLoad) {
|
||||||
|
$('#stats').hide();
|
||||||
|
opts.animation = true;
|
||||||
|
Settings.firstLoad = false;
|
||||||
|
$('#masthead').show();
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#masthead').slideUp('slow');
|
||||||
|
$('#stats').slideDown('slow');
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Container.query({all: 1}, function (d) {
|
||||||
|
var running = 0;
|
||||||
|
var ghost = 0;
|
||||||
|
var stopped = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < d.length; i++) {
|
||||||
|
var item = d[i];
|
||||||
|
|
||||||
|
if (item.Status === "Ghost") {
|
||||||
|
ghost += 1;
|
||||||
|
} else if (item.Status.indexOf('Exit') !== -1) {
|
||||||
|
stopped += 1;
|
||||||
|
} else {
|
||||||
|
running += 1;
|
||||||
|
$scope.containers.push(new ContainerViewModel(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getStarted(d);
|
||||||
|
|
||||||
|
var c = new Chart($('#containers-chart').get(0).getContext("2d"));
|
||||||
|
var data = [
|
||||||
|
{
|
||||||
|
value: running,
|
||||||
|
color: '#5bb75b',
|
||||||
|
title: 'Running'
|
||||||
|
}, // running
|
||||||
|
{
|
||||||
|
value: stopped,
|
||||||
|
color: '#C7604C',
|
||||||
|
title: 'Stopped'
|
||||||
|
}, // stopped
|
||||||
|
{
|
||||||
|
value: ghost,
|
||||||
|
color: '#E2EAE9',
|
||||||
|
title: 'Ghost'
|
||||||
|
} // ghost
|
||||||
|
];
|
||||||
|
|
||||||
|
c.Doughnut(data, opts);
|
||||||
|
var lgd = $('#chart-legend').get(0);
|
||||||
|
legend(lgd, data);
|
||||||
});
|
});
|
||||||
};
|
}]);
|
||||||
|
|
||||||
var opts = {animation:false};
|
|
||||||
if (Settings.firstLoad) {
|
|
||||||
$('#stats').hide();
|
|
||||||
opts.animation = true;
|
|
||||||
Settings.firstLoad = false;
|
|
||||||
$('#masthead').show();
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
$('#masthead').slideUp('slow');
|
|
||||||
$('#stats').slideDown('slow');
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Container.query({all: 1}, function(d) {
|
|
||||||
var running = 0;
|
|
||||||
var ghost = 0;
|
|
||||||
var stopped = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < d.length; i++) {
|
|
||||||
var item = d[i];
|
|
||||||
|
|
||||||
if (item.Status === "Ghost") {
|
|
||||||
ghost += 1;
|
|
||||||
} else if (item.Status.indexOf('Exit') !== -1) {
|
|
||||||
stopped += 1;
|
|
||||||
} else {
|
|
||||||
running += 1;
|
|
||||||
$scope.containers.push(new ContainerViewModel(item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getStarted(d);
|
|
||||||
|
|
||||||
var c = new Chart($('#containers-chart').get(0).getContext("2d"));
|
|
||||||
var data = [
|
|
||||||
{
|
|
||||||
value: running,
|
|
||||||
color: '#5bb75b',
|
|
||||||
title: 'Running'
|
|
||||||
}, // running
|
|
||||||
{
|
|
||||||
value: stopped,
|
|
||||||
color: '#C7604C',
|
|
||||||
title: 'Stopped'
|
|
||||||
}, // stopped
|
|
||||||
{
|
|
||||||
value: ghost,
|
|
||||||
color: '#E2EAE9',
|
|
||||||
title: 'Ghost'
|
|
||||||
} // ghost
|
|
||||||
];
|
|
||||||
|
|
||||||
c.Doughnut(data, opts);
|
|
||||||
var lgd = $('#chart-legend').get(0);
|
|
||||||
legend(lgd, data);
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h2>Events</h2>
|
<h2>Events</h2>
|
||||||
|
|
||||||
<form class="form-inline">
|
<form class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="since">Since:</label>
|
<label for="since">Since:</label>
|
||||||
|
@ -15,18 +16,18 @@
|
||||||
<br>
|
<br>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Event</th>
|
<th>Event</th>
|
||||||
<th>From</th>
|
<th>From</th>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Time</th>
|
<th>Time</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-repeat="event in dockerEvents">
|
<tr ng-repeat="event in dockerEvents">
|
||||||
<td ng-bind="event.status"/>
|
<td ng-bind="event.status"/>
|
||||||
<td ng-bind="event.from"/>
|
<td ng-bind="event.from"/>
|
||||||
<td ng-bind="event.id"/>
|
<td ng-bind="event.id"/>
|
||||||
<td ng-bind="event.time * 1000 | date:'medium'"/>
|
<td ng-bind="event.time * 1000 | date:'medium'"/>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('events', ['ngOboe'])
|
angular.module('events', ['ngOboe'])
|
||||||
.controller('EventsController', ['Settings', '$scope', 'Oboe', 'Messages', '$timeout', function(Settings, $scope, oboe, Messages, $timeout) {
|
.controller('EventsController', ['Settings', '$scope', 'Oboe', 'Messages', '$timeout', function (Settings, $scope, oboe, Messages, $timeout) {
|
||||||
$scope.updateEvents = function() {
|
$scope.updateEvents = function () {
|
||||||
$scope.dockerEvents = [];
|
$scope.dockerEvents = [];
|
||||||
|
|
||||||
// TODO: Clean up URL building
|
// TODO: Clean up URL building
|
||||||
|
@ -16,18 +16,18 @@ angular.module('events', ['ngOboe'])
|
||||||
}
|
}
|
||||||
|
|
||||||
oboe({
|
oboe({
|
||||||
url: url,
|
url: url,
|
||||||
pattern: '{id status time}'
|
pattern: '{id status time}'
|
||||||
})
|
})
|
||||||
.then(function(node) {
|
.then(function (node) {
|
||||||
// finished loading
|
// finished loading
|
||||||
$timeout(function() {
|
$timeout(function () {
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
});
|
});
|
||||||
}, function(error) {
|
}, function (error) {
|
||||||
// handle errors
|
// handle errors
|
||||||
Messages.error("Failure", error.data);
|
Messages.error("Failure", error.data);
|
||||||
}, function(node) {
|
}, function (node) {
|
||||||
// node received
|
// node received
|
||||||
$scope.dockerEvents.push(node);
|
$scope.dockerEvents.push(node);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
angular.module('footer', [])
|
angular.module('footer', [])
|
||||||
.controller('FooterController', ['$scope', 'Settings', 'Docker', function($scope, Settings, Docker) {
|
.controller('FooterController', ['$scope', 'Settings', 'Docker', function ($scope, Settings, Docker) {
|
||||||
$scope.template = 'app/components/footer/statusbar.html';
|
$scope.template = 'app/components/footer/statusbar.html';
|
||||||
|
|
||||||
$scope.uiVersion = Settings.uiVersion;
|
$scope.uiVersion = Settings.uiVersion;
|
||||||
Docker.get({}, function(d) { $scope.apiVersion = d.ApiVersion; });
|
Docker.get({}, function (d) {
|
||||||
}]);
|
$scope.apiVersion = d.ApiVersion;
|
||||||
|
});
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<footer class="center well">
|
<footer class="center well">
|
||||||
<p><small>Docker API Version: <strong>{{ apiVersion }}</strong> UI Version: <strong>{{ uiVersion }}</strong> <a class="pull-right" href="https://github.com/crosbymichael/dockerui">dockerui</a></small></p>
|
<p>
|
||||||
|
<small>Docker API Version: <strong>{{ apiVersion }}</strong> UI Version: <strong>{{ uiVersion }}</strong> <a
|
||||||
|
class="pull-right" href="https://github.com/crosbymichael/dockerui">dockerui</a></small>
|
||||||
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -5,59 +5,60 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
|
|
||||||
<h4>Image: {{ tag }}</h4>
|
<h4>Image: {{ tag }}</h4>
|
||||||
|
|
||||||
<div class="btn-group detail">
|
<div class="btn-group detail">
|
||||||
<button class="btn btn-success" data-toggle="modal" data-target="#create-modal">Create</button>
|
<button class="btn btn-success" data-toggle="modal" data-target="#create-modal">Create</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4>Containers created:</h4>
|
<h4>Containers created:</h4>
|
||||||
<canvas id="containers-started-chart" width="750">
|
<canvas id="containers-started-chart" width="750">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
</canvas>
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Created:</td>
|
<td>Created:</td>
|
||||||
<td>{{ image.Created }}</td>
|
<td>{{ image.Created }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Parent:</td>
|
<td>Parent:</td>
|
||||||
<td><a href="#/images/{{ image.Parent }}/">{{ image.Parent }}</a></td>
|
<td><a href="#/images/{{ image.Parent }}/">{{ image.Parent }}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Size (Virtual Size):</td>
|
<td>Size (Virtual Size):</td>
|
||||||
<td>{{ image.Size|humansize }} ({{ image.VirtualSize|humansize }})</td>
|
<td>{{ image.Size|humansize }} ({{ image.VirtualSize|humansize }})</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Hostname:</td>
|
<td>Hostname:</td>
|
||||||
<td>{{ image.ContainerConfig.Hostname }}</td>
|
<td>{{ image.ContainerConfig.Hostname }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>User:</td>
|
<td>User:</td>
|
||||||
<td>{{ image.ContainerConfig.User }}</td>
|
<td>{{ image.ContainerConfig.User }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Cmd:</td>
|
<td>Cmd:</td>
|
||||||
<td>{{ image.ContainerConfig.Cmd }}</td>
|
<td>{{ image.ContainerConfig.Cmd }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Volumes:</td>
|
<td>Volumes:</td>
|
||||||
<td>{{ image.ContainerConfig.Volumes }}</td>
|
<td>{{ image.ContainerConfig.Volumes }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Volumes from:</td>
|
<td>Volumes from:</td>
|
||||||
<td>{{ image.ContainerConfig.VolumesFrom }}</td>
|
<td>{{ image.ContainerConfig.VolumesFrom }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Built with:</td>
|
<td>Built with:</td>
|
||||||
<td>Docker {{ image.DockerVersion }} on {{ image.Os}}, {{ image.Architecture }}</td>
|
<td>Docker {{ image.DockerVersion }} on {{ image.Os}}, {{ image.Architecture }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -69,17 +70,18 @@
|
||||||
<div class="span5">
|
<div class="span5">
|
||||||
<i class="icon-refresh" style="width:32px;height:32px;" ng-click="getHistory()"></i>
|
<i class="icon-refresh" style="width:32px;height:32px;" ng-click="getHistory()"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="well well-large">
|
<div class="well well-large">
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-repeat="change in history">
|
<li ng-repeat="change in history">
|
||||||
<strong>{{ change.Id }}</strong>: Created: {{ change.Created|getdate }} Created by: {{ change.CreatedBy }}
|
<strong>{{ change.Id }}</strong>: Created: {{ change.Created|getdate }} Created by: {{ change.CreatedBy
|
||||||
|
}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr/>
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<form class="form-inline" role="form">
|
<form class="form-inline" role="form">
|
||||||
|
@ -94,12 +96,12 @@
|
||||||
<input type="checkbox" ng-model="tag.force" class="form-control"/> Force?
|
<input type="checkbox" ng-model="tag.force" class="form-control"/> Force?
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<input type="button" ng-click="updateTag()" value="Tag" class="btn btn-primary"/>
|
<input type="button" ng-click="updateTag()" value="Tag" class="btn btn-primary"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr/>
|
||||||
|
|
||||||
<div class="btn-remove">
|
<div class="btn-remove">
|
||||||
<button class="btn btn-large btn-block btn-primary btn-danger" ng-click="remove()">Remove Image</button>
|
<button class="btn btn-large btn-block btn-primary btn-danger" ng-click="remove()">Remove Image</button>
|
||||||
|
|
|
@ -1,72 +1,74 @@
|
||||||
angular.module('image', [])
|
angular.module('image', [])
|
||||||
.controller('ImageController', ['$scope', '$q', '$routeParams', '$location', 'Image', 'Container', 'Messages', 'LineChart',
|
.controller('ImageController', ['$scope', '$q', '$routeParams', '$location', 'Image', 'Container', 'Messages', 'LineChart',
|
||||||
function($scope, $q, $routeParams, $location, Image, Container, Messages, LineChart) {
|
function ($scope, $q, $routeParams, $location, Image, Container, Messages, LineChart) {
|
||||||
$scope.history = [];
|
$scope.history = [];
|
||||||
$scope.tag = {repo: '', force: false};
|
$scope.tag = {repo: '', force: false};
|
||||||
|
|
||||||
$scope.remove = function() {
|
$scope.remove = function () {
|
||||||
Image.remove({id: $routeParams.id}, function(d) {
|
Image.remove({id: $routeParams.id}, function (d) {
|
||||||
Messages.send("Image Removed", $routeParams.id);
|
Messages.send("Image Removed", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
$scope.error = e.data;
|
$scope.error = e.data;
|
||||||
$('#error-message').show();
|
$('#error-message').show();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getHistory = function() {
|
$scope.getHistory = function () {
|
||||||
Image.history({id: $routeParams.id}, function(d) {
|
Image.history({id: $routeParams.id}, function (d) {
|
||||||
$scope.history = d;
|
$scope.history = d;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.updateTag = function() {
|
$scope.updateTag = function () {
|
||||||
var tag = $scope.tag;
|
var tag = $scope.tag;
|
||||||
Image.tag({id: $routeParams.id, repo: tag.repo, force: tag.force ? 1 : 0}, function(d) {
|
Image.tag({id: $routeParams.id, repo: tag.repo, force: tag.force ? 1 : 0}, function (d) {
|
||||||
Messages.send("Tag Added", $routeParams.id);
|
Messages.send("Tag Added", $routeParams.id);
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
$scope.error = e.data;
|
$scope.error = e.data;
|
||||||
$('#error-message').show();
|
$('#error-message').show();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function getContainersFromImage($q, Container, tag) {
|
function getContainersFromImage($q, Container, tag) {
|
||||||
var defer = $q.defer();
|
var defer = $q.defer();
|
||||||
|
|
||||||
Container.query({all:1, notruc:1}, function(d) {
|
Container.query({all: 1, notruc: 1}, function (d) {
|
||||||
var containers = [];
|
var containers = [];
|
||||||
for (var i = 0; i < d.length; i++) {
|
for (var i = 0; i < d.length; i++) {
|
||||||
var c = d[i];
|
var c = d[i];
|
||||||
if (c.Image === tag) {
|
if (c.Image === tag) {
|
||||||
containers.push(new ContainerViewModel(c));
|
containers.push(new ContainerViewModel(c));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
defer.resolve(containers);
|
||||||
|
});
|
||||||
|
|
||||||
|
return defer.promise;
|
||||||
}
|
}
|
||||||
defer.resolve(containers);
|
|
||||||
});
|
|
||||||
|
|
||||||
return defer.promise;
|
Image.get({id: $routeParams.id}, function (d) {
|
||||||
}
|
$scope.image = d;
|
||||||
|
$scope.tag = d.id;
|
||||||
|
var t = $routeParams.tag;
|
||||||
|
if (t && t !== ":") {
|
||||||
|
$scope.tag = t;
|
||||||
|
var promise = getContainersFromImage($q, Container, t);
|
||||||
|
|
||||||
Image.get({id: $routeParams.id}, function(d) {
|
promise.then(function (containers) {
|
||||||
$scope.image = d;
|
LineChart.build('#containers-started-chart', containers, function (c) {
|
||||||
$scope.tag = d.id;
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
var t = $routeParams.tag;
|
});
|
||||||
if (t && t !== ":") {
|
});
|
||||||
$scope.tag = t;
|
}
|
||||||
var promise = getContainersFromImage($q, Container, t);
|
}, function (e) {
|
||||||
|
if (e.status === 404) {
|
||||||
promise.then(function(containers) {
|
$('.detail').hide();
|
||||||
LineChart.build('#containers-started-chart', containers, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
$scope.error = "Image not found.<br />" + $routeParams.id;
|
||||||
|
} else {
|
||||||
|
$scope.error = e.data;
|
||||||
|
}
|
||||||
|
$('#error-message').show();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}, function(e) {
|
|
||||||
if (e.status === 404) {
|
|
||||||
$('.detail').hide();
|
|
||||||
$scope.error = "Image not found.<br />" + $routeParams.id;
|
|
||||||
} else {
|
|
||||||
$scope.error = e.data;
|
|
||||||
}
|
|
||||||
$('#error-message').show();
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.getHistory();
|
$scope.getHistory();
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a class="dropdown-toggle" id="drop4" role="button" data-toggle="dropdown" data-target="#">Actions <b class="caret"></b></a>
|
<a class="dropdown-toggle" id="drop4" role="button" data-toggle="dropdown" data-target="#">Actions <b
|
||||||
|
class="caret"></b></a>
|
||||||
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
|
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
|
||||||
<li><a tabindex="-1" href="" ng-click="removeAction()">Remove</a></li>
|
<li><a tabindex="-1" href="" ng-click="removeAction()">Remove</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -14,21 +15,21 @@
|
||||||
</ul>
|
</ul>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><input type="checkbox" ng-model="toggle" ng-change="toggleSelectAll()" /> Action</th>
|
<th><input type="checkbox" ng-model="toggle" ng-change="toggleSelectAll()"/> Action</th>
|
||||||
<th>Id</th>
|
<th>Id</th>
|
||||||
<th>Repository</th>
|
<th>Repository</th>
|
||||||
<th>VirtualSize</th>
|
<th>VirtualSize</th>
|
||||||
<th>Created</th>
|
<th>Created</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="image in images | orderBy:predicate">
|
<tr ng-repeat="image in images | orderBy:predicate">
|
||||||
<td><input type="checkbox" ng-model="image.Checked" /></td>
|
<td><input type="checkbox" ng-model="image.Checked"/></td>
|
||||||
<td><a href="#/images/{{ image.Id }}/?tag={{ image|repotag }}">{{ image.Id|truncate:20}}</a></td>
|
<td><a href="#/images/{{ image.Id }}/?tag={{ image|repotag }}">{{ image.Id|truncate:20}}</a></td>
|
||||||
<td>{{ image|repotag }}</td>
|
<td>{{ image|repotag }}</td>
|
||||||
<td>{{ image.VirtualSize|humansize }}</td>
|
<td>{{ image.VirtualSize|humansize }}</td>
|
||||||
<td>{{ image.Created|getdate }}</td>
|
<td>{{ image.Created|getdate }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -1,52 +1,54 @@
|
||||||
angular.module('images', [])
|
angular.module('images', [])
|
||||||
.controller('ImagesController', ['$scope', 'Image', 'ViewSpinner', 'Messages',
|
.controller('ImagesController', ['$scope', 'Image', 'ViewSpinner', 'Messages',
|
||||||
function($scope, Image, ViewSpinner, Messages) {
|
function ($scope, Image, ViewSpinner, Messages) {
|
||||||
$scope.toggle = false;
|
$scope.toggle = false;
|
||||||
$scope.predicate = '-Created';
|
$scope.predicate = '-Created';
|
||||||
|
|
||||||
$scope.showBuilder = function() {
|
$scope.showBuilder = function () {
|
||||||
$('#build-modal').modal('show');
|
$('#build-modal').modal('show');
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.removeAction = function() {
|
$scope.removeAction = function () {
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
var complete = function() {
|
var complete = function () {
|
||||||
counter = counter - 1;
|
counter = counter - 1;
|
||||||
if (counter === 0) {
|
if (counter === 0) {
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
angular.forEach($scope.images, function(i) {
|
angular.forEach($scope.images, function (i) {
|
||||||
if (i.Checked) {
|
if (i.Checked) {
|
||||||
counter = counter + 1;
|
counter = counter + 1;
|
||||||
Image.remove({id: i.Id}, function(d) {
|
Image.remove({id: i.Id}, function (d) {
|
||||||
angular.forEach(d, function(resource) {
|
angular.forEach(d, function (resource) {
|
||||||
Messages.send("Image deleted", resource.Deleted);
|
Messages.send("Image deleted", resource.Deleted);
|
||||||
});
|
});
|
||||||
var index = $scope.images.indexOf(i);
|
var index = $scope.images.indexOf(i);
|
||||||
$scope.images.splice(index, 1);
|
$scope.images.splice(index, 1);
|
||||||
complete();
|
complete();
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
Messages.error("Failure", e.data);
|
Messages.error("Failure", e.data);
|
||||||
complete();
|
complete();
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.toggleSelectAll = function() {
|
$scope.toggleSelectAll = function () {
|
||||||
angular.forEach($scope.images, function(i) {
|
angular.forEach($scope.images, function (i) {
|
||||||
i.Checked = $scope.toggle;
|
i.Checked = $scope.toggle;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Image.query({}, function(d) {
|
Image.query({}, function (d) {
|
||||||
$scope.images = d.map(function(item) { return new ImageViewModel(item); });
|
$scope.images = d.map(function (item) {
|
||||||
ViewSpinner.stop();
|
return new ImageViewModel(item);
|
||||||
}, function (e) {
|
});
|
||||||
Messages.error("Failure", e.data);
|
ViewSpinner.stop();
|
||||||
ViewSpinner.stop();
|
}, function (e) {
|
||||||
});
|
Messages.error("Failure", e.data);
|
||||||
}]);
|
ViewSpinner.stop();
|
||||||
|
});
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,109 +1,110 @@
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<h2>Docker Information</h2>
|
<h2>Docker Information</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class="lead">
|
<p class="lead">
|
||||||
<strong>API Endpoint: </strong>{{ endpoint }}<br />
|
<strong>API Endpoint: </strong>{{ endpoint }}<br/>
|
||||||
<strong>API Version: </strong>{{ docker.ApiVersion }}<br />
|
<strong>API Version: </strong>{{ docker.ApiVersion }}<br/>
|
||||||
<strong>Docker version: </strong>{{ docker.Version }}<br />
|
<strong>Docker version: </strong>{{ docker.Version }}<br/>
|
||||||
<strong>Git Commit: </strong>{{ docker.GitCommit }}<br />
|
<strong>Git Commit: </strong>{{ docker.GitCommit }}<br/>
|
||||||
<strong>Go Version: </strong>{{ docker.GoVersion }}<br />
|
<strong>Go Version: </strong>{{ docker.GoVersion }}<br/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Containers:</td>
|
<td>Containers:</td>
|
||||||
<td>{{ info.Containers }}</td>
|
<td>{{ info.Containers }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Images:</td>
|
<td>Images:</td>
|
||||||
<td>{{ info.Images }}</td>
|
<td>{{ info.Images }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Debug:</td>
|
<td>Debug:</td>
|
||||||
<td>{{ info.Debug }}</td>
|
<td>{{ info.Debug }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>CPUs:</td>
|
<td>CPUs:</td>
|
||||||
<td>{{ info.NCPU }}</td>
|
<td>{{ info.NCPU }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Memory:</td>
|
<td>Total Memory:</td>
|
||||||
<td>{{ info.MemTotal|humansize }}</td>
|
<td>{{ info.MemTotal|humansize }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Operating System:</td>
|
<td>Operating System:</td>
|
||||||
<td>{{ info.OperatingSystem }}</td>
|
<td>{{ info.OperatingSystem }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Kernel Version:</td>
|
<td>Kernel Version:</td>
|
||||||
<td>{{ info.KernelVersion }}</td>
|
<td>{{ info.KernelVersion }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>ID:</td>
|
<td>ID:</td>
|
||||||
<td>{{ info.ID }}</td>
|
<td>{{ info.ID }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Labels:</td>
|
<td>Labels:</td>
|
||||||
<td>{{ info.Labels }}</td>
|
<td>{{ info.Labels }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>File Descriptors:</td>
|
<td>File Descriptors:</td>
|
||||||
<td>{{ info.NFd }}</td>
|
<td>{{ info.NFd }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Goroutines:</td>
|
<td>Goroutines:</td>
|
||||||
<td>{{ info.NGoroutines }}</td>
|
<td>{{ info.NGoroutines }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Storage Driver:</td>
|
<td>Storage Driver:</td>
|
||||||
<td>{{ info.Driver }}</td>
|
<td>{{ info.Driver }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Storage Driver Status:</td>
|
<td>Storage Driver Status:</td>
|
||||||
<td>
|
<td>
|
||||||
<p ng-repeat="val in info.DriverStatus">
|
<p ng-repeat="val in info.DriverStatus">
|
||||||
{{ val[0] }}: {{ val[1] }}
|
{{ val[0] }}: {{ val[1] }}
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Execution Driver:</td>
|
<td>Execution Driver:</td>
|
||||||
<td>{{ info.ExecutionDriver }}</td>
|
<td>{{ info.ExecutionDriver }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Events:</td>
|
<td>Events:</td>
|
||||||
<td><a href="#/events">Events</a></td>
|
<td><a href="#/events">Events</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IPv4 Forwarding:</td>
|
<td>IPv4 Forwarding:</td>
|
||||||
<td>{{ info.IPv4Forwarding }}</td>
|
<td>{{ info.IPv4Forwarding }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Index Server Address:</td>
|
<td>Index Server Address:</td>
|
||||||
<td>{{ info.IndexServerAddress }}</td>
|
<td>{{ info.IndexServerAddress }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Init Path:</td>
|
<td>Init Path:</td>
|
||||||
<td>{{ info.InitPath }}</td>
|
<td>{{ info.InitPath }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Docker Root Directory:</td>
|
<td>Docker Root Directory:</td>
|
||||||
<td>{{ info.DockerRootDir }}</td>
|
<td>{{ info.DockerRootDir }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Init SHA1</td>
|
<td>Init SHA1</td>
|
||||||
<td>{{ info.InitSha1 }}</td>
|
<td>{{ info.InitSha1 }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Memory Limit:</td>
|
<td>Memory Limit:</td>
|
||||||
<td>{{ info.MemoryLimit }}</td>
|
<td>{{ info.MemoryLimit }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Swap Limit:</td>
|
<td>Swap Limit:</td>
|
||||||
<td>{{ info.SwapLimit }}</td>
|
<td>{{ info.SwapLimit }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
angular.module('info', [])
|
angular.module('info', [])
|
||||||
.controller('InfoController', ['$scope', 'System', 'Docker', 'Settings', 'Messages',
|
.controller('InfoController', ['$scope', 'System', 'Docker', 'Settings', 'Messages',
|
||||||
function($scope, System, Docker, Settings, Messages) {
|
function ($scope, System, Docker, Settings, Messages) {
|
||||||
$scope.info = {};
|
$scope.info = {};
|
||||||
$scope.docker = {};
|
$scope.docker = {};
|
||||||
$scope.endpoint = Settings.endpoint;
|
$scope.endpoint = Settings.endpoint;
|
||||||
$scope.apiVersion = Settings.version;
|
$scope.apiVersion = Settings.version;
|
||||||
|
|
||||||
Docker.get({}, function(d) { $scope.docker = d; });
|
Docker.get({}, function (d) {
|
||||||
System.get({}, function(d) { $scope.info = d; });
|
$scope.docker = d;
|
||||||
}]);
|
});
|
||||||
|
System.get({}, function (d) {
|
||||||
|
$scope.info = d;
|
||||||
|
});
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="masthead">
|
<div class="masthead">
|
||||||
<h3 class="text-muted">DockerUI</h3>
|
<h3 class="text-muted">DockerUI</h3>
|
||||||
<ul class="nav well">
|
<ul class="nav well">
|
||||||
<li><a href="#">Dashboard</a></li>
|
<li><a href="#">Dashboard</a></li>
|
||||||
<li><a href="#/containers/">Containers</a></li>
|
<li><a href="#/containers/">Containers</a></li>
|
||||||
<li><a href="#/containers_network/">Containers Network</a></li>
|
<li><a href="#/containers_network/">Containers Network</a></li>
|
||||||
<li><a href="#/images/">Images</a></li>
|
<li><a href="#/images/">Images</a></li>
|
||||||
<li><a href="#/info/">Info</a></li>
|
<li><a href="#/info/">Info</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
angular.module('masthead', [])
|
angular.module('masthead', [])
|
||||||
.controller('MastheadController', ['$scope', function($scope) {
|
.controller('MastheadController', ['$scope', function ($scope) {
|
||||||
$scope.template = 'app/components/masthead/masthead.html';
|
$scope.template = 'app/components/masthead/masthead.html';
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -13,19 +13,23 @@
|
||||||
</div>-->
|
</div>-->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Registry:</label>
|
<label>Registry:</label>
|
||||||
<input type="text" ng-model="config.registry" class="form-control" placeholder="Registry. Leave empty to user docker hub"/>
|
<input type="text" ng-model="config.registry" class="form-control"
|
||||||
|
placeholder="Registry. Leave empty to user docker hub"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Repo:</label>
|
<label>Repo:</label>
|
||||||
<input type="text" ng-model="config.repo" class="form-control" placeholder="Repository - usually your username."/>
|
<input type="text" ng-model="config.repo" class="form-control"
|
||||||
|
placeholder="Repository - usually your username."/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Image Name:</label>
|
<label>Image Name:</label>
|
||||||
<input type="text" ng-model="config.fromImage" class="form-control" placeholder="Image name" required/>
|
<input type="text" ng-model="config.fromImage" class="form-control" placeholder="Image name"
|
||||||
|
required/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Tag Name:</label>
|
<label>Tag Name:</label>
|
||||||
<input type="text" ng-model="config.tag" class="form-control" placeholder="Tag name. If empty it will download ALL tags."/>
|
<input type="text" ng-model="config.tag" class="form-control"
|
||||||
|
placeholder="Tag name. If empty it will download ALL tags."/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
angular.module('pullImage', [])
|
angular.module('pullImage', [])
|
||||||
.controller('PullImageController', ['$scope', '$log', 'Dockerfile', 'Messages', 'Image', 'ViewSpinner',
|
.controller('PullImageController', ['$scope', '$log', 'Dockerfile', 'Messages', 'Image', 'ViewSpinner',
|
||||||
function($scope, $log, Dockerfile, Messages, Image, ViewSpinner) {
|
function ($scope, $log, Dockerfile, Messages, Image, ViewSpinner) {
|
||||||
$scope.template = 'app/components/pullImage/pullImage.html';
|
$scope.template = 'app/components/pullImage/pullImage.html';
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function () {
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
registry: '',
|
registry: '',
|
||||||
repo: '',
|
repo: '',
|
||||||
|
@ -18,7 +18,7 @@ angular.module('pullImage', [])
|
||||||
Messages.error('Error', errorMsgFilter(e));
|
Messages.error('Error', errorMsgFilter(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.pull = function() {
|
$scope.pull = function () {
|
||||||
$('#error-message').hide();
|
$('#error-message').hide();
|
||||||
var config = angular.copy($scope.config);
|
var config = angular.copy($scope.config);
|
||||||
var imageName = (config.registry ? config.registry + '/' : '' ) +
|
var imageName = (config.registry ? config.registry + '/' : '' ) +
|
||||||
|
@ -28,10 +28,10 @@ angular.module('pullImage', [])
|
||||||
|
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
$('#pull-modal').modal('hide');
|
$('#pull-modal').modal('hide');
|
||||||
Image.create(config, function(data) {
|
Image.create(config, function (data) {
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
if (data.constructor === Array) {
|
if (data.constructor === Array) {
|
||||||
var f = data.length > 0 && data[data.length-1].hasOwnProperty('error');
|
var f = data.length > 0 && data[data.length - 1].hasOwnProperty('error');
|
||||||
//check for error
|
//check for error
|
||||||
if (f) {
|
if (f) {
|
||||||
var d = data[data.length - 1];
|
var d = data[data.length - 1];
|
||||||
|
@ -46,7 +46,7 @@ angular.module('pullImage', [])
|
||||||
Messages.send("Image Added", imageName);
|
Messages.send("Image Added", imageName);
|
||||||
$scope.init();
|
$scope.init();
|
||||||
}
|
}
|
||||||
}, function(e) {
|
}, function (e) {
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
$scope.error = "Cannot pull image " + imageName + " Reason: " + e.data;
|
$scope.error = "Cannot pull image " + imageName + " Reason: " + e.data;
|
||||||
$('#pull-modal').modal('show');
|
$('#pull-modal').modal('show');
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<strong>Running containers:</strong>
|
<strong>Running containers:</strong>
|
||||||
<br />
|
<br/>
|
||||||
<strong>Endpoint: </strong>{{ endpoint }}
|
<strong>Endpoint: </strong>{{ endpoint }}
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-repeat="container in containers">
|
<li ng-repeat="container in containers">
|
||||||
<a href="#/containers/{{ container.Id }}/">{{ container.Id|truncate:20 }}</a>
|
<a href="#/containers/{{ container.Id }}/">{{ container.Id|truncate:20 }}</a>
|
||||||
<span class="pull-right label label-{{ container.Status|statusbadge }}">{{ container.Status }}</span>
|
<span class="pull-right label label-{{ container.Status|statusbadge }}">{{ container.Status }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
angular.module('sidebar', [])
|
angular.module('sidebar', [])
|
||||||
.controller('SideBarController', ['$scope', 'Container', 'Settings',
|
.controller('SideBarController', ['$scope', 'Container', 'Settings',
|
||||||
function($scope, Container, Settings) {
|
function ($scope, Container, Settings) {
|
||||||
$scope.template = 'partials/sidebar.html';
|
$scope.template = 'partials/sidebar.html';
|
||||||
$scope.containers = [];
|
$scope.containers = [];
|
||||||
$scope.endpoint = Settings.endpoint;
|
$scope.endpoint = Settings.endpoint;
|
||||||
|
|
||||||
Container.query({all: 0}, function(d) {
|
Container.query({all: 0}, function (d) {
|
||||||
$scope.containers = d;
|
$scope.containers = d;
|
||||||
});
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,147 +1,153 @@
|
||||||
angular.module('startContainer', ['ui.bootstrap'])
|
angular.module('startContainer', ['ui.bootstrap'])
|
||||||
.controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter', 'errorMsgFilter',
|
.controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter', 'errorMsgFilter',
|
||||||
function($scope, $routeParams, $location, Container, Messages, containernameFilter, errorMsgFilter) {
|
function ($scope, $routeParams, $location, Container, Messages, containernameFilter, errorMsgFilter) {
|
||||||
$scope.template = 'app/components/startContainer/startcontainer.html';
|
$scope.template = 'app/components/startContainer/startcontainer.html';
|
||||||
|
|
||||||
Container.query({all: 1}, function(d) {
|
Container.query({all: 1}, function (d) {
|
||||||
$scope.containerNames = d.map(function(container){
|
$scope.containerNames = d.map(function (container) {
|
||||||
return containernameFilter(container);
|
return containernameFilter(container);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
Env: [],
|
Env: [],
|
||||||
Volumes: [],
|
Volumes: [],
|
||||||
SecurityOpts: [],
|
SecurityOpts: [],
|
||||||
HostConfig: {
|
HostConfig: {
|
||||||
PortBindings: [],
|
PortBindings: [],
|
||||||
Binds: [],
|
Binds: [],
|
||||||
Links: [],
|
Links: [],
|
||||||
Dns: [],
|
Dns: [],
|
||||||
DnsSearch: [],
|
DnsSearch: [],
|
||||||
VolumesFrom: [],
|
VolumesFrom: [],
|
||||||
CapAdd: [],
|
CapAdd: [],
|
||||||
CapDrop: [],
|
CapDrop: [],
|
||||||
Devices: [],
|
Devices: [],
|
||||||
LxcConf: [],
|
LxcConf: [],
|
||||||
ExtraHosts: []
|
ExtraHosts: []
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
$scope.menuStatus = {
|
|
||||||
containerOpen: true,
|
|
||||||
hostConfigOpen: false
|
|
||||||
};
|
|
||||||
|
|
||||||
function failedRequestHandler(e, Messages) {
|
|
||||||
Messages.error('Error', errorMsgFilter(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
function rmEmptyKeys(col) {
|
|
||||||
for (var key in col) {
|
|
||||||
if (col[key] === null || col[key] === undefined || col[key] === '' || $.isEmptyObject(col[key]) || col[key].length === 0) {
|
|
||||||
delete col[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNames(arr) {
|
|
||||||
return arr.map(function(item) {return item.name;});
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.create = function() {
|
|
||||||
// Copy the config before transforming fields to the remote API format
|
|
||||||
var config = angular.copy($scope.config);
|
|
||||||
|
|
||||||
config.Image = $routeParams.id;
|
|
||||||
|
|
||||||
if (config.Cmd && config.Cmd[0] === "[") {
|
|
||||||
config.Cmd = angular.fromJson(config.Cmd);
|
|
||||||
} else if (config.Cmd) {
|
|
||||||
config.Cmd = config.Cmd.split(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Env = config.Env.map(function(envar) {return envar.name + '=' + envar.value;});
|
|
||||||
|
|
||||||
config.Volumes = getNames(config.Volumes);
|
|
||||||
config.SecurityOpts = getNames(config.SecurityOpts);
|
|
||||||
|
|
||||||
config.HostConfig.VolumesFrom = getNames(config.HostConfig.VolumesFrom);
|
|
||||||
config.HostConfig.Binds = getNames(config.HostConfig.Binds);
|
|
||||||
config.HostConfig.Links = getNames(config.HostConfig.Links);
|
|
||||||
config.HostConfig.Dns = getNames(config.HostConfig.Dns);
|
|
||||||
config.HostConfig.DnsSearch = getNames(config.HostConfig.DnsSearch);
|
|
||||||
config.HostConfig.CapAdd = getNames(config.HostConfig.CapAdd);
|
|
||||||
config.HostConfig.CapDrop = getNames(config.HostConfig.CapDrop);
|
|
||||||
config.HostConfig.LxcConf = config.HostConfig.LxcConf.reduce(function(prev, cur, idx){
|
|
||||||
prev[cur.name] = cur.value;
|
|
||||||
return prev;
|
|
||||||
}, {});
|
|
||||||
config.HostConfig.ExtraHosts = config.HostConfig.ExtraHosts.map(function(entry) {return entry.host + ':' + entry.ip;});
|
|
||||||
|
|
||||||
var ExposedPorts = {};
|
|
||||||
var PortBindings = {};
|
|
||||||
config.HostConfig.PortBindings.forEach(function(portBinding) {
|
|
||||||
var intPort = portBinding.intPort + "/tcp";
|
|
||||||
if (portBinding.protocol === "udp") {
|
|
||||||
intPort = portBinding.intPort + "/udp";
|
|
||||||
}
|
|
||||||
var binding = {
|
|
||||||
HostIp: portBinding.ip,
|
|
||||||
HostPort: portBinding.extPort
|
|
||||||
};
|
};
|
||||||
if (portBinding.intPort) {
|
|
||||||
ExposedPorts[intPort] = {};
|
$scope.menuStatus = {
|
||||||
if (intPort in PortBindings) {
|
containerOpen: true,
|
||||||
PortBindings[intPort].push(binding);
|
hostConfigOpen: false
|
||||||
} else {
|
};
|
||||||
PortBindings[intPort] = [binding];
|
|
||||||
}
|
function failedRequestHandler(e, Messages) {
|
||||||
} else {
|
Messages.error('Error', errorMsgFilter(e));
|
||||||
Messages.send('Warning', 'Internal port must be specified for PortBindings');
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
config.ExposedPorts = ExposedPorts;
|
|
||||||
config.HostConfig.PortBindings = PortBindings;
|
|
||||||
|
|
||||||
// Remove empty fields from the request to avoid overriding defaults
|
function rmEmptyKeys(col) {
|
||||||
rmEmptyKeys(config.HostConfig);
|
for (var key in col) {
|
||||||
rmEmptyKeys(config);
|
if (col[key] === null || col[key] === undefined || col[key] === '' || $.isEmptyObject(col[key]) || col[key].length === 0) {
|
||||||
|
delete col[key];
|
||||||
var ctor = Container;
|
}
|
||||||
var loc = $location;
|
|
||||||
var s = $scope;
|
|
||||||
Container.create(config, function(d) {
|
|
||||||
if (d.Id) {
|
|
||||||
var reqBody = config.HostConfig || {};
|
|
||||||
reqBody.id = d.Id;
|
|
||||||
ctor.start(reqBody, function(cd) {
|
|
||||||
if (cd.id) {
|
|
||||||
Messages.send('Container Started', d.Id);
|
|
||||||
$('#create-modal').modal('hide');
|
|
||||||
loc.path('/containers/' + d.Id + '/');
|
|
||||||
} else {
|
|
||||||
failedRequestHandler(cd, Messages);
|
|
||||||
ctor.remove({id: d.Id}, function() {
|
|
||||||
Messages.send('Container Removed', d.Id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(e) {
|
|
||||||
failedRequestHandler(e, Messages);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
failedRequestHandler(d, Messages);
|
|
||||||
}
|
}
|
||||||
}, function(e) {
|
}
|
||||||
failedRequestHandler(e, Messages);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.addEntry = function(array, entry) {
|
function getNames(arr) {
|
||||||
array.push(entry);
|
return arr.map(function (item) {
|
||||||
};
|
return item.name;
|
||||||
$scope.rmEntry = function(array, entry) {
|
});
|
||||||
var idx = array.indexOf(entry);
|
}
|
||||||
array.splice(idx, 1);
|
|
||||||
};
|
$scope.create = function () {
|
||||||
}]);
|
// Copy the config before transforming fields to the remote API format
|
||||||
|
var config = angular.copy($scope.config);
|
||||||
|
|
||||||
|
config.Image = $routeParams.id;
|
||||||
|
|
||||||
|
if (config.Cmd && config.Cmd[0] === "[") {
|
||||||
|
config.Cmd = angular.fromJson(config.Cmd);
|
||||||
|
} else if (config.Cmd) {
|
||||||
|
config.Cmd = config.Cmd.split(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Env = config.Env.map(function (envar) {
|
||||||
|
return envar.name + '=' + envar.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
config.Volumes = getNames(config.Volumes);
|
||||||
|
config.SecurityOpts = getNames(config.SecurityOpts);
|
||||||
|
|
||||||
|
config.HostConfig.VolumesFrom = getNames(config.HostConfig.VolumesFrom);
|
||||||
|
config.HostConfig.Binds = getNames(config.HostConfig.Binds);
|
||||||
|
config.HostConfig.Links = getNames(config.HostConfig.Links);
|
||||||
|
config.HostConfig.Dns = getNames(config.HostConfig.Dns);
|
||||||
|
config.HostConfig.DnsSearch = getNames(config.HostConfig.DnsSearch);
|
||||||
|
config.HostConfig.CapAdd = getNames(config.HostConfig.CapAdd);
|
||||||
|
config.HostConfig.CapDrop = getNames(config.HostConfig.CapDrop);
|
||||||
|
config.HostConfig.LxcConf = config.HostConfig.LxcConf.reduce(function (prev, cur, idx) {
|
||||||
|
prev[cur.name] = cur.value;
|
||||||
|
return prev;
|
||||||
|
}, {});
|
||||||
|
config.HostConfig.ExtraHosts = config.HostConfig.ExtraHosts.map(function (entry) {
|
||||||
|
return entry.host + ':' + entry.ip;
|
||||||
|
});
|
||||||
|
|
||||||
|
var ExposedPorts = {};
|
||||||
|
var PortBindings = {};
|
||||||
|
config.HostConfig.PortBindings.forEach(function (portBinding) {
|
||||||
|
var intPort = portBinding.intPort + "/tcp";
|
||||||
|
if (portBinding.protocol === "udp") {
|
||||||
|
intPort = portBinding.intPort + "/udp";
|
||||||
|
}
|
||||||
|
var binding = {
|
||||||
|
HostIp: portBinding.ip,
|
||||||
|
HostPort: portBinding.extPort
|
||||||
|
};
|
||||||
|
if (portBinding.intPort) {
|
||||||
|
ExposedPorts[intPort] = {};
|
||||||
|
if (intPort in PortBindings) {
|
||||||
|
PortBindings[intPort].push(binding);
|
||||||
|
} else {
|
||||||
|
PortBindings[intPort] = [binding];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Messages.send('Warning', 'Internal port must be specified for PortBindings');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
config.ExposedPorts = ExposedPorts;
|
||||||
|
config.HostConfig.PortBindings = PortBindings;
|
||||||
|
|
||||||
|
// Remove empty fields from the request to avoid overriding defaults
|
||||||
|
rmEmptyKeys(config.HostConfig);
|
||||||
|
rmEmptyKeys(config);
|
||||||
|
|
||||||
|
var ctor = Container;
|
||||||
|
var loc = $location;
|
||||||
|
var s = $scope;
|
||||||
|
Container.create(config, function (d) {
|
||||||
|
if (d.Id) {
|
||||||
|
var reqBody = config.HostConfig || {};
|
||||||
|
reqBody.id = d.Id;
|
||||||
|
ctor.start(reqBody, function (cd) {
|
||||||
|
if (cd.id) {
|
||||||
|
Messages.send('Container Started', d.Id);
|
||||||
|
$('#create-modal').modal('hide');
|
||||||
|
loc.path('/containers/' + d.Id + '/');
|
||||||
|
} else {
|
||||||
|
failedRequestHandler(cd, Messages);
|
||||||
|
ctor.remove({id: d.Id}, function () {
|
||||||
|
Messages.send('Container Removed', d.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, function (e) {
|
||||||
|
failedRequestHandler(e, Messages);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
failedRequestHandler(d, Messages);
|
||||||
|
}
|
||||||
|
}, function (e) {
|
||||||
|
failedRequestHandler(e, Messages);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addEntry = function (array, entry) {
|
||||||
|
array.push(entry);
|
||||||
|
};
|
||||||
|
$scope.rmEntry = function (array, entry) {
|
||||||
|
var idx = array.indexOf(entry);
|
||||||
|
array.splice(idx, 1);
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
|
@ -6,301 +6,413 @@
|
||||||
<h3>Create And Start Container From Image</h3>
|
<h3>Create And Start Container From Image</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form role="form">
|
<form role="form">
|
||||||
<accordion close-others="true">
|
<accordion close-others="true">
|
||||||
<accordion-group heading="Container options" is-open="menuStatus.containerOpen">
|
<accordion-group heading="Container options" is-open="menuStatus.containerOpen">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Cmd:</label>
|
<label>Cmd:</label>
|
||||||
<input type="text" placeholder='["/bin/echo", "Hello world"]' ng-model="config.Cmd" class="form-control"/>
|
<input type="text" placeholder='["/bin/echo", "Hello world"]'
|
||||||
<small>Input commands as a raw string or JSON array</small>
|
ng-model="config.Cmd" class="form-control"/>
|
||||||
</div>
|
<small>Input commands as a raw string or JSON array</small>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>Entrypoint:</label>
|
<div class="form-group">
|
||||||
<input type="text" ng-model="config.Entrypoint" class="form-control" placeholder="./entrypoint.sh"/>
|
<label>Entrypoint:</label>
|
||||||
</div>
|
<input type="text" ng-model="config.Entrypoint" class="form-control"
|
||||||
<div class="form-group">
|
placeholder="./entrypoint.sh"/>
|
||||||
<label>Name:</label>
|
</div>
|
||||||
<input type="text" ng-model="config.name" class="form-control"/>
|
<div class="form-group">
|
||||||
</div>
|
<label>Name:</label>
|
||||||
<div class="form-group">
|
<input type="text" ng-model="config.name" class="form-control"/>
|
||||||
<label>Hostname:</label>
|
</div>
|
||||||
<input type="text" ng-model="config.Hostname" class="form-control"/>
|
<div class="form-group">
|
||||||
</div>
|
<label>Hostname:</label>
|
||||||
<div class="form-group">
|
<input type="text" ng-model="config.Hostname" class="form-control"/>
|
||||||
<label>Domainname:</label>
|
</div>
|
||||||
<input type="text" ng-model="config.Domainname" class="form-control"/>
|
<div class="form-group">
|
||||||
</div>
|
<label>Domainname:</label>
|
||||||
<div class="form-group">
|
<input type="text" ng-model="config.Domainname" class="form-control"/>
|
||||||
<label>User:</label>
|
</div>
|
||||||
<input type="text" ng-model="config.User" class="form-control"/>
|
<div class="form-group">
|
||||||
</div>
|
<label>User:</label>
|
||||||
<div class="form-group">
|
<input type="text" ng-model="config.User" class="form-control"/>
|
||||||
<label>Memory:</label>
|
</div>
|
||||||
<input type="number" ng-model="config.Memory" class="form-control"/>
|
<div class="form-group">
|
||||||
</div>
|
<label>Memory:</label>
|
||||||
<div class="form-group">
|
<input type="number" ng-model="config.Memory" class="form-control"/>
|
||||||
<label>Volumes:</label>
|
</div>
|
||||||
<div ng-repeat="volume in config.Volumes">
|
<div class="form-group">
|
||||||
<div class="form-group form-inline">
|
<label>Volumes:</label>
|
||||||
<input type="text" ng-model="volume.name" class="form-control" placeholder="/var/data"/>
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.Volumes, volume)">Remove</button>
|
<div ng-repeat="volume in config.Volumes">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="volume.name" class="form-control"
|
||||||
|
placeholder="/var/data"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.Volumes, volume)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.Volumes, {name: ''})">Add Volume
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.Volumes, {name: ''})">Add Volume</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-xs-6">
|
||||||
<div class="col-xs-6">
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>MemorySwap:</label>
|
||||||
<label>MemorySwap:</label>
|
<input type="number" ng-model="config.MemorySwap" class="form-control"/>
|
||||||
<input type="number" ng-model="config.MemorySwap" class="form-control"/>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>CpuShares:</label>
|
||||||
<label>CpuShares:</label>
|
<input type="number" ng-model="config.CpuShares" class="form-control"/>
|
||||||
<input type="number" ng-model="config.CpuShares" class="form-control"/>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>Cpuset:</label>
|
||||||
<label>Cpuset:</label>
|
<input type="text" ng-model="config.Cpuset" class="form-control"
|
||||||
<input type="text" ng-model="config.Cpuset" class="form-control" placeholder="1,2"/>
|
placeholder="1,2"/>
|
||||||
<small>Input as comma-separated list of numbers</small>
|
<small>Input as comma-separated list of numbers</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>WorkingDir:</label>
|
<label>WorkingDir:</label>
|
||||||
<input type="text" ng-model="config.WorkingDir" class="form-control" placeholder="/app"/>
|
<input type="text" ng-model="config.WorkingDir" class="form-control"
|
||||||
</div>
|
placeholder="/app"/>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>MacAddress:</label>
|
<div class="form-group">
|
||||||
<input type="text" ng-model="config.MacAddress" class="form-control" placeholder="12:34:56:78:9a:bc"/>
|
<label>MacAddress:</label>
|
||||||
</div>
|
<input type="text" ng-model="config.MacAddress" class="form-control"
|
||||||
<div class="form-group">
|
placeholder="12:34:56:78:9a:bc"/>
|
||||||
<label for="networkDisabled">NetworkDisabled:</label>
|
</div>
|
||||||
<input id="networkDisabled" type="checkbox" ng-model="config.NetworkDisabled"/>
|
<div class="form-group">
|
||||||
</div>
|
<label for="networkDisabled">NetworkDisabled:</label>
|
||||||
<div class="form-group">
|
<input id="networkDisabled" type="checkbox"
|
||||||
<label for="tty">Tty:</label>
|
ng-model="config.NetworkDisabled"/>
|
||||||
<input id="tty" type="checkbox" ng-model="config.Tty"/>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="tty">Tty:</label>
|
||||||
<label for="openStdin">OpenStdin:</label>
|
<input id="tty" type="checkbox" ng-model="config.Tty"/>
|
||||||
<input id="openStdin" type="checkbox" ng-model="config.OpenStdin"/>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="openStdin">OpenStdin:</label>
|
||||||
<label for="stdinOnce">StdinOnce:</label>
|
<input id="openStdin" type="checkbox" ng-model="config.OpenStdin"/>
|
||||||
<input id="stdinOnce" type="checkbox" ng-model="config.StdinOnce"/>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="stdinOnce">StdinOnce:</label>
|
||||||
<label>SecurityOpts:</label>
|
<input id="stdinOnce" type="checkbox" ng-model="config.StdinOnce"/>
|
||||||
<div ng-repeat="opt in config.SecurityOpts">
|
</div>
|
||||||
<div class="form-group form-inline">
|
<div class="form-group">
|
||||||
<input type="text" ng-model="opt.name" class="form-control" placeholder="label:type:svirt_apache"/>
|
<label>SecurityOpts:</label>
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.SecurityOpts, opt)">Remove</button>
|
|
||||||
|
<div ng-repeat="opt in config.SecurityOpts">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="opt.name" class="form-control"
|
||||||
|
placeholder="label:type:svirt_apache"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.SecurityOpts, opt)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.SecurityOpts, {name: ''})">Add Option</button>
|
ng-click="addEntry(config.SecurityOpts, {name: ''})">Add Option
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Env:</label>
|
|
||||||
<div ng-repeat="envar in config.Env">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="sr-only">Variable Name:</label>
|
|
||||||
<input type="text" ng-model="envar.name" class="form-control" placeholder="NAME"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="sr-only">Variable Value:</label>
|
|
||||||
<input type="text" ng-model="envar.value" class="form-control" placeholder="value"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.Env, envar)">Remove</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.Env, {name: '', value: ''})">Add environment variable</button>
|
<hr>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</fieldset>
|
<label>Env:</label>
|
||||||
</accordion-group>
|
|
||||||
<accordion-group heading="HostConfig options" is-open="menuStatus.hostConfigOpen">
|
<div ng-repeat="envar in config.Env">
|
||||||
<fieldset>
|
<div class="form-group form-inline">
|
||||||
<div class="row">
|
<div class="form-group">
|
||||||
<div class="col-xs-6">
|
<label class="sr-only">Variable Name:</label>
|
||||||
<div class="form-group">
|
<input type="text" ng-model="envar.name" class="form-control"
|
||||||
<label>Binds:</label>
|
placeholder="NAME"/>
|
||||||
<div ng-repeat="bind in config.HostConfig.Binds">
|
</div>
|
||||||
<div class="form-group form-inline">
|
<div class="form-group">
|
||||||
<input type="text" ng-model="bind.name" class="form-control" placeholder="/host:/container"/>
|
<label class="sr-only">Variable Value:</label>
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Binds, bind)">Remove</button>
|
<input type="text" ng-model="envar.value" class="form-control"
|
||||||
|
placeholder="value"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.Env, envar)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Binds, {name: ''})">Add Bind</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Links:</label>
|
|
||||||
<div ng-repeat="link in config.HostConfig.Links">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<input type="text" ng-model="link.name" class="form-control" placeholder="web:db">
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Links, link)">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Links, {name: ''})">Add Link</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Dns:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.Dns">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="8.8.8.8"/>
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Dns, entry)">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Dns, {name: ''})">Add entry</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>DnsSearch:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.DnsSearch">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="example.com"/>
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.DnsSearch, entry)">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.DnsSearch, {name: ''})">Add entry</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>CapAdd:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.CapAdd">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapAdd, entry)">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.CapAdd, {name: ''})">Add entry</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>CapDrop:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.CapDrop">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
|
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapDrop, entry)">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.CapDrop, {name: ''})">Add entry</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.Env, {name: '', value: ''})">Add environment
|
||||||
|
variable
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
</fieldset>
|
||||||
<div class="form-group">
|
</accordion-group>
|
||||||
<label>NetworkMode:</label>
|
<accordion-group heading="HostConfig options" is-open="menuStatus.hostConfigOpen">
|
||||||
<input type="text" ng-model="config.HostConfig.NetworkMode" class="form-control" placeholder="bridge"/>
|
<fieldset>
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="form-group">
|
<div class="col-xs-6">
|
||||||
<label for="publishAllPorts">PublishAllPorts:</label>
|
<div class="form-group">
|
||||||
<input id="publishAllPorts" type="checkbox" ng-model="config.HostConfig.PublishAllPorts"/>
|
<label>Binds:</label>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div ng-repeat="bind in config.HostConfig.Binds">
|
||||||
<label for="privileged">Privileged:</label>
|
<div class="form-group form-inline">
|
||||||
<input id="privileged" type="checkbox" ng-model="config.HostConfig.Privileged"/>
|
<input type="text" ng-model="bind.name" class="form-control"
|
||||||
</div>
|
placeholder="/host:/container"/>
|
||||||
<div class="form-group">
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
<label>VolumesFrom:</label>
|
ng-click="rmEntry(config.HostConfig.Binds, bind)">Remove
|
||||||
<div ng-repeat="volume in config.HostConfig.VolumesFrom">
|
</button>
|
||||||
<div class="form-group form-inline">
|
</div>
|
||||||
<select ng-model="volume.name" ng-options="name for name in containerNames track by name" class="form-control"/>
|
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.VolumesFrom, volume)">Remove</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Binds, {name: ''})">Add Bind
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Links:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="link in config.HostConfig.Links">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="link.name" class="form-control"
|
||||||
|
placeholder="web:db">
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Links, link)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Links, {name: ''})">Add Link
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Dns:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="entry in config.HostConfig.Dns">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
|
placeholder="8.8.8.8"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Dns, entry)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Dns, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>DnsSearch:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="entry in config.HostConfig.DnsSearch">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
|
placeholder="example.com"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.DnsSearch, entry)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.DnsSearch, {name: ''})">Add
|
||||||
|
entry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>CapAdd:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="entry in config.HostConfig.CapAdd">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
|
placeholder="cap_sys_admin"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.CapAdd, entry)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.CapAdd, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>CapDrop:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="entry in config.HostConfig.CapDrop">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
|
placeholder="cap_sys_admin"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.CapDrop, entry)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.CapDrop, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.VolumesFrom, {name: ''})">Add volume</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
|
||||||
<label>RestartPolicy:</label>
|
|
||||||
<select ng-model="config.HostConfig.RestartPolicy.name">
|
|
||||||
<option value="">disabled</option>
|
|
||||||
<option value="always">always</option>
|
|
||||||
<option value="on-failure">on-failure</option>
|
|
||||||
</select>
|
|
||||||
<label>MaximumRetryCount:</label>
|
|
||||||
<input type="number" ng-model="config.HostConfig.RestartPolicy.MaximumRetryCount"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>ExtraHosts:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.ExtraHosts">
|
|
||||||
<div class="form-group form-inline">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Hostname:</label>
|
<label>NetworkMode:</label>
|
||||||
<input type="text" ng-model="entry.host" class="form-control" placeholder="hostname"/>
|
<input type="text" ng-model="config.HostConfig.NetworkMode"
|
||||||
|
class="form-control" placeholder="bridge"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">IP Address:</label>
|
<label for="publishAllPorts">PublishAllPorts:</label>
|
||||||
<input type="text" ng-model="entry.ip" class="form-control" placeholder="127.0.0.1"/>
|
<input id="publishAllPorts" type="checkbox"
|
||||||
|
ng-model="config.HostConfig.PublishAllPorts"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.ExtraHosts, entry)">Remove</button>
|
<label for="privileged">Privileged:</label>
|
||||||
|
<input id="privileged" type="checkbox"
|
||||||
|
ng-model="config.HostConfig.Privileged"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>VolumesFrom:</label>
|
||||||
|
|
||||||
|
<div ng-repeat="volume in config.HostConfig.VolumesFrom">
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<select ng-model="volume.name"
|
||||||
|
ng-options="name for name in containerNames track by name"
|
||||||
|
class="form-control"/>
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.VolumesFrom, volume)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.VolumesFrom, {name: ''})">Add
|
||||||
|
volume
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>RestartPolicy:</label>
|
||||||
|
<select ng-model="config.HostConfig.RestartPolicy.name">
|
||||||
|
<option value="">disabled</option>
|
||||||
|
<option value="always">always</option>
|
||||||
|
<option value="on-failure">on-failure</option>
|
||||||
|
</select>
|
||||||
|
<label>MaximumRetryCount:</label>
|
||||||
|
<input type="number"
|
||||||
|
ng-model="config.HostConfig.RestartPolicy.MaximumRetryCount"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.ExtraHosts, {host: '', ip: ''})">Add extra host</button>
|
<hr>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>ExtraHosts:</label>
|
||||||
<label>LxcConf:</label>
|
|
||||||
<div ng-repeat="entry in config.HostConfig.LxcConf">
|
<div ng-repeat="entry in config.HostConfig.ExtraHosts">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Name:</label>
|
<label class="sr-only">Hostname:</label>
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="lxc.utsname"/>
|
<input type="text" ng-model="entry.host" class="form-control"
|
||||||
</div>
|
placeholder="hostname"/>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label class="sr-only">Value:</label>
|
<div class="form-group">
|
||||||
<input type="text" ng-model="entry.value" class="form-control" placeholder="docker"/>
|
<label class="sr-only">IP Address:</label>
|
||||||
</div>
|
<input type="text" ng-model="entry.ip" class="form-control"
|
||||||
<div class="form-group">
|
placeholder="127.0.0.1"/>
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.LxcConf, entry)">Remove</button>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.ExtraHosts, entry)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.ExtraHosts, {host: '', ip: ''})">Add
|
||||||
|
extra host
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.LxcConf, {name: '', value: ''})">Add Entry</button>
|
<div class="form-group">
|
||||||
</div>
|
<label>LxcConf:</label>
|
||||||
<div class="form-group">
|
|
||||||
<label>Devices:</label>
|
<div ng-repeat="entry in config.HostConfig.LxcConf">
|
||||||
<div ng-repeat="device in config.HostConfig.Devices">
|
<div class="form-group form-inline">
|
||||||
<div class="form-group form-inline inline-four">
|
<div class="form-group">
|
||||||
<label class="sr-only">PathOnHost:</label>
|
<label class="sr-only">Name:</label>
|
||||||
<input type="text" ng-model="device.PathOnHost" class="form-control" placeholder="PathOnHost"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
<label class="sr-only">PathInContainer:</label>
|
placeholder="lxc.utsname"/>
|
||||||
<input type="text" ng-model="device.PathInContainer" class="form-control" placeholder="PathInContainer"/>
|
</div>
|
||||||
<label class="sr-only">CgroupPermissions:</label>
|
<div class="form-group">
|
||||||
<input type="text" ng-model="device.CgroupPermissions" class="form-control" placeholder="CgroupPermissions"/>
|
<label class="sr-only">Value:</label>
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.Devices, device)">Remove</button>
|
<input type="text" ng-model="entry.value" class="form-control"
|
||||||
|
placeholder="docker"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.LxcConf, entry)">Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.LxcConf, {name: '', value: ''})">Add
|
||||||
|
Entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Devices, { PathOnHost: '', PathInContainer: '', CgroupPermissions: ''})">Add Device</button>
|
<div class="form-group">
|
||||||
</div>
|
<label>Devices:</label>
|
||||||
<div class="form-group">
|
|
||||||
<label>PortBindings:</label>
|
<div ng-repeat="device in config.HostConfig.Devices">
|
||||||
<div ng-repeat="portBinding in config.HostConfig.PortBindings">
|
<div class="form-group form-inline inline-four">
|
||||||
<div class="form-group form-inline inline-four">
|
<label class="sr-only">PathOnHost:</label>
|
||||||
<label class="sr-only">Host IP:</label>
|
<input type="text" ng-model="device.PathOnHost" class="form-control"
|
||||||
<input type="text" ng-model="portBinding.ip" class="form-control" placeholder="Host IP Address"/>
|
placeholder="PathOnHost"/>
|
||||||
<label class="sr-only">Host Port:</label>
|
<label class="sr-only">PathInContainer:</label>
|
||||||
<input type="text" ng-model="portBinding.extPort" class="form-control" placeholder="Host Port"/>
|
<input type="text" ng-model="device.PathInContainer" class="form-control"
|
||||||
<label class="sr-only">Container port:</label>
|
placeholder="PathInContainer"/>
|
||||||
<input type="text" ng-model="portBinding.intPort" class="form-control" placeholder="Container Port"/>
|
<label class="sr-only">CgroupPermissions:</label>
|
||||||
<select ng-model="portBinding.protocol">
|
<input type="text" ng-model="device.CgroupPermissions" class="form-control"
|
||||||
<option value="">tcp</option>
|
placeholder="CgroupPermissions"/>
|
||||||
<option value="udp">udp</option>
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
</select>
|
ng-click="rmEntry(config.HostConfig.Devices, device)">Remove
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.PortBindings, portBinding)">Remove</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Devices, { PathOnHost: '', PathInContainer: '', CgroupPermissions: ''})">
|
||||||
|
Add Device
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.PortBindings, {ip: '', extPort: '', intPort: ''})">Add Port Binding</button>
|
<div class="form-group">
|
||||||
</div>
|
<label>PortBindings:</label>
|
||||||
</fieldset>
|
|
||||||
</accordion-group>
|
<div ng-repeat="portBinding in config.HostConfig.PortBindings">
|
||||||
</accordion>
|
<div class="form-group form-inline inline-four">
|
||||||
|
<label class="sr-only">Host IP:</label>
|
||||||
|
<input type="text" ng-model="portBinding.ip" class="form-control"
|
||||||
|
placeholder="Host IP Address"/>
|
||||||
|
<label class="sr-only">Host Port:</label>
|
||||||
|
<input type="text" ng-model="portBinding.extPort" class="form-control"
|
||||||
|
placeholder="Host Port"/>
|
||||||
|
<label class="sr-only">Container port:</label>
|
||||||
|
<input type="text" ng-model="portBinding.intPort" class="form-control"
|
||||||
|
placeholder="Container Port"/>
|
||||||
|
<select ng-model="portBinding.protocol">
|
||||||
|
<option value="">tcp</option>
|
||||||
|
<option value="udp">udp</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.PortBindings, portBinding)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.PortBindings, {ip: '', extPort: '', intPort: ''})">
|
||||||
|
Add Port Binding
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</accordion-group>
|
||||||
|
</accordion>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
<br>
|
<br>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Time read</th>
|
<th>Time read</th>
|
||||||
<th>CPU usage</th>
|
<th>CPU usage</th>
|
||||||
<th>Stat</th>
|
<th>Stat</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-repeat="stat in dockerStats">
|
<tr ng-repeat="stat in dockerStats">
|
||||||
<td ng-bind="stat.read"/>
|
<td ng-bind="stat.read"/>
|
||||||
<td ng-bind="calculateCPUPercent(stat)"/>
|
<td ng-bind="calculateCPUPercent(stat)"/>
|
||||||
<td ng-bind="stat"/>
|
<td ng-bind="stat"/>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,9 @@ angular.module('stats', [])
|
||||||
function updateStats() {
|
function updateStats() {
|
||||||
Container.stats({id: $routeParams.id}, function (d) {
|
Container.stats({id: $routeParams.id}, function (d) {
|
||||||
console.log(d);
|
console.log(d);
|
||||||
var arr = Object.keys(d).map(function (key) {return d[key];});
|
var arr = Object.keys(d).map(function (key) {
|
||||||
|
return d[key];
|
||||||
|
});
|
||||||
if (arr.join('').indexOf('no such id') !== -1) {
|
if (arr.join('').indexOf('no such id') !== -1) {
|
||||||
Messages.error('Unable to retrieve container stats', 'Has this container been removed?');
|
Messages.error('Unable to retrieve container stats', 'Has this container been removed?');
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
angular.module('dockerui.filters', [])
|
angular.module('dockerui.filters', [])
|
||||||
.filter('truncate', function() {
|
.filter('truncate', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(text, length, end) {
|
return function (text, length, end) {
|
||||||
if (isNaN(length)) {
|
if (isNaN(length)) {
|
||||||
length = 10;
|
length = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end === undefined){
|
if (end === undefined) {
|
||||||
end = '...';
|
end = '...';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ angular.module('dockerui.filters', [])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('statusbadge', function() {
|
.filter('statusbadge', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(text) {
|
return function (text) {
|
||||||
if (text === 'Ghost') {
|
if (text === 'Ghost') {
|
||||||
return 'important';
|
return 'important';
|
||||||
} else if (text.indexOf('Exit') !== -1 && text !== 'Exit 0') {
|
} else if (text.indexOf('Exit') !== -1 && text !== 'Exit 0') {
|
||||||
|
@ -29,9 +29,9 @@ angular.module('dockerui.filters', [])
|
||||||
return 'success';
|
return 'success';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('getstatetext', function() {
|
.filter('getstatetext', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(state) {
|
return function (state) {
|
||||||
if (state === undefined) {
|
if (state === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,9 @@ angular.module('dockerui.filters', [])
|
||||||
return 'Stopped';
|
return 'Stopped';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('getstatelabel', function() {
|
.filter('getstatelabel', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(state) {
|
return function (state) {
|
||||||
if (state === undefined) {
|
if (state === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -63,45 +63,47 @@ angular.module('dockerui.filters', [])
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('humansize', function() {
|
.filter('humansize', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(bytes) {
|
return function (bytes) {
|
||||||
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||||
if (bytes === 0) {
|
if (bytes === 0) {
|
||||||
return 'n/a';
|
return 'n/a';
|
||||||
}
|
}
|
||||||
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
||||||
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[[i]];
|
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[[i]];
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('containername', function() {
|
.filter('containername', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(container) {
|
return function (container) {
|
||||||
var name = container.Names[0];
|
var name = container.Names[0];
|
||||||
return name.substring(1, name.length);
|
return name.substring(1, name.length);
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('repotag', function() {
|
.filter('repotag', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(image) {
|
return function (image) {
|
||||||
if (image.RepoTags && image.RepoTags.length > 0) {
|
if (image.RepoTags && image.RepoTags.length > 0) {
|
||||||
var tag = image.RepoTags[0];
|
var tag = image.RepoTags[0];
|
||||||
if (tag === '<none>:<none>') { tag = ''; }
|
if (tag === '<none>:<none>') {
|
||||||
|
tag = '';
|
||||||
|
}
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('getdate', function() {
|
.filter('getdate', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
return function(data) {
|
return function (data) {
|
||||||
//Multiply by 1000 for the unix format
|
//Multiply by 1000 for the unix format
|
||||||
var date = new Date(data * 1000);
|
var date = new Date(data * 1000);
|
||||||
return date.toDateString();
|
return date.toDateString();
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('errorMsg', function() {
|
.filter('errorMsg', function () {
|
||||||
return function(object) {
|
return function (object) {
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
var msg = '';
|
var msg = '';
|
||||||
while (object[idx] && typeof(object[idx]) === 'string') {
|
while (object[idx] && typeof(object[idx]) === 'string') {
|
||||||
|
|
|
@ -25,16 +25,16 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
'use strict';
|
'use strict';
|
||||||
return {
|
return {
|
||||||
commit: function (params, callback) {
|
commit: function (params, callback) {
|
||||||
$http({
|
$http({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: Settings.url + '/commit',
|
url: Settings.url + '/commit',
|
||||||
params: {
|
params: {
|
||||||
'container': params.id,
|
'container': params.id,
|
||||||
'repo': params.repo
|
'repo': params.repo
|
||||||
}
|
}
|
||||||
}).success(callback).error(function (data, status, headers, config) {
|
}).success(callback).error(function (data, status, headers, config) {
|
||||||
console.log(error, data);
|
console.log(error, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
@ -80,11 +80,13 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
get: {method: 'GET', params: {action: 'json'}},
|
get: {method: 'GET', params: {action: 'json'}},
|
||||||
search: {method: 'GET', params: {action: 'search'}},
|
search: {method: 'GET', params: {action: 'search'}},
|
||||||
history: {method: 'GET', params: {action: 'history'}, isArray: true},
|
history: {method: 'GET', params: {action: 'history'}, isArray: true},
|
||||||
create: {method: 'POST', isArray: true, transformResponse: [function f(data) {
|
create: {
|
||||||
var str = data.replace(/\n/g, " ").replace(/\}\W*\{/g, "}, {");
|
method: 'POST', isArray: true, transformResponse: [function f(data) {
|
||||||
return angular.fromJson("[" + str + "]");
|
var str = data.replace(/\n/g, " ").replace(/\}\W*\{/g, "}, {");
|
||||||
}],
|
return angular.fromJson("[" + str + "]");
|
||||||
params: {action: 'create', fromImage: '@fromImage', repo: '@repo', tag: '@tag', registry: '@registry'}},
|
}],
|
||||||
|
params: {action: 'create', fromImage: '@fromImage', repo: '@repo', tag: '@tag', registry: '@registry'}
|
||||||
|
},
|
||||||
insert: {method: 'POST', params: {id: '@id', action: 'insert'}},
|
insert: {method: 'POST', params: {id: '@id', action: 'insert'}},
|
||||||
push: {method: 'POST', params: {id: '@id', action: 'push'}},
|
push: {method: 'POST', params: {id: '@id', action: 'push'}},
|
||||||
tag: {method: 'POST', params: {id: '@id', action: 'tag', force: 0, repo: '@repo'}},
|
tag: {method: 'POST', params: {id: '@id', action: 'tag', force: 0, repo: '@repo'}},
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
function ImageViewModel(data) {
|
function ImageViewModel(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
this.Tag = data.Tag;
|
this.Tag = data.Tag;
|
||||||
|
@ -10,12 +9,12 @@ function ImageViewModel(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ContainerViewModel(data) {
|
function ContainerViewModel(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
this.Image = data.Image;
|
this.Image = data.Image;
|
||||||
this.Command = data.Command;
|
this.Command = data.Command;
|
||||||
this.Created = data.Created;
|
this.Created = data.Created;
|
||||||
this.SizeRw = data.SizeRw;
|
this.SizeRw = data.SizeRw;
|
||||||
this.Status = data.Status;
|
this.Status = data.Status;
|
||||||
this.Checked = false;
|
this.Checked = false;
|
||||||
this.Names = data.Names;
|
this.Names = data.Names;
|
||||||
}
|
}
|
||||||
|
|
89
gruntFile.js
89
gruntFile.js
|
@ -11,19 +11,19 @@ module.exports = function (grunt) {
|
||||||
grunt.loadNpmTasks('grunt-html2js');
|
grunt.loadNpmTasks('grunt-html2js');
|
||||||
|
|
||||||
// Default task.
|
// Default task.
|
||||||
grunt.registerTask('default', ['jshint','build','karma:unit']);
|
grunt.registerTask('default', ['jshint', 'build', 'karma:unit']);
|
||||||
grunt.registerTask('build', ['clean','html2js','concat','recess:build', 'copy']);
|
grunt.registerTask('build', ['clean', 'html2js', 'concat', 'recess:build', 'copy']);
|
||||||
grunt.registerTask('release', ['clean','html2js','uglify','jshint','karma:unit','concat:index', 'recess:min', 'copy']);
|
grunt.registerTask('release', ['clean', 'html2js', 'uglify', 'jshint', 'karma:unit', 'concat:index', 'recess:min', 'copy']);
|
||||||
grunt.registerTask('test-watch', ['karma:watch']);
|
grunt.registerTask('test-watch', ['karma:watch']);
|
||||||
|
|
||||||
// Print a timestamp (useful for when watching)
|
// Print a timestamp (useful for when watching)
|
||||||
grunt.registerTask('timestamp', function() {
|
grunt.registerTask('timestamp', function () {
|
||||||
grunt.log.subhead(Date());
|
grunt.log.subhead(Date());
|
||||||
});
|
});
|
||||||
|
|
||||||
var karmaConfig = function(configFile, customOptions) {
|
var karmaConfig = function (configFile, customOptions) {
|
||||||
var options = { configFile: configFile, keepalive: true };
|
var options = {configFile: configFile, keepalive: true};
|
||||||
var travisOptions = process.env.TRAVIS && { browsers: ['Firefox'], reporters: 'dots' };
|
var travisOptions = process.env.TRAVIS && {browsers: ['Firefox'], reporters: 'dots'};
|
||||||
return grunt.util._.extend(options, customOptions, travisOptions);
|
return grunt.util._.extend(options, customOptions, travisOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,8 +31,7 @@ module.exports = function (grunt) {
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
distdir: 'dist',
|
distdir: 'dist',
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
banner:
|
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||||
'/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
|
||||||
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
|
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
|
||||||
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
|
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
|
||||||
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
|
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
|
||||||
|
@ -50,12 +49,12 @@ module.exports = function (grunt) {
|
||||||
clean: ['<%= distdir %>/*'],
|
clean: ['<%= distdir %>/*'],
|
||||||
copy: {
|
copy: {
|
||||||
assets: {
|
assets: {
|
||||||
files: [{ dest: '<%= distdir %>/assets', src : '**', expand: true, cwd: 'assets/' }]
|
files: [{dest: '<%= distdir %>/assets', src: '**', expand: true, cwd: 'assets/'}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
karma: {
|
karma: {
|
||||||
unit: { options: karmaConfig('test/unit/karma.conf.js') },
|
unit: {options: karmaConfig('test/unit/karma.conf.js')},
|
||||||
watch: { options: karmaConfig('test/unit/karma.conf.js', { singleRun:false, autoWatch: true}) }
|
watch: {options: karmaConfig('test/unit/karma.conf.js', {singleRun: false, autoWatch: true})}
|
||||||
},
|
},
|
||||||
html2js: {
|
html2js: {
|
||||||
app: {
|
app: {
|
||||||
|
@ -67,14 +66,14 @@ module.exports = function (grunt) {
|
||||||
module: '<%= pkg.name %>.templates'
|
module: '<%= pkg.name %>.templates'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
concat:{
|
concat: {
|
||||||
dist:{
|
dist: {
|
||||||
options: {
|
options: {
|
||||||
banner: "<%= banner %>",
|
banner: "<%= banner %>",
|
||||||
process: true
|
process: true
|
||||||
},
|
},
|
||||||
src:['<%= src.js %>', '<%= src.jsTpl %>'],
|
src: ['<%= src.js %>', '<%= src.jsTpl %>'],
|
||||||
dest:'<%= distdir %>/<%= pkg.name %>.js'
|
dest: '<%= distdir %>/<%= pkg.name %>.js'
|
||||||
},
|
},
|
||||||
index: {
|
index: {
|
||||||
src: ['index.html'],
|
src: ['index.html'],
|
||||||
|
@ -84,32 +83,32 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
angular: {
|
angular: {
|
||||||
src:['assets/js/angularjs/1.3.15/angular.min.js',
|
src: ['assets/js/angularjs/1.3.15/angular.min.js',
|
||||||
'assets/js/angularjs/1.3.15/angular-route.min.js',
|
'assets/js/angularjs/1.3.15/angular-route.min.js',
|
||||||
'assets/js/angularjs/1.3.15/angular-resource.min.js',
|
'assets/js/angularjs/1.3.15/angular-resource.min.js',
|
||||||
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
||||||
'assets/js/angular-oboe.min.js'],
|
'assets/js/angular-oboe.min.js'],
|
||||||
dest: '<%= distdir %>/angular.js'
|
dest: '<%= distdir %>/angular.js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
uglify: {
|
uglify: {
|
||||||
dist:{
|
dist: {
|
||||||
options: {
|
options: {
|
||||||
banner: "<%= banner %>"
|
banner: "<%= banner %>"
|
||||||
},
|
},
|
||||||
src:['<%= src.js %>' ,'<%= src.jsTpl %>'],
|
src: ['<%= src.js %>', '<%= src.jsTpl %>'],
|
||||||
dest:'<%= distdir %>/<%= pkg.name %>.js'
|
dest: '<%= distdir %>/<%= pkg.name %>.js'
|
||||||
},
|
},
|
||||||
angular: {
|
angular: {
|
||||||
src:['<%= concat.angular.src %>'],
|
src: ['<%= concat.angular.src %>'],
|
||||||
dest: '<%= distdir %>/angular.js'
|
dest: '<%= distdir %>/angular.js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recess: {
|
recess: {
|
||||||
build: {
|
build: {
|
||||||
files: {
|
files: {
|
||||||
'<%= distdir %>/<%= pkg.name %>.css':
|
'<%= distdir %>/<%= pkg.name %>.css': ['<%= src.css %>']
|
||||||
['<%= src.css %>'] },
|
},
|
||||||
options: {
|
options: {
|
||||||
compile: true,
|
compile: true,
|
||||||
noOverqualifying: false // TODO: Added because of .nav class, rename
|
noOverqualifying: false // TODO: Added because of .nav class, rename
|
||||||
|
@ -124,29 +123,29 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch:{
|
watch: {
|
||||||
all: {
|
all: {
|
||||||
files:['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl.app %>', '<%= src.tpl.common %>', '<%= src.html %>'],
|
files: ['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl.app %>', '<%= src.tpl.common %>', '<%= src.html %>'],
|
||||||
tasks:['default','timestamp']
|
tasks: ['default', 'timestamp']
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
files:['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl.app %>', '<%= src.tpl.common %>', '<%= src.html %>'],
|
files: ['<%= src.js %>', '<%= src.specs %>', '<%= src.css %>', '<%= src.tpl.app %>', '<%= src.tpl.common %>', '<%= src.html %>'],
|
||||||
tasks:['build','timestamp']
|
tasks: ['build', 'timestamp']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
jshint:{
|
jshint: {
|
||||||
files:['gruntFile.js', '<%= src.js %>', '<%= src.jsTpl %>', '<%= src.specs %>', '<%= src.scenarios %>'],
|
files: ['gruntFile.js', '<%= src.js %>', '<%= src.jsTpl %>', '<%= src.specs %>', '<%= src.scenarios %>'],
|
||||||
options:{
|
options: {
|
||||||
curly:true,
|
curly: true,
|
||||||
eqeqeq:true,
|
eqeqeq: true,
|
||||||
immed:true,
|
immed: true,
|
||||||
latedef:true,
|
latedef: true,
|
||||||
newcap:true,
|
newcap: true,
|
||||||
noarg:true,
|
noarg: true,
|
||||||
sub:true,
|
sub: true,
|
||||||
boss:true,
|
boss: true,
|
||||||
eqnull:true,
|
eqnull: true,
|
||||||
globals:{
|
globals: {
|
||||||
angular: false,
|
angular: false,
|
||||||
'$': false
|
'$': false
|
||||||
}
|
}
|
||||||
|
|
64
package.json
64
package.json
|
@ -1,35 +1,35 @@
|
||||||
{
|
{
|
||||||
"author": "Michael Crosby & Kevan Ahlquist",
|
"author": "Michael Crosby & Kevan Ahlquist",
|
||||||
"name": "dockerui",
|
"name": "dockerui",
|
||||||
"homepage": "https://github.com/crosbymichael/dockerui",
|
"homepage": "https://github.com/crosbymichael/dockerui",
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:crosbymichael/dockerui.git"
|
"url": "git@github.com:crosbymichael/dockerui.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/crosbymichael/dockerui/issues"
|
"url": "https://github.com/crosbymichael/dockerui/issues"
|
||||||
},
|
},
|
||||||
"licenses": [
|
"licenses": [
|
||||||
{
|
{
|
||||||
"type": "MIT",
|
"type": "MIT",
|
||||||
"url": "https://raw.githubusercontent.com/crosbymichael/dockerui/master/LICENSE"
|
"url": "https://raw.githubusercontent.com/crosbymichael/dockerui/master/LICENSE"
|
||||||
}
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8.4"
|
|
||||||
},
|
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
|
||||||
"grunt": "~0.4.0",
|
|
||||||
"grunt-recess": "~0.3",
|
|
||||||
"grunt-contrib-clean": "~0.4.0",
|
|
||||||
"grunt-contrib-copy": "~0.4.0",
|
|
||||||
"grunt-contrib-jshint": "~0.2.0",
|
|
||||||
"grunt-contrib-concat": "~0.1.3",
|
|
||||||
"grunt-contrib-uglify": "~0.1.1",
|
|
||||||
"grunt-karma": "~0.4.4",
|
|
||||||
"grunt-html2js": "~0.1.0",
|
|
||||||
"grunt-contrib-watch": "~0.3.1"
|
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.4"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"grunt": "~0.4.0",
|
||||||
|
"grunt-recess": "~0.3",
|
||||||
|
"grunt-contrib-clean": "~0.4.0",
|
||||||
|
"grunt-contrib-copy": "~0.4.0",
|
||||||
|
"grunt-contrib-jshint": "~0.2.0",
|
||||||
|
"grunt-contrib-concat": "~0.1.3",
|
||||||
|
"grunt-contrib-uglify": "~0.1.1",
|
||||||
|
"grunt-karma": "~0.4.4",
|
||||||
|
"grunt-html2js": "~0.1.0",
|
||||||
|
"grunt-contrib-watch": "~0.3.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
describe('startContainerController', function() {
|
describe('startContainerController', function () {
|
||||||
var scope, $location, createController, mockContainer, $httpBackend;
|
var scope, $location, createController, mockContainer, $httpBackend;
|
||||||
|
|
||||||
beforeEach(angular.mock.module('dockerui'));
|
beforeEach(angular.mock.module('dockerui'));
|
||||||
|
|
||||||
beforeEach(inject(function($rootScope, $controller, _$location_) {
|
beforeEach(inject(function ($rootScope, $controller, _$location_) {
|
||||||
$location = _$location_;
|
$location = _$location_;
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
|
|
||||||
createController = function() {
|
createController = function () {
|
||||||
return $controller('StartContainerController', {
|
return $controller('StartContainerController', {
|
||||||
'$scope': scope
|
'$scope': scope
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
angular.mock.inject(function(_Container_, _$httpBackend_) {
|
angular.mock.inject(function (_Container_, _$httpBackend_) {
|
||||||
mockContainer = _Container_;
|
mockContainer = _Container_;
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
});
|
});
|
||||||
|
@ -34,8 +34,9 @@ describe('startContainerController', function() {
|
||||||
'Status': 'Up 2 minutes'
|
'Status': 'Up 2 minutes'
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
describe('Create and start a container with port bindings', function() {
|
|
||||||
it('should issue a correct create request to the Docker remote API', function() {
|
describe('Create and start a container with port bindings', function () {
|
||||||
|
it('should issue a correct create request to the Docker remote API', function () {
|
||||||
var controller = createController();
|
var controller = createController();
|
||||||
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
||||||
var expectedBody = {
|
var expectedBody = {
|
||||||
|
@ -76,8 +77,8 @@ describe('startContainerController', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Create and start a container with environment variables', function() {
|
describe('Create and start a container with environment variables', function () {
|
||||||
it('should issue a correct create request to the Docker remote API', function() {
|
it('should issue a correct create request to the Docker remote API', function () {
|
||||||
var controller = createController();
|
var controller = createController();
|
||||||
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
||||||
var expectedBody = {
|
var expectedBody = {
|
||||||
|
@ -110,8 +111,8 @@ describe('startContainerController', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Create and start a container with volumesFrom', function() {
|
describe('Create and start a container with volumesFrom', function () {
|
||||||
it('should issue a correct create request to the Docker remote API', function() {
|
it('should issue a correct create request to the Docker remote API', function () {
|
||||||
var controller = createController();
|
var controller = createController();
|
||||||
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
||||||
var expectedBody = {
|
var expectedBody = {
|
||||||
|
@ -133,15 +134,15 @@ describe('startContainerController', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.config.name = 'container-name';
|
scope.config.name = 'container-name';
|
||||||
scope.config.HostConfig.VolumesFrom = [{name: 'parent'}, {name:'other:ro'}];
|
scope.config.HostConfig.VolumesFrom = [{name: 'parent'}, {name: 'other:ro'}];
|
||||||
|
|
||||||
scope.create();
|
scope.create();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Create and start a container with multiple options', function() {
|
describe('Create and start a container with multiple options', function () {
|
||||||
it('should issue a correct create request to the Docker remote API', function() {
|
it('should issue a correct create request to the Docker remote API', function () {
|
||||||
var controller = createController();
|
var controller = createController();
|
||||||
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
|
||||||
var expectedBody = {
|
var expectedBody = {
|
||||||
|
@ -154,8 +155,12 @@ describe('startContainerController', function() {
|
||||||
DnsSearch: ['example.com'],
|
DnsSearch: ['example.com'],
|
||||||
CapAdd: ['cap_sys_admin'],
|
CapAdd: ['cap_sys_admin'],
|
||||||
CapDrop: ['cap_foo_bar'],
|
CapDrop: ['cap_foo_bar'],
|
||||||
Devices: [{ 'PathOnHost': '/dev/deviceName', 'PathInContainer': '/dev/deviceName', 'CgroupPermissions': 'mrw'}],
|
Devices: [{
|
||||||
LxcConf: {'lxc.utsname':'docker'},
|
'PathOnHost': '/dev/deviceName',
|
||||||
|
'PathInContainer': '/dev/deviceName',
|
||||||
|
'CgroupPermissions': 'mrw'
|
||||||
|
}],
|
||||||
|
LxcConf: {'lxc.utsname': 'docker'},
|
||||||
ExtraHosts: ['hostname:127.0.0.1'],
|
ExtraHosts: ['hostname:127.0.0.1'],
|
||||||
RestartPolicy: {name: 'always', MaximumRetryCount: 5}
|
RestartPolicy: {name: 'always', MaximumRetryCount: 5}
|
||||||
},
|
},
|
||||||
|
@ -190,7 +195,11 @@ describe('startContainerController', function() {
|
||||||
scope.config.HostConfig.PublishAllPorts = true;
|
scope.config.HostConfig.PublishAllPorts = true;
|
||||||
scope.config.HostConfig.Privileged = true;
|
scope.config.HostConfig.Privileged = true;
|
||||||
scope.config.HostConfig.RestartPolicy = {name: 'always', MaximumRetryCount: 5};
|
scope.config.HostConfig.RestartPolicy = {name: 'always', MaximumRetryCount: 5};
|
||||||
scope.config.HostConfig.Devices = [{ 'PathOnHost': '/dev/deviceName', 'PathInContainer': '/dev/deviceName', 'CgroupPermissions': 'mrw'}];
|
scope.config.HostConfig.Devices = [{
|
||||||
|
'PathOnHost': '/dev/deviceName',
|
||||||
|
'PathInContainer': '/dev/deviceName',
|
||||||
|
'CgroupPermissions': 'mrw'
|
||||||
|
}];
|
||||||
scope.config.HostConfig.LxcConf = [{name: 'lxc.utsname', value: 'docker'}];
|
scope.config.HostConfig.LxcConf = [{name: 'lxc.utsname', value: 'docker'}];
|
||||||
scope.config.HostConfig.ExtraHosts = [{host: 'hostname', ip: '127.0.0.1'}];
|
scope.config.HostConfig.ExtraHosts = [{host: 'hostname', ip: '127.0.0.1'}];
|
||||||
|
|
||||||
|
|
|
@ -2,40 +2,40 @@ describe('filters', function () {
|
||||||
beforeEach(module('dockerui.filters'));
|
beforeEach(module('dockerui.filters'));
|
||||||
|
|
||||||
describe('truncate', function () {
|
describe('truncate', function () {
|
||||||
it('should truncate the string to 10 characters ending in "..." by default', inject(function(truncateFilter) {
|
it('should truncate the string to 10 characters ending in "..." by default', inject(function (truncateFilter) {
|
||||||
expect(truncateFilter('this is 20 chars long')).toBe('this is...');
|
expect(truncateFilter('this is 20 chars long')).toBe('this is...');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should truncate the string to 7 characters ending in "..."', inject(function(truncateFilter) {
|
it('should truncate the string to 7 characters ending in "..."', inject(function (truncateFilter) {
|
||||||
expect(truncateFilter('this is 20 chars long', 7)).toBe('this...');
|
expect(truncateFilter('this is 20 chars long', 7)).toBe('this...');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should truncate the string to 10 characters ending in "???"', inject(function(truncateFilter) {
|
it('should truncate the string to 10 characters ending in "???"', inject(function (truncateFilter) {
|
||||||
expect(truncateFilter('this is 20 chars long', 10, '???')).toBe('this is???');
|
expect(truncateFilter('this is 20 chars long', 10, '???')).toBe('this is???');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('statusbadge', function () {
|
describe('statusbadge', function () {
|
||||||
it('should be "important" when input is "Ghost"', inject(function(statusbadgeFilter) {
|
it('should be "important" when input is "Ghost"', inject(function (statusbadgeFilter) {
|
||||||
expect(statusbadgeFilter('Ghost')).toBe('important');
|
expect(statusbadgeFilter('Ghost')).toBe('important');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be "success" when input is "Exit 0"', inject(function(statusbadgeFilter) {
|
it('should be "success" when input is "Exit 0"', inject(function (statusbadgeFilter) {
|
||||||
expect(statusbadgeFilter('Exit 0')).toBe('success');
|
expect(statusbadgeFilter('Exit 0')).toBe('success');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be "warning" when exit code is non-zero', inject(function(statusbadgeFilter) {
|
it('should be "warning" when exit code is non-zero', inject(function (statusbadgeFilter) {
|
||||||
expect(statusbadgeFilter('Exit 1')).toBe('warning');
|
expect(statusbadgeFilter('Exit 1')).toBe('warning');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getstatetext', function () {
|
describe('getstatetext', function () {
|
||||||
|
|
||||||
it('should return an empty string when state is undefined', inject(function(getstatetextFilter) {
|
it('should return an empty string when state is undefined', inject(function (getstatetextFilter) {
|
||||||
expect(getstatetextFilter(undefined)).toBe('');
|
expect(getstatetextFilter(undefined)).toBe('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should detect a Ghost state', inject(function(getstatetextFilter) {
|
it('should detect a Ghost state', inject(function (getstatetextFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: true,
|
Ghost: true,
|
||||||
Running: true,
|
Running: true,
|
||||||
|
@ -44,7 +44,7 @@ describe('filters', function () {
|
||||||
expect(getstatetextFilter(state)).toBe('Ghost');
|
expect(getstatetextFilter(state)).toBe('Ghost');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should detect a Paused state', inject(function(getstatetextFilter) {
|
it('should detect a Paused state', inject(function (getstatetextFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: false,
|
Ghost: false,
|
||||||
Running: true,
|
Running: true,
|
||||||
|
@ -53,7 +53,7 @@ describe('filters', function () {
|
||||||
expect(getstatetextFilter(state)).toBe('Running (Paused)');
|
expect(getstatetextFilter(state)).toBe('Running (Paused)');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should detect a Running state', inject(function(getstatetextFilter) {
|
it('should detect a Running state', inject(function (getstatetextFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: false,
|
Ghost: false,
|
||||||
Running: true,
|
Running: true,
|
||||||
|
@ -62,7 +62,7 @@ describe('filters', function () {
|
||||||
expect(getstatetextFilter(state)).toBe('Running');
|
expect(getstatetextFilter(state)).toBe('Running');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should detect a Stopped state', inject(function(getstatetextFilter) {
|
it('should detect a Stopped state', inject(function (getstatetextFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: false,
|
Ghost: false,
|
||||||
Running: false,
|
Running: false,
|
||||||
|
@ -73,11 +73,11 @@ describe('filters', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getstatelabel', function () {
|
describe('getstatelabel', function () {
|
||||||
it('should return an empty string when state is undefined', inject(function(getstatelabelFilter) {
|
it('should return an empty string when state is undefined', inject(function (getstatelabelFilter) {
|
||||||
expect(getstatelabelFilter(undefined)).toBe('');
|
expect(getstatelabelFilter(undefined)).toBe('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should return label-important when a ghost state is detected', inject(function(getstatelabelFilter) {
|
it('should return label-important when a ghost state is detected', inject(function (getstatelabelFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: true,
|
Ghost: true,
|
||||||
Running: true,
|
Running: true,
|
||||||
|
@ -86,7 +86,7 @@ describe('filters', function () {
|
||||||
expect(getstatelabelFilter(state)).toBe('label-important');
|
expect(getstatelabelFilter(state)).toBe('label-important');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should return label-success when a running state is detected', inject(function(getstatelabelFilter) {
|
it('should return label-success when a running state is detected', inject(function (getstatelabelFilter) {
|
||||||
var state = {
|
var state = {
|
||||||
Ghost: false,
|
Ghost: false,
|
||||||
Running: true,
|
Running: true,
|
||||||
|
@ -97,33 +97,33 @@ describe('filters', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('humansize', function () {
|
describe('humansize', function () {
|
||||||
it('should return n/a when size is zero', inject(function(humansizeFilter) {
|
it('should return n/a when size is zero', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(0)).toBe('n/a');
|
expect(humansizeFilter(0)).toBe('n/a');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle Bytes values', inject(function(humansizeFilter) {
|
it('should handle Bytes values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(512)).toBe('512 Bytes');
|
expect(humansizeFilter(512)).toBe('512 Bytes');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle KB values', inject(function(humansizeFilter) {
|
it('should handle KB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5120)).toBe('5 KB');
|
expect(humansizeFilter(5120)).toBe('5 KB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle MB values', inject(function(humansizeFilter) {
|
it('should handle MB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 6))).toBe('5 MB');
|
expect(humansizeFilter(5 * Math.pow(10, 6))).toBe('5 MB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle GB values', inject(function(humansizeFilter) {
|
it('should handle GB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 9))).toBe('5 GB');
|
expect(humansizeFilter(5 * Math.pow(10, 9))).toBe('5 GB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle TB values', inject(function(humansizeFilter) {
|
it('should handle TB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 12))).toBe('5 TB');
|
expect(humansizeFilter(5 * Math.pow(10, 12))).toBe('5 TB');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('containername', function () {
|
describe('containername', function () {
|
||||||
it('should strip the leading slash from container name', inject(function(containernameFilter) {
|
it('should strip the leading slash from container name', inject(function (containernameFilter) {
|
||||||
var container = {
|
var container = {
|
||||||
Names: ['/elegant_ardinghelli']
|
Names: ['/elegant_ardinghelli']
|
||||||
};
|
};
|
||||||
|
@ -133,14 +133,14 @@ describe('filters', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('repotag', function () {
|
describe('repotag', function () {
|
||||||
it('should not display empty repo tag', inject(function(repotagFilter) {
|
it('should not display empty repo tag', inject(function (repotagFilter) {
|
||||||
var image = {
|
var image = {
|
||||||
RepoTags: ['<none>:<none>']
|
RepoTags: ['<none>:<none>']
|
||||||
};
|
};
|
||||||
expect(repotagFilter(image)).toBe('');
|
expect(repotagFilter(image)).toBe('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display a normal repo tag', inject(function(repotagFilter) {
|
it('should display a normal repo tag', inject(function (repotagFilter) {
|
||||||
var image = {
|
var image = {
|
||||||
RepoTags: ['ubuntu:latest']
|
RepoTags: ['ubuntu:latest']
|
||||||
};
|
};
|
||||||
|
@ -149,17 +149,207 @@ describe('filters', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getdate', function () {
|
describe('getdate', function () {
|
||||||
it('should convert the Docker date to a human readable form', inject(function(getdateFilter) {
|
it('should convert the Docker date to a human readable form', inject(function (getdateFilter) {
|
||||||
expect(getdateFilter(1420424998)).toBe('Sun Jan 04 2015');
|
expect(getdateFilter(1420424998)).toBe('Sun Jan 04 2015');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('errorMsgFilter', function() {
|
describe('errorMsgFilter', function () {
|
||||||
it('should convert the $resource object to a string message',
|
it('should convert the $resource object to a string message',
|
||||||
inject(function(errorMsgFilter) {
|
inject(function (errorMsgFilter) {
|
||||||
var response = {'0':'C','1':'o','2':'n','3':'f','4':'l','5':'i','6':'c','7':'t','8':',','9':' ','10':'T','11':'h','12':'e','13':' ','14':'n','15':'a','16':'m','17':'e','18':' ','19':'u','20':'b','21':'u','22':'n','23':'t','24':'u','25':'-','26':'s','27':'l','28':'e','29':'e','30':'p','31':'-','32':'r','33':'u','34':'n','35':'t','36':'i','37':'m','38':'e','39':' ','40':'i','41':'s','42':' ','43':'a','44':'l','45':'r','46':'e','47':'a','48':'d','49':'y','50':' ','51':'a','52':'s','53':'s','54':'i','55':'g','56':'n','57':'e','58':'d','59':' ','60':'t','61':'o','62':' ','63':'b','64':'6','65':'9','66':'e','67':'5','68':'3','69':'a','70':'6','71':'2','72':'2','73':'c','74':'8','75':'.','76':' ','77':'Y','78':'o','79':'u','80':' ','81':'h','82':'a','83':'v','84':'e','85':' ','86':'t','87':'o','88':' ','89':'d','90':'e','91':'l','92':'e','93':'t','94':'e','95':' ','96':'(','97':'o','98':'r','99':' ','100':'r','101':'e','102':'n','103':'a','104':'m','105':'e','106':')','107':' ','108':'t','109':'h','110':'a','111':'t','112':' ','113':'c','114':'o','115':'n','116':'t','117':'a','118':'i','119':'n','120':'e','121':'r','122':' ','123':'t','124':'o','125':' ','126':'b','127':'e','128':' ','129':'a','130':'b','131':'l','132':'e','133':' ','134':'t','135':'o','136':' ','137':'a','138':'s','139':'s','140':'i','141':'g','142':'n','143':' ','144':'u','145':'b','146':'u','147':'n','148':'t','149':'u','150':'-','151':'s','152':'l','153':'e','154':'e','155':'p','156':'-','157':'r','158':'u','159':'n','160':'t','161':'i','162':'m','163':'e','164':' ','165':'t','166':'o','167':' ','168':'a','169':' ','170':'c','171':'o','172':'n','173':'t','174':'a','175':'i','176':'n','177':'e','178':'r','179':' ','180':'a','181':'g','182':'a','183':'i','184':'n','185':'.','186':'\n','$promise':{},'$resolved':true};
|
var response = {
|
||||||
|
'0': 'C',
|
||||||
|
'1': 'o',
|
||||||
|
'2': 'n',
|
||||||
|
'3': 'f',
|
||||||
|
'4': 'l',
|
||||||
|
'5': 'i',
|
||||||
|
'6': 'c',
|
||||||
|
'7': 't',
|
||||||
|
'8': ',',
|
||||||
|
'9': ' ',
|
||||||
|
'10': 'T',
|
||||||
|
'11': 'h',
|
||||||
|
'12': 'e',
|
||||||
|
'13': ' ',
|
||||||
|
'14': 'n',
|
||||||
|
'15': 'a',
|
||||||
|
'16': 'm',
|
||||||
|
'17': 'e',
|
||||||
|
'18': ' ',
|
||||||
|
'19': 'u',
|
||||||
|
'20': 'b',
|
||||||
|
'21': 'u',
|
||||||
|
'22': 'n',
|
||||||
|
'23': 't',
|
||||||
|
'24': 'u',
|
||||||
|
'25': '-',
|
||||||
|
'26': 's',
|
||||||
|
'27': 'l',
|
||||||
|
'28': 'e',
|
||||||
|
'29': 'e',
|
||||||
|
'30': 'p',
|
||||||
|
'31': '-',
|
||||||
|
'32': 'r',
|
||||||
|
'33': 'u',
|
||||||
|
'34': 'n',
|
||||||
|
'35': 't',
|
||||||
|
'36': 'i',
|
||||||
|
'37': 'm',
|
||||||
|
'38': 'e',
|
||||||
|
'39': ' ',
|
||||||
|
'40': 'i',
|
||||||
|
'41': 's',
|
||||||
|
'42': ' ',
|
||||||
|
'43': 'a',
|
||||||
|
'44': 'l',
|
||||||
|
'45': 'r',
|
||||||
|
'46': 'e',
|
||||||
|
'47': 'a',
|
||||||
|
'48': 'd',
|
||||||
|
'49': 'y',
|
||||||
|
'50': ' ',
|
||||||
|
'51': 'a',
|
||||||
|
'52': 's',
|
||||||
|
'53': 's',
|
||||||
|
'54': 'i',
|
||||||
|
'55': 'g',
|
||||||
|
'56': 'n',
|
||||||
|
'57': 'e',
|
||||||
|
'58': 'd',
|
||||||
|
'59': ' ',
|
||||||
|
'60': 't',
|
||||||
|
'61': 'o',
|
||||||
|
'62': ' ',
|
||||||
|
'63': 'b',
|
||||||
|
'64': '6',
|
||||||
|
'65': '9',
|
||||||
|
'66': 'e',
|
||||||
|
'67': '5',
|
||||||
|
'68': '3',
|
||||||
|
'69': 'a',
|
||||||
|
'70': '6',
|
||||||
|
'71': '2',
|
||||||
|
'72': '2',
|
||||||
|
'73': 'c',
|
||||||
|
'74': '8',
|
||||||
|
'75': '.',
|
||||||
|
'76': ' ',
|
||||||
|
'77': 'Y',
|
||||||
|
'78': 'o',
|
||||||
|
'79': 'u',
|
||||||
|
'80': ' ',
|
||||||
|
'81': 'h',
|
||||||
|
'82': 'a',
|
||||||
|
'83': 'v',
|
||||||
|
'84': 'e',
|
||||||
|
'85': ' ',
|
||||||
|
'86': 't',
|
||||||
|
'87': 'o',
|
||||||
|
'88': ' ',
|
||||||
|
'89': 'd',
|
||||||
|
'90': 'e',
|
||||||
|
'91': 'l',
|
||||||
|
'92': 'e',
|
||||||
|
'93': 't',
|
||||||
|
'94': 'e',
|
||||||
|
'95': ' ',
|
||||||
|
'96': '(',
|
||||||
|
'97': 'o',
|
||||||
|
'98': 'r',
|
||||||
|
'99': ' ',
|
||||||
|
'100': 'r',
|
||||||
|
'101': 'e',
|
||||||
|
'102': 'n',
|
||||||
|
'103': 'a',
|
||||||
|
'104': 'm',
|
||||||
|
'105': 'e',
|
||||||
|
'106': ')',
|
||||||
|
'107': ' ',
|
||||||
|
'108': 't',
|
||||||
|
'109': 'h',
|
||||||
|
'110': 'a',
|
||||||
|
'111': 't',
|
||||||
|
'112': ' ',
|
||||||
|
'113': 'c',
|
||||||
|
'114': 'o',
|
||||||
|
'115': 'n',
|
||||||
|
'116': 't',
|
||||||
|
'117': 'a',
|
||||||
|
'118': 'i',
|
||||||
|
'119': 'n',
|
||||||
|
'120': 'e',
|
||||||
|
'121': 'r',
|
||||||
|
'122': ' ',
|
||||||
|
'123': 't',
|
||||||
|
'124': 'o',
|
||||||
|
'125': ' ',
|
||||||
|
'126': 'b',
|
||||||
|
'127': 'e',
|
||||||
|
'128': ' ',
|
||||||
|
'129': 'a',
|
||||||
|
'130': 'b',
|
||||||
|
'131': 'l',
|
||||||
|
'132': 'e',
|
||||||
|
'133': ' ',
|
||||||
|
'134': 't',
|
||||||
|
'135': 'o',
|
||||||
|
'136': ' ',
|
||||||
|
'137': 'a',
|
||||||
|
'138': 's',
|
||||||
|
'139': 's',
|
||||||
|
'140': 'i',
|
||||||
|
'141': 'g',
|
||||||
|
'142': 'n',
|
||||||
|
'143': ' ',
|
||||||
|
'144': 'u',
|
||||||
|
'145': 'b',
|
||||||
|
'146': 'u',
|
||||||
|
'147': 'n',
|
||||||
|
'148': 't',
|
||||||
|
'149': 'u',
|
||||||
|
'150': '-',
|
||||||
|
'151': 's',
|
||||||
|
'152': 'l',
|
||||||
|
'153': 'e',
|
||||||
|
'154': 'e',
|
||||||
|
'155': 'p',
|
||||||
|
'156': '-',
|
||||||
|
'157': 'r',
|
||||||
|
'158': 'u',
|
||||||
|
'159': 'n',
|
||||||
|
'160': 't',
|
||||||
|
'161': 'i',
|
||||||
|
'162': 'm',
|
||||||
|
'163': 'e',
|
||||||
|
'164': ' ',
|
||||||
|
'165': 't',
|
||||||
|
'166': 'o',
|
||||||
|
'167': ' ',
|
||||||
|
'168': 'a',
|
||||||
|
'169': ' ',
|
||||||
|
'170': 'c',
|
||||||
|
'171': 'o',
|
||||||
|
'172': 'n',
|
||||||
|
'173': 't',
|
||||||
|
'174': 'a',
|
||||||
|
'175': 'i',
|
||||||
|
'176': 'n',
|
||||||
|
'177': 'e',
|
||||||
|
'178': 'r',
|
||||||
|
'179': ' ',
|
||||||
|
'180': 'a',
|
||||||
|
'181': 'g',
|
||||||
|
'182': 'a',
|
||||||
|
'183': 'i',
|
||||||
|
'184': 'n',
|
||||||
|
'185': '.',
|
||||||
|
'186': '\n',
|
||||||
|
'$promise': {},
|
||||||
|
'$resolved': true
|
||||||
|
};
|
||||||
var message = 'Conflict, The name ubuntu-sleep-runtime is already assigned to b69e53a622c8. You have to delete (or rename) that container to be able to assign ubuntu-sleep-runtime to a container again.\n';
|
var message = 'Conflict, The name ubuntu-sleep-runtime is already assigned to b69e53a622c8. You have to delete (or rename) that container to be able to assign ubuntu-sleep-runtime to a container again.\n';
|
||||||
expect(errorMsgFilter(response)).toBe(message);
|
expect(errorMsgFilter(response)).toBe(message);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -3,19 +3,19 @@ basePath = '../..';
|
||||||
|
|
||||||
// list of files / patterns to load in the browser
|
// list of files / patterns to load in the browser
|
||||||
files = [
|
files = [
|
||||||
JASMINE,
|
JASMINE,
|
||||||
JASMINE_ADAPTER,
|
JASMINE_ADAPTER,
|
||||||
'assets/js/jquery-1.11.1.min.js',
|
'assets/js/jquery-1.11.1.min.js',
|
||||||
'assets/js/jquery.gritter.min.js',
|
'assets/js/jquery.gritter.min.js',
|
||||||
'assets/js/bootstrap.min.js',
|
'assets/js/bootstrap.min.js',
|
||||||
'assets/js/spin.js',
|
'assets/js/spin.js',
|
||||||
'dist/angular.js',
|
'dist/angular.js',
|
||||||
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
||||||
'assets/js/angular-vis.js',
|
'assets/js/angular-vis.js',
|
||||||
'test/assets/angular/angular-mocks.js',
|
'test/assets/angular/angular-mocks.js',
|
||||||
'app/**/*.js',
|
'app/**/*.js',
|
||||||
'test/unit/**/*.spec.js',
|
'test/unit/**/*.spec.js',
|
||||||
'dist/templates/**/*.js'
|
'dist/templates/**/*.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
// use dots reporter, as travis terminal does not support escaping sequences
|
// use dots reporter, as travis terminal does not support escaping sequences
|
||||||
|
|
Loading…
Reference in New Issue