mirror of https://github.com/portainer/portainer
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1864 lines
86 KiB
1864 lines
86 KiB
/*! dockerui - v0.6.0 - 2015-02-09
|
|
* https://github.com/crosbymichael/dockerui
|
|
* Copyright (c) 2015 Michael Crosby & Kevan Ahlquist;
|
|
* Licensed MIT
|
|
*/
|
|
angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services', 'dockerui.filters', 'masthead', 'footer', 'dashboard', 'container', 'containers', 'images', 'image', 'startContainer', 'sidebar', 'settings', 'builder', 'containerLogs'])
|
|
.config(['$routeProvider', function ($routeProvider) {
|
|
'use strict';
|
|
$routeProvider.when('/', {templateUrl: 'app/components/dashboard/dashboard.html', controller: 'DashboardController'});
|
|
$routeProvider.when('/containers/', {templateUrl: 'app/components/containers/containers.html', controller: 'ContainersController'});
|
|
$routeProvider.when('/containers/:id/', {templateUrl: 'app/components/container/container.html', controller: 'ContainerController'});
|
|
$routeProvider.when('/containers/:id/logs/', {templateUrl: 'app/components/containerLogs/containerlogs.html', controller: 'ContainerLogsController'});
|
|
$routeProvider.when('/images/', {templateUrl: 'app/components/images/images.html', controller: 'ImagesController'});
|
|
$routeProvider.when('/images/:id/', {templateUrl: 'app/components/image/image.html', controller: 'ImageController'});
|
|
$routeProvider.when('/settings', {templateUrl: 'app/components/settings/settings.html', controller: 'SettingsController'});
|
|
$routeProvider.otherwise({redirectTo: '/'});
|
|
}])
|
|
// This is your docker url that the api will use to make requests
|
|
// You need to set this to the api endpoint without the port i.e. http://192.168.1.9
|
|
.constant('DOCKER_ENDPOINT', 'dockerapi')
|
|
.constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is requred. If you have a port, prefix it with a ':' i.e. :4243
|
|
.constant('UI_VERSION', 'v0.6.0')
|
|
.constant('DOCKER_API_VERSION', 'v1.16');
|
|
|
|
angular.module('builder', [])
|
|
.controller('BuilderController', ['$scope', 'Dockerfile', 'Messages',
|
|
function($scope, Dockerfile, Messages) {
|
|
$scope.template = 'app/components/builder/builder.html';
|
|
}]);
|
|
|
|
angular.module('container', [])
|
|
.controller('ContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'ViewSpinner',
|
|
function($scope, $routeParams, $location, Container, Messages, ViewSpinner) {
|
|
$scope.changes = [];
|
|
|
|
var update = function() {
|
|
ViewSpinner.spin();
|
|
Container.get({id: $routeParams.id}, function(d) {
|
|
$scope.container = d;
|
|
ViewSpinner.stop();
|
|
}, function(e) {
|
|
if (e.status === 404) {
|
|
$('.detail').hide();
|
|
Messages.error("Not found", "Container not found.");
|
|
} else {
|
|
Messages.error("Failure", e.data);
|
|
}
|
|
ViewSpinner.stop();
|
|
});
|
|
};
|
|
|
|
$scope.start = function(){
|
|
ViewSpinner.spin();
|
|
Container.start({
|
|
id: $scope.container.Id,
|
|
HostConfig: $scope.container.HostConfig
|
|
}, function(d) {
|
|
update();
|
|
Messages.send("Container started", $routeParams.id);
|
|
}, function(e) {
|
|
update();
|
|
Messages.error("Failure", "Container failed to start." + e.data);
|
|
});
|
|
};
|
|
|
|
$scope.stop = function() {
|
|
ViewSpinner.spin();
|
|
Container.stop({id: $routeParams.id}, function(d) {
|
|
update();
|
|
Messages.send("Container stopped", $routeParams.id);
|
|
}, function(e) {
|
|
update();
|
|
Messages.error("Failure", "Container failed to stop." + e.data);
|
|
});
|
|
};
|
|
|
|
$scope.kill = function() {
|
|
ViewSpinner.spin();
|
|
Container.kill({id: $routeParams.id}, function(d) {
|
|
update();
|
|
Messages.send("Container killed", $routeParams.id);
|
|
}, function(e) {
|
|
update();
|
|
Messages.error("Failure", "Container failed to die." + e.data);
|
|
});
|
|
};
|
|
|
|
$scope.pause = function() {
|
|
ViewSpinner.spin();
|
|
Container.pause({id: $routeParams.id}, function(d) {
|
|
update();
|
|
Messages.send("Container paused", $routeParams.id);
|
|
}, function(e) {
|
|
update();
|
|
Messages.error("Failure", "Container failed to pause." + e.data);
|
|
});
|
|
};
|
|
|
|
$scope.unpause = function() {
|
|
ViewSpinner.spin();
|
|
Container.unpause({id: $routeParams.id}, function(d) {
|
|
update();
|
|
Messages.send("Container unpaused", $routeParams.id);
|
|
}, function(e) {
|
|
update();
|
|
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.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();
|
|
});
|
|
};
|
|
|
|
update();
|
|
$scope.getChanges();
|
|
}]);
|
|
|
|
angular.module('containerLogs', [])
|
|
.controller('ContainerLogsController', ['$scope', '$routeParams', '$location', '$anchorScroll', 'ContainerLogs', 'Container', 'ViewSpinner',
|
|
function($scope, $routeParams, $location, $anchorScroll, ContainerLogs, Container, ViewSpinner) {
|
|
$scope.stdout = '';
|
|
$scope.stderr = '';
|
|
$scope.showTimestamps = false;
|
|
|
|
ViewSpinner.spin();
|
|
Container.get({id: $routeParams.id}, function(d) {
|
|
$scope.container = d;
|
|
ViewSpinner.stop();
|
|
}, function(e) {
|
|
if (e.status === 404) {
|
|
Messages.error("Not found", "Container not found.");
|
|
} else {
|
|
Messages.error("Failure", e.data);
|
|
}
|
|
ViewSpinner.stop();
|
|
});
|
|
|
|
function getLogs() {
|
|
ContainerLogs.get($routeParams.id, {stdout: 1, stderr: 0, timestamps: $scope.showTimestamps}, function(data, status, headers, config) {
|
|
// Replace carriage returns twith newlines to clean up output
|
|
$scope.stdout = data.replace(/[\r]/g, '\n');
|
|
});
|
|
ContainerLogs.get($routeParams.id, {stdout: 0, stderr: 1}, function(data, status, headers, config) {
|
|
$scope.stderr = data.replace(/[\r]/g, '\n');
|
|
});
|
|
}
|
|
|
|
// initial call
|
|
getLogs();
|
|
var logIntervalId = window.setInterval(getLogs, 5000);
|
|
|
|
$scope.$on("$destroy", function(){
|
|
// clearing interval when view changes
|
|
clearInterval(logIntervalId);
|
|
});
|
|
|
|
$scope.scrollTo = function(id) {
|
|
$location.hash(id);
|
|
$anchorScroll();
|
|
};
|
|
|
|
$scope.toggleTimestamps = function() {
|
|
getLogs();
|
|
};
|
|
}]);
|
|
|
|
angular.module('containers', [])
|
|
.controller('ContainersController', ['$scope', 'Container', 'Settings', 'Messages', 'ViewSpinner',
|
|
function($scope, Container, Settings, Messages, ViewSpinner) {
|
|
$scope.predicate = '-Created';
|
|
$scope.toggle = false;
|
|
$scope.displayAll = Settings.displayAll;
|
|
|
|
var update = function(data) {
|
|
ViewSpinner.spin();
|
|
Container.query(data, function(d) {
|
|
$scope.containers = d.map(function(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) {
|
|
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();
|
|
}
|
|
};
|
|
|
|
$scope.toggleSelectAll = function() {
|
|
angular.forEach($scope.containers, function(i) {
|
|
i.Checked = $scope.toggle;
|
|
});
|
|
};
|
|
|
|
$scope.toggleGetAll = function() {
|
|
Settings.displayAll = $scope.displayAll;
|
|
update({all: Settings.displayAll ? 1 : 0});
|
|
};
|
|
|
|
$scope.startAction = function() {
|
|
batch($scope.containers, Container.start, "Started");
|
|
};
|
|
|
|
$scope.stopAction = function() {
|
|
batch($scope.containers, Container.stop, "Stopped");
|
|
};
|
|
|
|
$scope.killAction = function() {
|
|
batch($scope.containers, Container.kill, "Killed");
|
|
};
|
|
|
|
$scope.pauseAction = function() {
|
|
batch($scope.containers, Container.pause, "Paused");
|
|
};
|
|
|
|
$scope.unpauseAction = function() {
|
|
batch($scope.containers, Container.unpause, "Unpaused");
|
|
};
|
|
|
|
$scope.removeAction = function() {
|
|
batch($scope.containers, Container.remove, "Removed");
|
|
};
|
|
|
|
update({all: Settings.displayAll ? 1 : 0});
|
|
}]);
|
|
|
|
angular.module('dashboard', [])
|
|
.controller('DashboardController', ['$scope', 'Container', 'Image', 'Settings', 'LineChart', function($scope, Container, Image, Settings, LineChart) {
|
|
$scope.predicate = '-Created';
|
|
$scope.containers = [];
|
|
|
|
var getStarted = function(data) {
|
|
$scope.totalContainers = data.length;
|
|
LineChart.build('#containers-started-chart', data, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
|
var s = $scope;
|
|
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);
|
|
});
|
|
}]);
|
|
|
|
angular.module('footer', [])
|
|
.controller('FooterController', ['$scope', 'Settings', function($scope, Settings) {
|
|
$scope.template = 'app/components/footer/statusbar.html';
|
|
|
|
$scope.uiVersion = Settings.uiVersion;
|
|
$scope.apiVersion = Settings.version;
|
|
}]);
|
|
|
|
angular.module('image', [])
|
|
.controller('ImageController', ['$scope', '$q', '$routeParams', '$location', 'Image', 'Container', 'Messages', 'LineChart',
|
|
function($scope, $q, $routeParams, $location, Image, Container, Messages, LineChart) {
|
|
$scope.history = [];
|
|
$scope.tag = {repo: '', force: false};
|
|
|
|
$scope.remove = function() {
|
|
Image.remove({id: $routeParams.id}, function(d) {
|
|
Messages.send("Image Removed", $routeParams.id);
|
|
}, function(e) {
|
|
$scope.error = e.data;
|
|
$('#error-message').show();
|
|
});
|
|
};
|
|
|
|
$scope.getHistory = function() {
|
|
Image.history({id: $routeParams.id}, function(d) {
|
|
$scope.history = d;
|
|
});
|
|
};
|
|
|
|
$scope.updateTag = function() {
|
|
var tag = $scope.tag;
|
|
Image.tag({id: $routeParams.id, repo: tag.repo, force: tag.force ? 1 : 0}, function(d) {
|
|
Messages.send("Tag Added", $routeParams.id);
|
|
}, function(e) {
|
|
$scope.error = e.data;
|
|
$('#error-message').show();
|
|
});
|
|
};
|
|
|
|
function getContainersFromImage($q, Container, tag) {
|
|
var defer = $q.defer();
|
|
|
|
Container.query({all:1, notruc:1}, function(d) {
|
|
var containers = [];
|
|
for (var i = 0; i < d.length; i++) {
|
|
var c = d[i];
|
|
if (c.Image === tag) {
|
|
containers.push(new ContainerViewModel(c));
|
|
}
|
|
}
|
|
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);
|
|
|
|
promise.then(function(containers) {
|
|
LineChart.build('#containers-started-chart', containers, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
|
});
|
|
}
|
|
}, 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();
|
|
}]);
|
|
|
|
angular.module('images', [])
|
|
.controller('ImagesController', ['$scope', 'Image', 'ViewSpinner', 'Messages',
|
|
function($scope, Image, ViewSpinner, Messages) {
|
|
$scope.toggle = false;
|
|
$scope.predicate = '-Created';
|
|
|
|
$scope.showBuilder = function() {
|
|
$('#build-modal').modal('show');
|
|
};
|
|
|
|
$scope.removeAction = function() {
|
|
ViewSpinner.spin();
|
|
var counter = 0;
|
|
var complete = function() {
|
|
counter = counter - 1;
|
|
if (counter === 0) {
|
|
ViewSpinner.stop();
|
|
}
|
|
};
|
|
angular.forEach($scope.images, function(i) {
|
|
if (i.Checked) {
|
|
counter = counter + 1;
|
|
Image.remove({id: i.Id}, function(d) {
|
|
angular.forEach(d, function(resource) {
|
|
Messages.send("Image deleted", resource.Deleted);
|
|
});
|
|
var index = $scope.images.indexOf(i);
|
|
$scope.images.splice(index, 1);
|
|
complete();
|
|
}, function(e) {
|
|
Messages.error("Failure", e.data);
|
|
complete();
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
$scope.toggleSelectAll = function() {
|
|
angular.forEach($scope.images, function(i) {
|
|
i.Checked = $scope.toggle;
|
|
});
|
|
};
|
|
|
|
ViewSpinner.spin();
|
|
Image.query({}, function(d) {
|
|
$scope.images = d.map(function(item) { return new ImageViewModel(item); });
|
|
ViewSpinner.stop();
|
|
}, function (e) {
|
|
Messages.error("Failure", e.data);
|
|
ViewSpinner.stop();
|
|
});
|
|
}]);
|
|
|
|
angular.module('masthead', [])
|
|
.controller('MastheadController', ['$scope', function($scope) {
|
|
$scope.template = 'app/components/masthead/masthead.html';
|
|
}]);
|
|
|
|
angular.module('settings', [])
|
|
.controller('SettingsController', ['$scope', 'System', 'Docker', 'Settings', 'Messages',
|
|
function($scope, System, Docker, Settings, Messages) {
|
|
$scope.info = {};
|
|
$scope.docker = {};
|
|
$scope.endpoint = Settings.endpoint;
|
|
$scope.apiVersion = Settings.version;
|
|
|
|
Docker.get({}, function(d) { $scope.docker = d; });
|
|
System.get({}, function(d) { $scope.info = d; });
|
|
}]);
|
|
|
|
angular.module('sidebar', [])
|
|
.controller('SideBarController', ['$scope', 'Container', 'Settings',
|
|
function($scope, Container, Settings) {
|
|
$scope.template = 'partials/sidebar.html';
|
|
$scope.containers = [];
|
|
$scope.endpoint = Settings.endpoint;
|
|
|
|
Container.query({all: 0}, function(d) {
|
|
$scope.containers = d;
|
|
});
|
|
}]);
|
|
|
|
angular.module('startContainer', ['ui.bootstrap'])
|
|
.controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter', 'errorMsgFilter',
|
|
function($scope, $routeParams, $location, Container, Messages, containernameFilter, errorMsgFilter) {
|
|
$scope.template = 'app/components/startContainer/startcontainer.html';
|
|
|
|
Container.query({all: 1}, function(d) {
|
|
$scope.containerNames = d.map(function(container){
|
|
return containernameFilter(container);
|
|
});
|
|
});
|
|
|
|
$scope.config = {
|
|
Env: [],
|
|
Volumes: [],
|
|
SecurityOpts: [],
|
|
HostConfig: {
|
|
PortBindings: [],
|
|
Binds: [],
|
|
Links: [],
|
|
Dns: [],
|
|
DnsSearch: [],
|
|
VolumesFrom: [],
|
|
CapAdd: [],
|
|
CapDrop: [],
|
|
Devices: [],
|
|
LxcConf: [],
|
|
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";
|
|
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);
|
|
};
|
|
}]);
|
|
|
|
angular.module('dockerui.filters', [])
|
|
.filter('truncate', function() {
|
|
'use strict';
|
|
return function(text, length, end) {
|
|
if (isNaN(length)) {
|
|
length = 10;
|
|
}
|
|
|
|
if (end === undefined){
|
|
end = '...';
|
|
}
|
|
|
|
if (text.length <= length || text.length - end.length <= length) {
|
|
return text;
|
|
}
|
|
else {
|
|
return String(text).substring(0, length - end.length) + end;
|
|
}
|
|
};
|
|
})
|
|
.filter('statusbadge', function() {
|
|
'use strict';
|
|
return function(text) {
|
|
if (text === 'Ghost') {
|
|
return 'important';
|
|
} else if (text.indexOf('Exit') !== -1 && text !== 'Exit 0') {
|
|
return 'warning';
|
|
}
|
|
return 'success';
|
|
};
|
|
})
|
|
.filter('getstatetext', function() {
|
|
'use strict';
|
|
return function(state) {
|
|
if (state === undefined) {
|
|
return '';
|
|
}
|
|
if (state.Ghost && state.Running) {
|
|
return 'Ghost';
|
|
}
|
|
if (state.Running && state.Paused) {
|
|
return 'Running (Paused)';
|
|
}
|
|
if (state.Running) {
|
|
return 'Running';
|
|
}
|
|
return 'Stopped';
|
|
};
|
|
})
|
|
.filter('getstatelabel', function() {
|
|
'use strict';
|
|
return function(state) {
|
|
if (state === undefined) {
|
|
return '';
|
|
}
|
|
|
|
if (state.Ghost && state.Running) {
|
|
return 'label-important';
|
|
}
|
|
if (state.Running) {
|
|
return 'label-success';
|
|
}
|
|
return '';
|
|
};
|
|
})
|
|
.filter('humansize', function() {
|
|
'use strict';
|
|
return function(bytes) {
|
|
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
if (bytes === 0) {
|
|
return 'n/a';
|
|
}
|
|
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
|
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[[i]];
|
|
};
|
|
})
|
|
.filter('containername', function() {
|
|
'use strict';
|
|
return function(container) {
|
|
var name = container.Names[0];
|
|
return name.substring(1, name.length);
|
|
};
|
|
})
|
|
.filter('repotag', function() {
|
|
'use strict';
|
|
return function(image) {
|
|
if (image.RepoTags && image.RepoTags.length > 0) {
|
|
var tag = image.RepoTags[0];
|
|
if (tag === '<none>:<none>') { tag = ''; }
|
|
return tag;
|
|
}
|
|
return '';
|
|
};
|
|
})
|
|
.filter('getdate', function() {
|
|
'use strict';
|
|
return function(data) {
|
|
//Multiply by 1000 for the unix format
|
|
var date = new Date(data * 1000);
|
|
return date.toDateString();
|
|
};
|
|
})
|
|
.filter('errorMsg', function() {
|
|
return function(object) {
|
|
var idx = 0;
|
|
var msg = '';
|
|
while (object[idx] && typeof(object[idx]) === 'string') {
|
|
msg += object[idx];
|
|
idx++;
|
|
}
|
|
return msg;
|
|
};
|
|
});
|
|
|
|
angular.module('dockerui.services', ['ngResource'])
|
|
.factory('Container', function($resource, Settings) {
|
|
'use strict';
|
|
// Resource for interacting with the docker containers
|
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#containers
|
|
return $resource(Settings.url + '/containers/:id/:action', {
|
|
name: '@name'
|
|
}, {
|
|
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
|
get: {method: 'GET', params: { action:'json'}},
|
|
start: {method: 'POST', params: {id: '@id', action: 'start'}},
|
|
stop: {method: 'POST', params: {id: '@id', t: 5, action: 'stop'}},
|
|
restart: {method: 'POST', params: {id: '@id', t: 5, action: 'restart' }},
|
|
kill: {method: 'POST', params: {id: '@id', action: 'kill'}},
|
|
pause: {method: 'POST', params: {id: '@id', action: 'pause'}},
|
|
unpause: {method: 'POST', params: {id: '@id', action: 'unpause'}},
|
|
changes: {method: 'GET', params: {action:'changes'}, isArray: true},
|
|
create: {method: 'POST', params: {action:'create'}},
|
|
remove: {method: 'DELETE', params: {id: '@id', v:0}}
|
|
});
|
|
})
|
|
.factory('ContainerLogs', function($resource, $http, Settings) {
|
|
'use strict';
|
|
return {
|
|
get: function(id, params, callback) {
|
|
$http({
|
|
method: 'GET',
|
|
url: Settings.url + '/containers/'+id+'/logs',
|
|
params: {'stdout': params.stdout || 0, 'stderr': params.stderr || 0, 'timestamps': params.timestamps || 0, 'tail': params.tail || 'all'}
|
|
}).success(callback).error(function(data, status, headers, config) {
|
|
console.log(error, data);
|
|
});
|
|
}
|
|
};
|
|
})
|
|
.factory('Image', function($resource, Settings) {
|
|
'use strict';
|
|
// Resource for docker images
|
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#images
|
|
return $resource(Settings.url + '/images/:id/:action', {}, {
|
|
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
|
get: {method: 'GET', params: { action:'json'}},
|
|
search: {method: 'GET', params: { action:'search'}},
|
|
history: {method: 'GET', params: { action:'history'}, isArray: true},
|
|
create: {method: 'POST', params: {action:'create'}},
|
|
insert: {method: 'POST', params: {id: '@id', action:'insert'}},
|
|
push: {method: 'POST', params: {id: '@id', action:'push'}},
|
|
tag: {method: 'POST', params: {id: '@id', action:'tag', force: 0, repo: '@repo'}},
|
|
remove: {method: 'DELETE', params: {id: '@id'}, isArray: true}
|
|
});
|
|
})
|
|
.factory('Docker', function($resource, Settings) {
|
|
'use strict';
|
|
// Information for docker
|
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#display-system-wide-information
|
|
return $resource(Settings.url + '/version', {}, {
|
|
get: {method: 'GET'}
|
|
});
|
|
})
|
|
.factory('Auth', function($resource, Settings) {
|
|
'use strict';
|
|
// Auto Information for docker
|
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#set-auth-configuration
|
|
return $resource(Settings.url + '/auth', {}, {
|
|
get: {method: 'GET'},
|
|
update: {method: 'POST'}
|
|
});
|
|
})
|
|
.factory('System', function($resource, Settings) {
|
|
'use strict';
|
|
// System for docker
|
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#display-system-wide-information
|
|
return $resource(Settings.url + '/info', {}, {
|
|
get: {method: 'GET'}
|
|
});
|
|
})
|
|
.factory('Settings', function(DOCKER_ENDPOINT, DOCKER_PORT, DOCKER_API_VERSION, UI_VERSION) {
|
|
'use strict';
|
|
var url = DOCKER_ENDPOINT;
|
|
if (DOCKER_PORT) {
|
|
url = url + DOCKER_PORT + '\\' + DOCKER_PORT;
|
|
}
|
|
return {
|
|
displayAll: false,
|
|
endpoint: DOCKER_ENDPOINT,
|
|
version: DOCKER_API_VERSION,
|
|
rawUrl: DOCKER_ENDPOINT + DOCKER_PORT + '/' + DOCKER_API_VERSION,
|
|
uiVersion: UI_VERSION,
|
|
url: url,
|
|
firstLoad: true
|
|
};
|
|
})
|
|
.factory('ViewSpinner', function() {
|
|
'use strict';
|
|
var spinner = new Spinner();
|
|
var target = document.getElementById('view');
|
|
|
|
return {
|
|
spin: function() { spinner.spin(target); },
|
|
stop: function() { spinner.stop(); }
|
|
};
|
|
})
|
|
.factory('Messages', function($rootScope) {
|
|
'use strict';
|
|
return {
|
|
send: function(title, text) {
|
|
$.gritter.add({
|
|
title: title,
|
|
text: text,
|
|
time: 2000,
|
|
before_open: function() {
|
|
if($('.gritter-item-wrapper').length === 3) {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
error: function(title, text) {
|
|
$.gritter.add({
|
|
title: title,
|
|
text: text,
|
|
time: 10000,
|
|
before_open: function() {
|
|
if($('.gritter-item-wrapper').length === 4) {
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
})
|
|
.factory('Dockerfile', function(Settings) {
|
|
'use strict';
|
|
var url = Settings.rawUrl + '/build';
|
|
return {
|
|
build: function(file, callback) {
|
|
var data = new FormData();
|
|
var dockerfile = new Blob([file], { type: 'text/text' });
|
|
data.append('Dockerfile', dockerfile);
|
|
|
|
var request = new XMLHttpRequest();
|
|
request.onload = callback;
|
|
request.open('POST', url);
|
|
request.send(data);
|
|
}
|
|
};
|
|
})
|
|
.factory('LineChart', function(Settings) {
|
|
'use strict';
|
|
var url = Settings.rawUrl + '/build';
|
|
return {
|
|
build: function(id, data, getkey){
|
|
var chart = new Chart($(id).get(0).getContext("2d"));
|
|
var map = {};
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var c = data[i];
|
|
var key = getkey(c);
|
|
|
|
var count = map[key];
|
|
if (count === undefined) {
|
|
count = 0;
|
|
}
|
|
count += 1;
|
|
map[key] = count;
|
|
}
|
|
|
|
var labels = [];
|
|
data = [];
|
|
var keys = Object.keys(map);
|
|
|
|
for (i = keys.length - 1; i > -1; i--) {
|
|
var k = keys[i];
|
|
labels.push(k);
|
|
data.push(map[k]);
|
|
}
|
|
var dataset = {
|
|
fillColor : "rgba(151,187,205,0.5)",
|
|
strokeColor : "rgba(151,187,205,1)",
|
|
pointColor : "rgba(151,187,205,1)",
|
|
pointStrokeColor : "#fff",
|
|
data : data
|
|
};
|
|
chart.Line({
|
|
labels: labels,
|
|
datasets: [dataset]
|
|
},
|
|
{
|
|
scaleStepWidth: 1,
|
|
pointDotRadius:1,
|
|
scaleOverride: true,
|
|
scaleSteps: labels.length
|
|
});
|
|
}
|
|
};
|
|
});
|
|
|
|
|
|
function ImageViewModel(data) {
|
|
this.Id = data.Id;
|
|
this.Tag = data.Tag;
|
|
this.Repository = data.Repository;
|
|
this.Created = data.Created;
|
|
this.Checked = false;
|
|
this.RepoTags = data.RepoTags;
|
|
this.VirtualSize = data.VirtualSize;
|
|
}
|
|
|
|
function ContainerViewModel(data) {
|
|
this.Id = data.Id;
|
|
this.Image = data.Image;
|
|
this.Command = data.Command;
|
|
this.Created = data.Created;
|
|
this.SizeRw = data.SizeRw;
|
|
this.Status = data.Status;
|
|
this.Checked = false;
|
|
this.Names = data.Names;
|
|
}
|
|
|
|
angular.module('dockerui.templates', ['app/components/builder/builder.html', 'app/components/container/container.html', 'app/components/containerLogs/containerlogs.html', 'app/components/containers/containers.html', 'app/components/dashboard/dashboard.html', 'app/components/footer/statusbar.html', 'app/components/image/image.html', 'app/components/images/images.html', 'app/components/masthead/masthead.html', 'app/components/settings/settings.html', 'app/components/sidebar/sidebar.html', 'app/components/startContainer/startcontainer.html']);
|
|
|
|
angular.module("app/components/builder/builder.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/builder/builder.html",
|
|
"<div id=\"build-modal\" class=\"modal fade\">\n" +
|
|
" <div class=\"modal-dialog\">\n" +
|
|
" <div class=\"modal-content\">\n" +
|
|
" <div class=\"modal-header\">\n" +
|
|
" <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n" +
|
|
" <h3>Build Image</h3>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"modal-body\">\n" +
|
|
" <div id=\"editor\"></div>\n" +
|
|
" <p>{{ messages }}</p>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"modal-footer\">\n" +
|
|
" <a href=\"\" class=\"btn btn-primary\" ng-click=\"build()\">Build</a>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/container/container.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/container/container.html",
|
|
"<div class=\"detail\">\n" +
|
|
" \n" +
|
|
" <h4>Container: {{ container.Name }}</h4>\n" +
|
|
"\n" +
|
|
" <div class=\"btn-group detail\">\n" +
|
|
" <button class=\"btn btn-success\"\n" +
|
|
" ng-click=\"start()\"\n" +
|
|
" ng-show=\"!container.State.Running\">Start</button>\n" +
|
|
" <button class=\"btn btn-warning\"\n" +
|
|
" ng-click=\"stop()\"\n" +
|
|
" ng-show=\"container.State.Running && !container.State.Paused\">Stop</button>\n" +
|
|
" <button class=\"btn btn-danger\"\n" +
|
|
" ng-click=\"kill()\"\n" +
|
|
" ng-show=\"container.State.Running && !container.State.Paused\">Kill</button>\n" +
|
|
" <button class=\"btn btn-info\"\n" +
|
|
" ng-click=\"pause()\"\n" +
|
|
" ng-show=\"container.State.Running && !container.State.Paused\">Pause</button>\n" +
|
|
" <button class=\"btn btn-success\"\n" +
|
|
" ng-click=\"unpause()\"\n" +
|
|
" ng-show=\"container.State.Running && container.State.Paused\">Unpause</button>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <table class=\"table table-striped\">\n" +
|
|
" <tbody>\n" +
|
|
" <tr>\n" +
|
|
" <td>Created:</td>\n" +
|
|
" <td>{{ container.Created }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Path:</td>\n" +
|
|
" <td>{{ container.Path }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Args:</td>\n" +
|
|
" <td>{{ container.Args }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Exposed Ports:</td>\n" +
|
|
" <td>\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"(k, v) in container.Config.ExposedPorts\">{{ k }}</li>\n" +
|
|
" </ul>\n" +
|
|
" </td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Environment:</td>\n" +
|
|
" <td>\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"k in container.Config.Env\">{{ k }}</li>\n" +
|
|
" </ul>\n" +
|
|
" </td>\n" +
|
|
" </tr>\n" +
|
|
"\n" +
|
|
" <tr>\n" +
|
|
" <td>Publish All:</td>\n" +
|
|
" <td>{{ container.HostConfig.PublishAllPorts }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Ports:</td>\n" +
|
|
" <td>\n" +
|
|
" <ul style=\"display:inline-table\">\n" +
|
|
" <li ng-repeat=\"(containerport, hostports) in container.HostConfig.PortBindings\">\n" +
|
|
" {{ containerport }} => <span class=\"label\" ng-repeat=\"(k,v) in hostports\">{{ v.HostIp }}:{{ v.HostPort }}</span>\n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
" </td>\n" +
|
|
"\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Hostname:</td>\n" +
|
|
" <td>{{ container.Config.Hostname }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>IPAddress:</td>\n" +
|
|
" <td>{{ container.NetworkSettings.IPAddress }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Cmd:</td>\n" +
|
|
" <td>{{ container.Config.Cmd }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Entrypoint:</td>\n" +
|
|
" <td>{{ container.Config.Entrypoint }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Volumes:</td>\n" +
|
|
" <td>{{ container.Volumes }}</td>\n" +
|
|
" </tr>\n" +
|
|
"\n" +
|
|
" <tr>\n" +
|
|
" <td>SysInitpath:</td>\n" +
|
|
" <td>{{ container.SysInitPath }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Image:</td>\n" +
|
|
" <td><a href=\"#/images/{{ container.Image }}/\">{{ container.Image }}</a></td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>State:</td>\n" +
|
|
" <td><span class=\"label {{ container.State|getstatelabel }}\">{{ container.State|getstatetext }}</span></td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Logs:</td>\n" +
|
|
" <td><a href=\"#/containers/{{ container.Id }}/logs\">stdout/stderr</a></td>\n" +
|
|
" </tr>\n" +
|
|
" </tbody>\n" +
|
|
" </table>\n" +
|
|
" \n" +
|
|
" <div class=\"row-fluid\">\n" +
|
|
" <div class=\"span1\">\n" +
|
|
" Changes:\n" +
|
|
" </div>\n" +
|
|
" <div class=\"span5\">\n" +
|
|
" <i class=\"icon-refresh\" style=\"width:32px;height:32px;\" ng-click=\"getChanges()\"></i>\n" +
|
|
" </div>\n" +
|
|
" </div> \n" +
|
|
"\n" +
|
|
" <div class=\"well well-large\">\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"change in changes | filter:hasContent\">\n" +
|
|
" <strong>{{ change.Path }}</strong> {{ change.Kind }}\n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <hr />\n" +
|
|
"\n" +
|
|
" <div class=\"btn-remove\">\n" +
|
|
" <button class=\"btn btn-large btn-block btn-primary btn-danger\" ng-click=\"remove()\">Remove Container</button>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/containerLogs/containerlogs.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/containerLogs/containerlogs.html",
|
|
"<div class=\"row logs\">\n" +
|
|
" <div class=\"col-xs-12\">\n" +
|
|
" <h4>Logs for container: <a href=\"#/containers/{{ container.Id }}/\">{{ container.Name }}</a></td></h4>\n" +
|
|
" <div class=\"btn-group detail\">\n" +
|
|
" <button class=\"btn btn-info\" ng-click=\"scrollTo('stdout')\">stdout</button>\n" +
|
|
" <button class=\"btn btn-warning\" ng-click=\"scrollTo('stderr')\">stderr</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"pull-right\">\n" +
|
|
" <input id=\"timestampToggle\" type=\"checkbox\" ng-model=\"showTimestamps\" \n" +
|
|
" ng-change=\"toggleTimestamps()\"/> <label for=\"timestampToggle\">Display Timestamps</label>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <div class=\"col-xs-12\">\n" +
|
|
" <div class=\"panel panel-default\">\n" +
|
|
" <div class=\"panel-heading\">\n" +
|
|
" <h3 id=\"stdout\" class=\"panel-title\">STDOUT</h3>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"panel-body\">\n" +
|
|
" <pre id=\"stdoutLog\" class=\"pre-scrollable pre-x-scrollable\">{{stdout}}</pre>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"col-xs-12\">\n" +
|
|
" <div class=\"panel panel-default\">\n" +
|
|
" <div class=\"panel-heading\">\n" +
|
|
" <h3 id=\"stderr\" class=\"panel-title\">STDERR</h3>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"panel-body\">\n" +
|
|
" <pre id=\"stderrLog\" class=\"pre-scrollable pre-x-scrollable\">{{stderr}}</pre>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/containers/containers.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/containers/containers.html",
|
|
"\n" +
|
|
"<h2>Containers:</h2>\n" +
|
|
"\n" +
|
|
"<div>\n" +
|
|
" <ul class=\"nav nav-pills pull-left\">\n" +
|
|
" <li class=\"dropdown\">\n" +
|
|
" <a class=\"dropdown-toggle\" id=\"drop4\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\">Actions <b class=\"caret\"></b></a>\n" +
|
|
" <ul id=\"menu1\" class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"drop4\">\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"startAction()\">Start</a></li>\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"stopAction()\">Stop</a></li>\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"killAction()\">Kill</a></li>\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"pauseAction()\">Pause</a></li>\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"unpauseAction()\">Unpause</a></li>\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"removeAction()\">Remove</a></li>\n" +
|
|
" </ul>\n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
"\n" +
|
|
" <div class=\"pull-right\">\n" +
|
|
" <input type=\"checkbox\" ng-model=\"displayAll\" \n" +
|
|
" ng-change=\"toggleGetAll()\"/> Display All\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"<table class=\"table table-striped\">\n" +
|
|
" <thead>\n" +
|
|
" <tr>\n" +
|
|
" <th><input type=\"checkbox\" ng-model=\"toggle\" ng-change=\"toggleSelectAll()\" /> Action</th>\n" +
|
|
" <th>Name</th>\n" +
|
|
" <th>Image</th>\n" +
|
|
" <th>Command</th>\n" +
|
|
" <th>Created</th>\n" +
|
|
" <th>Status</th>\n" +
|
|
" </tr>\n" +
|
|
" </thead>\n" +
|
|
" <tbody>\n" +
|
|
" <tr ng-repeat=\"container in containers|orderBy:predicate\">\n" +
|
|
" <td><input type=\"checkbox\" ng-model=\"container.Checked\" /></td>\n" +
|
|
" <td><a href=\"#/containers/{{ container.Id }}/\">{{ container|containername}}</a></td>\n" +
|
|
" <td><a href=\"#/images/{{ container.Image }}/\">{{ container.Image }}</a></td>\n" +
|
|
" <td>{{ container.Command|truncate:40 }}</td>\n" +
|
|
" <td>{{ container.Created|getdate }}</td>\n" +
|
|
" <td><span class=\"label label-{{ container.Status|statusbadge }}\">{{ container.Status }}</span></td>\n" +
|
|
" </tr>\n" +
|
|
" </tbody>\n" +
|
|
"</table>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/dashboard/dashboard.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/dashboard/dashboard.html",
|
|
" \n" +
|
|
"<div class=\"col-xs-offset-1\">\n" +
|
|
" <!--<div class=\"sidebar span4\">\n" +
|
|
" <div ng-include=\"template\" ng-controller=\"SideBarController\"></div>\n" +
|
|
" </div>-->\n" +
|
|
" <div class=\"row\">\n" +
|
|
" <div class=\"col-xs-10\" id=\"masthead\" style=\"display:none\">\n" +
|
|
" <div class=\"jumbotron\">\n" +
|
|
" <h1>DockerUI</h1>\n" +
|
|
" <p class=\"lead\">The Linux container engine</p>\n" +
|
|
" <a class=\"btn btn-large btn-success\" href=\"http://docker.io\">Learn more.</a>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" \n" +
|
|
" <div class=\"row\">\n" +
|
|
" <div class=\"col-xs-10\">\n" +
|
|
" <div class=\"col-xs-5\">\n" +
|
|
" <h3>Running Containers</h3>\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"container in containers|orderBy:predicate\">\n" +
|
|
" <a href=\"#/containers/{{ container.Id }}/\">{{ container|containername }}</a>\n" +
|
|
" <span class=\"label label-{{ container.Status|statusbadge }}\">{{ container.Status }}</span>\n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"col-xs-5 text-right\">\n" +
|
|
" <h3>Status</h3>\n" +
|
|
" <canvas id=\"containers-chart\" class=\"pull-right\">\n" +
|
|
" Get a better browser... Your holding everyone back.\n" +
|
|
" </canvas>\n" +
|
|
" <div id=\"chart-legend\"></div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <div class=\"row\">\n" +
|
|
" <div class=\"col-xs-10\" id=\"stats\">\n" +
|
|
" <h4>Containers created</h4>\n" +
|
|
" <canvas id=\"containers-started-chart\" width=\"700\">\n" +
|
|
" Get a better browser... You're holding everyone back.\n" +
|
|
" </canvas>\n" +
|
|
" <h4>Images created</h4>\n" +
|
|
" <canvas id=\"images-created-chart\" width=\"700\">\n" +
|
|
" Get a better browser... You're holding everyone back.\n" +
|
|
" </canvas>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/footer/statusbar.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/footer/statusbar.html",
|
|
"<footer class=\"center well\">\n" +
|
|
" <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>\n" +
|
|
"</footer>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/image/image.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/image/image.html",
|
|
"<div ng-include=\"template\" ng-controller=\"StartContainerController\"></div>\n" +
|
|
"\n" +
|
|
"<div class=\"alert alert-error\" id=\"error-message\" style=\"display:none\">\n" +
|
|
" {{ error }}\n" +
|
|
"</div>\n" +
|
|
"\n" +
|
|
"<div class=\"detail\">\n" +
|
|
" \n" +
|
|
" <h4>Image: {{ tag }}</h4>\n" +
|
|
"\n" +
|
|
" <div class=\"btn-group detail\">\n" +
|
|
" <button class=\"btn btn-success\" data-toggle=\"modal\" data-target=\"#create-modal\">Create</button>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <div>\n" +
|
|
" <h4>Containers created:</h4>\n" +
|
|
" <canvas id=\"containers-started-chart\" width=\"750\">\n" +
|
|
" Get a better broswer... Your holding everyone back.\n" +
|
|
" </canvas>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <table class=\"table table-striped\">\n" +
|
|
" <tbody>\n" +
|
|
" <tr>\n" +
|
|
" <td>Created:</td>\n" +
|
|
" <td>{{ image.created }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Parent:</td>\n" +
|
|
" <td><a href=\"#/images/{{ image.parent }}/\">{{ image.parent }}</a></td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Size:</td>\n" +
|
|
" <td>{{ image.Size|humansize }}</td>\n" +
|
|
" </tr>\n" +
|
|
"\n" +
|
|
" <tr>\n" +
|
|
" <td>Hostname:</td>\n" +
|
|
" <td>{{ image.container_config.Hostname }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>User:</td>\n" +
|
|
" <td>{{ image.container_config.User }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Cmd:</td>\n" +
|
|
" <td>{{ image.container_config.Cmd }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Volumes:</td>\n" +
|
|
" <td>{{ image.container_config.Volumes }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Volumes from:</td>\n" +
|
|
" <td>{{ image.container_config.VolumesFrom }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Comment:</td>\n" +
|
|
" <td>{{ image.comment }}</td>\n" +
|
|
" </tr>\n" +
|
|
"\n" +
|
|
" </tbody>\n" +
|
|
" </table>\n" +
|
|
"\n" +
|
|
" <div class=\"row-fluid\">\n" +
|
|
" <div class=\"span1\">\n" +
|
|
" History:\n" +
|
|
" </div>\n" +
|
|
" <div class=\"span5\">\n" +
|
|
" <i class=\"icon-refresh\" style=\"width:32px;height:32px;\" ng-click=\"getHistory()\"></i>\n" +
|
|
" </div>\n" +
|
|
" </div> \n" +
|
|
"\n" +
|
|
" <div class=\"well well-large\">\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"change in history\">\n" +
|
|
" <strong>{{ change.Id }}</strong>: Created: {{ change.Created|getdate }} Created by: {{ change.CreatedBy }}\n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <hr />\n" +
|
|
"\n" +
|
|
" <div class=\"row-fluid\">\n" +
|
|
" <form class=\"form-inline\" role=\"form\">\n" +
|
|
" <fieldset>\n" +
|
|
" <legend>Tag image</legend>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Tag:</label>\n" +
|
|
" <input type=\"text\" placeholder=\"repo...\" ng-model=\"tag.repo\" class=\"form-control\">\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"checkbox\">\n" +
|
|
" <input type=\"checkbox\" ng-model=\"tag.force\" class=\"form-control\"/> Force?\n" +
|
|
" </label>\n" +
|
|
" </div>\n" +
|
|
" <input type=\"button\" ng-click=\"updateTag()\" value=\"Tag\" class=\"btn btn-primary\"/>\n" +
|
|
" </fieldset>\n" +
|
|
" </form>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <hr />\n" +
|
|
"\n" +
|
|
" <div class=\"btn-remove\">\n" +
|
|
" <button class=\"btn btn-large btn-block btn-primary btn-danger\" ng-click=\"remove()\">Remove Image</button>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/images/images.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/images/images.html",
|
|
"\n" +
|
|
"<div ng-include=\"template\" ng-controller=\"BuilderController\"></div>\n" +
|
|
"\n" +
|
|
"<h2>Images:</h2>\n" +
|
|
"\n" +
|
|
"<ul class=\"nav nav-pills\">\n" +
|
|
" <li class=\"dropdown\">\n" +
|
|
" <a class=\"dropdown-toggle\" id=\"drop4\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\">Actions <b class=\"caret\"></b></a>\n" +
|
|
" <ul id=\"menu1\" class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"drop4\">\n" +
|
|
" <li><a tabindex=\"-1\" href=\"\" ng-click=\"removeAction()\">Remove</a></li>\n" +
|
|
" </ul>\n" +
|
|
" </li>\n" +
|
|
"</ul>\n" +
|
|
"<table class=\"table table-striped\">\n" +
|
|
" <thead>\n" +
|
|
" <tr>\n" +
|
|
" <th><input type=\"checkbox\" ng-model=\"toggle\" ng-change=\"toggleSelectAll()\" /> Action</th>\n" +
|
|
" <th>Id</th>\n" +
|
|
" <th>Repository</th>\n" +
|
|
" <th>VirtualSize</th>\n" +
|
|
" <th>Created</th>\n" +
|
|
" </tr>\n" +
|
|
" </thead>\n" +
|
|
" <tbody>\n" +
|
|
" <tr ng-repeat=\"image in images | orderBy:predicate\">\n" +
|
|
" <td><input type=\"checkbox\" ng-model=\"image.Checked\" /></td>\n" +
|
|
" <td><a href=\"#/images/{{ image.Id }}/?tag={{ image|repotag }}\">{{ image.Id|truncate:20}}</a></td>\n" +
|
|
" <td>{{ image|repotag }}</td>\n" +
|
|
" <td>{{ image.VirtualSize|humansize }}</td>\n" +
|
|
" <td>{{ image.Created|getdate }}</td>\n" +
|
|
" </tr>\n" +
|
|
" </tbody>\n" +
|
|
"</table>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/masthead/masthead.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/masthead/masthead.html",
|
|
" <div class=\"masthead\">\n" +
|
|
" <h3 class=\"text-muted\">DockerUI</h3>\n" +
|
|
" <ul class=\"nav well\">\n" +
|
|
" <li><a href=\"#\">Dashboard</a></li>\n" +
|
|
" <li><a href=\"#/containers/\">Containers</a></li>\n" +
|
|
" <li><a href=\"#/images/\">Images</a></li>\n" +
|
|
" <li><a href=\"#/settings/\">Settings</a></li>\n" +
|
|
" </ul>\n" +
|
|
" </div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/settings/settings.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/settings/settings.html",
|
|
"<div class=\"detail\">\n" +
|
|
" <h2>Docker Information</h2>\n" +
|
|
" <div>\n" +
|
|
" <p class=\"lead\">\n" +
|
|
" <strong>Endpoint: </strong>{{ endpoint }}<br />\n" +
|
|
" <strong>Api Version: </strong>{{ apiVersion }}<br />\n" +
|
|
" <strong>Version: </strong>{{ docker.Version }}<br />\n" +
|
|
" <strong>Git Commit: </strong>{{ docker.GitCommit }}<br />\n" +
|
|
" <strong>Go Version: </strong>{{ docker.GoVersion }}<br />\n" +
|
|
" </p>\n" +
|
|
" </div>\n" +
|
|
"\n" +
|
|
" <table class=\"table table-striped\">\n" +
|
|
" <tbody>\n" +
|
|
" <tr>\n" +
|
|
" <td>Containers:</td>\n" +
|
|
" <td>{{ info.Containers }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Images:</td>\n" +
|
|
" <td>{{ info.Images }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>Debug:</td>\n" +
|
|
" <td>{{ info.Debug }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>NFd:</td>\n" +
|
|
" <td>{{ info.NFd }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>NGoroutines:</td>\n" +
|
|
" <td>{{ info.NGoroutines }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>MemoryLimit:</td>\n" +
|
|
" <td>{{ info.MemoryLimit }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>SwapLimit:</td>\n" +
|
|
" <td>{{ info.SwapLimit }}</td>\n" +
|
|
" </tr>\n" +
|
|
" <tr>\n" +
|
|
" <td>NFd:</td>\n" +
|
|
" <td>{{ info.NFd }}</td>\n" +
|
|
" </tr>\n" +
|
|
" </tbody>\n" +
|
|
" </table>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/sidebar/sidebar.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/sidebar/sidebar.html",
|
|
"<div class=\"well\">\n" +
|
|
" <strong>Running containers:</strong>\n" +
|
|
" <br />\n" +
|
|
" <strong>Endpoint: </strong>{{ endpoint }}\n" +
|
|
" <ul>\n" +
|
|
" <li ng-repeat=\"container in containers\">\n" +
|
|
" <a href=\"#/containers/{{ container.Id }}/\">{{ container.Id|truncate:20 }}</a>\n" +
|
|
" <span class=\"pull-right label label-{{ container.Status|statusbadge }}\">{{ container.Status }}</span> \n" +
|
|
" </li>\n" +
|
|
" </ul>\n" +
|
|
"</div> \n" +
|
|
"");
|
|
}]);
|
|
|
|
angular.module("app/components/startContainer/startcontainer.html", []).run(["$templateCache", function($templateCache) {
|
|
$templateCache.put("app/components/startContainer/startcontainer.html",
|
|
"<div id=\"create-modal\" class=\"modal fade\">\n" +
|
|
" <div class=\"modal-dialog\">\n" +
|
|
" <div class=\"modal-content\">\n" +
|
|
" <div class=\"modal-header\">\n" +
|
|
" <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">×</button>\n" +
|
|
" <h3>Create And Start Container From Image</h3>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"modal-body\">\n" +
|
|
" <form role=\"form\">\n" +
|
|
" <accordion close-others=\"true\">\n" +
|
|
" <accordion-group heading=\"Container options\" is-open=\"menuStatus.containerOpen\">\n" +
|
|
" <fieldset>\n" +
|
|
" <div class=\"row\">\n" +
|
|
" <div class=\"col-xs-6\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Cmd:</label>\n" +
|
|
" <input type=\"text\" placeholder='[\"/bin/echo\", \"Hello world\"]' ng-model=\"config.Cmd\" class=\"form-control\"/>\n" +
|
|
" <small>Input commands as a raw string or JSON array</small>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Entrypoint:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.Entrypoint\" class=\"form-control\" placeholder=\"./entrypoint.sh\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Name:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.name\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Hostname:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.Hostname\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Domainname:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.Domainname\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>User:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.User\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Memory:</label>\n" +
|
|
" <input type=\"number\" ng-model=\"config.Memory\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Volumes:</label>\n" +
|
|
" <div ng-repeat=\"volume in config.Volumes\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"volume.name\" class=\"form-control\" placeholder=\"/var/data\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.Volumes, volume)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.Volumes, {name: ''})\">Add Volume</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"col-xs-6\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>MemorySwap:</label>\n" +
|
|
" <input type=\"number\" ng-model=\"config.MemorySwap\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>CpuShares:</label>\n" +
|
|
" <input type=\"number\" ng-model=\"config.CpuShares\" class=\"form-control\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Cpuset:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.Cpuset\" class=\"form-control\" placeholder=\"1,2\"/>\n" +
|
|
" <small>Input as comma-separated list of numbers</small>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>WorkingDir:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.WorkingDir\" class=\"form-control\" placeholder=\"/app\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>MacAddress:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.MacAddress\" class=\"form-control\" placeholder=\"12:34:56:78:9a:bc\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"networkDisabled\">NetworkDisabled:</label>\n" +
|
|
" <input id=\"networkDisabled\" type=\"checkbox\" ng-model=\"config.NetworkDisabled\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"tty\">Tty:</label>\n" +
|
|
" <input id=\"tty\" type=\"checkbox\" ng-model=\"config.Tty\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"openStdin\">OpenStdin:</label>\n" +
|
|
" <input id=\"openStdin\" type=\"checkbox\" ng-model=\"config.OpenStdin\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"stdinOnce\">StdinOnce:</label>\n" +
|
|
" <input id=\"stdinOnce\" type=\"checkbox\" ng-model=\"config.StdinOnce\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>SecurityOpts:</label>\n" +
|
|
" <div ng-repeat=\"opt in config.SecurityOpts\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"opt.name\" class=\"form-control\" placeholder=\"label:type:svirt_apache\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.SecurityOpts, opt)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.SecurityOpts, {name: ''})\">Add Option</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <hr>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Env:</label>\n" +
|
|
" <div ng-repeat=\"envar in config.Env\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">Variable Name:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"envar.name\" class=\"form-control\" placeholder=\"NAME\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">Variable Value:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"envar.value\" class=\"form-control\" placeholder=\"value\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.Env, envar)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.Env, {name: '', value: ''})\">Add environment variable</button>\n" +
|
|
" </div>\n" +
|
|
" </fieldset>\n" +
|
|
" </accordion-group>\n" +
|
|
" <accordion-group heading=\"HostConfig options\" is-open=\"menuStatus.hostConfigOpen\">\n" +
|
|
" <fieldset>\n" +
|
|
" <div class=\"row\">\n" +
|
|
" <div class=\"col-xs-6\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Binds:</label>\n" +
|
|
" <div ng-repeat=\"bind in config.HostConfig.Binds\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"bind.name\" class=\"form-control\" placeholder=\"/host:/container\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.Binds, bind)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.Binds, {name: ''})\">Add Bind</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Links:</label>\n" +
|
|
" <div ng-repeat=\"link in config.HostConfig.Links\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"link.name\" class=\"form-control\" placeholder=\"web:db\">\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.Links, link)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.Links, {name: ''})\">Add Link</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Dns:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.Dns\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"entry.name\" class=\"form-control\" placeholder=\"8.8.8.8\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.Dns, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.Dns, {name: ''})\">Add entry</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>DnsSearch:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.DnsSearch\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"entry.name\" class=\"form-control\" placeholder=\"example.com\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.DnsSearch, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.DnsSearch, {name: ''})\">Add entry</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>CapAdd:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.CapAdd\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"entry.name\" class=\"form-control\" placeholder=\"cap_sys_admin\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.CapAdd, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.CapAdd, {name: ''})\">Add entry</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>CapDrop:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.CapDrop\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <input type=\"text\" ng-model=\"entry.name\" class=\"form-control\" placeholder=\"cap_sys_admin\"/>\n" +
|
|
" <button type=\"button\" class=\"btn btn-danger btn-sm\" ng-click=\"rmEntry(config.HostConfig.CapDrop, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.CapDrop, {name: ''})\">Add entry</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"col-xs-6\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>NetworkMode:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"config.HostConfig.NetworkMode\" class=\"form-control\" placeholder=\"bridge\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"publishAllPorts\">PublishAllPorts:</label>\n" +
|
|
" <input id=\"publishAllPorts\" type=\"checkbox\" ng-model=\"config.HostConfig.PublishAllPorts\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label for=\"privileged\">Privileged:</label>\n" +
|
|
" <input id=\"privileged\" type=\"checkbox\" ng-model=\"config.HostConfig.Privileged\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>VolumesFrom:</label>\n" +
|
|
" <div ng-repeat=\"volume in config.HostConfig.VolumesFrom\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <select ng-model=\"volume.name\" ng-options=\"name for name in containerNames track by name\" class=\"form-control\"/>\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.HostConfig.VolumesFrom, volume)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.VolumesFrom, {name: ''})\">Add volume</button>\n" +
|
|
" </div>\n" +
|
|
" \n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>RestartPolicy:</label>\n" +
|
|
" <select ng-model=\"config.HostConfig.RestartPolicy.name\">\n" +
|
|
" <option value=\"\">disabled</option>\n" +
|
|
" <option value=\"always\">always</option>\n" +
|
|
" <option value=\"on-failure\">on-failure</option>\n" +
|
|
" </select>\n" +
|
|
" <label>MaximumRetryCount:</label>\n" +
|
|
" <input type=\"number\" ng-model=\"config.HostConfig.RestartPolicy.MaximumRetryCount\"/>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <hr>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>ExtraHosts:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.ExtraHosts\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">Hostname:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"entry.host\" class=\"form-control\" placeholder=\"hostname\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">IP Address:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"entry.ip\" class=\"form-control\" placeholder=\"127.0.0.1\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.HostConfig.ExtraHosts, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.ExtraHosts, {host: '', ip: ''})\">Add extra host</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>LxcConf:</label>\n" +
|
|
" <div ng-repeat=\"entry in config.HostConfig.LxcConf\">\n" +
|
|
" <div class=\"form-group form-inline\">\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">Name:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"entry.name\" class=\"form-control\" placeholder=\"lxc.utsname\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label class=\"sr-only\">Value:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"entry.value\" class=\"form-control\" placeholder=\"docker\"/>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.HostConfig.LxcConf, entry)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.LxcConf, {name: '', value: ''})\">Add Entry</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>Devices:</label>\n" +
|
|
" <div ng-repeat=\"device in config.HostConfig.Devices\">\n" +
|
|
" <div class=\"form-group form-inline inline-four\">\n" +
|
|
" <label class=\"sr-only\">PathOnHost:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"device.PathOnHost\" class=\"form-control\" placeholder=\"PathOnHost\"/>\n" +
|
|
" <label class=\"sr-only\">PathInContainer:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"device.PathInContainer\" class=\"form-control\" placeholder=\"PathInContainer\"/>\n" +
|
|
" <label class=\"sr-only\">CgroupPermissions:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"device.CgroupPermissions\" class=\"form-control\" placeholder=\"CgroupPermissions\"/>\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.HostConfig.Devices, device)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.Devices, { PathOnHost: '', PathInContainer: '', CgroupPermissions: ''})\">Add Device</button>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"form-group\">\n" +
|
|
" <label>PortBindings:</label>\n" +
|
|
" <div ng-repeat=\"portBinding in config.HostConfig.PortBindings\">\n" +
|
|
" <div class=\"form-group form-inline inline-four\">\n" +
|
|
" <label class=\"sr-only\">Host IP:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"portBinding.ip\" class=\"form-control\" placeholder=\"Host IP Address\"/>\n" +
|
|
" <label class=\"sr-only\">Host Port:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"portBinding.extPort\" class=\"form-control\" placeholder=\"Host Port\"/>\n" +
|
|
" <label class=\"sr-only\">Container port:</label>\n" +
|
|
" <input type=\"text\" ng-model=\"portBinding.intPort\" class=\"form-control\" placeholder=\"Container Port\"/>\n" +
|
|
" <button class=\"btn btn-danger btn-xs form-control\" ng-click=\"rmEntry(config.HostConfig.PortBindings, portBinding)\">Remove</button>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" <button type=\"button\" class=\"btn btn-success btn-sm\" ng-click=\"addEntry(config.HostConfig.PortBindings, {ip: '', extPort: '', intPort: ''})\">Add Port Binding</button>\n" +
|
|
" </div>\n" +
|
|
" </fieldset>\n" +
|
|
" </accordion-group>\n" +
|
|
" </accordion>\n" +
|
|
" </form>\n" +
|
|
" </div>\n" +
|
|
" <div class=\"modal-footer\">\n" +
|
|
" <a href=\"\" class=\"btn btn-primary btn-lg\" ng-click=\"create()\">Create</a>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
" </div>\n" +
|
|
"</div>\n" +
|
|
"");
|
|
}]);
|