diff --git a/README.md b/README.md index 8f5258c51..d53d59cbb 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ The easiest way to manage Docker. [![Microbadger](https://images.microbadger.com/badges/image/portainer/portainer.svg)](http://microbadger.com/images/portainer/portainer "Image size") +[![Documentation Status](https://readthedocs.org/projects/portainer/badge/?version=stable)](http://portainer.readthedocs.io/en/stable/?badge=stable) [![Gitter](https://badges.gitter.im/portainer/Lobby.svg)](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Portainer is a lightweight management UI which allows you to **easily** manage your Docker host or Swarm cluster. @@ -29,7 +30,7 @@ If you don't specify any target, its default behaviour is to use a bind mount on $ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer ``` -Have a look at our [wiki](https://github.com/portainer/portainer/wiki/Deployment) for more deployment options. +Have a look at our [documentation](http://portainer.readthedocs.io/en/stable/deployment.html) for more deployment options. # Configuration @@ -61,13 +62,13 @@ Add the `--templates` flag and specify the external location of your templates w $ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer --templates http://my-host.my-domain/templates.json ``` -For more information about hosting your own template definitions and the format, see: https://github.com/portainer/templates +For more information about hosting your own template definitions and the format, see the [templates documentation](http://portainer.readthedocs.io/en/stable/templates.html). -Have a look at our [wiki](https://github.com/portainer/portainer/wiki/Configuration) for more configuration options. +Check our [documentation](http://portainer.readthedocs.io/en/stable/configuration.html) for more configuration options. # FAQ -Be sure to check our [FAQ](https://github.com/portainer/portainer/wiki/FAQ) if you are missing some information. +Be sure to check our [FAQ](http://portainer.readthedocs.io/en/stable/faq.html) if you are missing some information. # Limitations diff --git a/api/main.go b/api/main.go index 4e81b2c56..e6ad24eb2 100644 --- a/api/main.go +++ b/api/main.go @@ -6,7 +6,7 @@ import ( // main is the entry point of the program func main() { - kingpin.Version("1.9.0") + kingpin.Version("1.9.1") var ( endpoint = kingpin.Flag("host", "Dockerd endpoint").Default("unix:///var/run/docker.sock").Short('H').String() addr = kingpin.Flag("bind", "Address and port to serve Portainer").Default(":9000").Short('p').String() diff --git a/app/app.js b/app/app.js index 0daaa86d7..8cc2eb4d7 100644 --- a/app/app.js +++ b/app/app.js @@ -188,4 +188,4 @@ angular.module('portainer', [ .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('CONFIG_ENDPOINT', 'settings') .constant('TEMPLATES_ENDPOINT', 'templates') - .constant('UI_VERSION', 'v1.9.0'); + .constant('UI_VERSION', 'v1.9.1'); diff --git a/app/components/containerConsole/containerConsoleController.js b/app/components/containerConsole/containerConsoleController.js index 7bcd91734..3f1bcd757 100644 --- a/app/components/containerConsole/containerConsoleController.js +++ b/app/components/containerConsole/containerConsoleController.js @@ -9,7 +9,7 @@ function ($scope, $stateParams, Settings, Container, Exec, $timeout, Messages) { // Ensure the socket is closed before leaving the view $scope.$on('$stateChangeStart', function (event, next, current) { - if (socket !== null) { + if (socket && socket !== null) { socket.close(); } }); diff --git a/app/components/containers/containers.html b/app/components/containers/containers.html index 378233f34..e8f681f41 100644 --- a/app/components/containers/containers.html +++ b/app/components/containers/containers.html @@ -41,8 +41,8 @@ State - - + + @@ -93,7 +93,7 @@ {{ container.hostIP }} - {{ p.private }} + {{p.public}}:{{ p.private }} - diff --git a/app/components/dashboard/dashboard.html b/app/components/dashboard/dashboard.html index ca289aafc..0ae284cc3 100644 --- a/app/components/dashboard/dashboard.html +++ b/app/components/dashboard/dashboard.html @@ -41,7 +41,7 @@ Nodes - {{ infoData.SystemStatus[3][1] }} + {{ infoData.SystemStatus[0][1] == 'primary' ? infoData.SystemStatus[3][1] : infoData.SystemStatus[4][1] }} Swarm version @@ -53,7 +53,7 @@ Total memory - {{ infoData.MemTotal|humansize }} + {{ infoData.MemTotal|humansize: 2 }} diff --git a/app/components/stats/statsController.js b/app/components/stats/statsController.js index 8585640d1..902b15b59 100644 --- a/app/components/stats/statsController.js +++ b/app/components/stats/statsController.js @@ -87,7 +87,7 @@ function (Settings, $scope, Messages, $timeout, Container, ContainerTop, $stateP }, { scaleLabel: function (valueObj) { - return humansizeFilter(parseInt(valueObj.value, 10)); + return humansizeFilter(parseInt(valueObj.value, 10), 2); }, responsive: true //scaleOverride: true, @@ -100,7 +100,7 @@ function (Settings, $scope, Messages, $timeout, Container, ContainerTop, $stateP datasets: [networkRxDataset, networkTxDataset] }, { scaleLabel: function (valueObj) { - return humansizeFilter(parseInt(valueObj.value, 10)); + return humansizeFilter(parseInt(valueObj.value, 10), 2); }, responsive: true }); diff --git a/app/components/swarm/swarm.html b/app/components/swarm/swarm.html index a9b5316e8..125b45c1e 100644 --- a/app/components/swarm/swarm.html +++ b/app/components/swarm/swarm.html @@ -42,8 +42,8 @@ Total memory - {{ info.MemTotal|humansize }} - {{ totalMemory|humansize }} + {{ info.MemTotal|humansize: 2 }} + {{ totalMemory|humansize: 2 }} Operating system diff --git a/app/components/swarm/swarmController.js b/app/components/swarm/swarmController.js index b0a1435fc..a79954120 100644 --- a/app/components/swarm/swarmController.js +++ b/app/components/swarm/swarmController.js @@ -47,7 +47,8 @@ function ($scope, Info, Version, Node) { // Swarm filters $scope.swarm[systemStatus[2][0]] = systemStatus[2][1]; // Swarm node count - var node_count = parseInt(systemStatus[3][1], 10); + var nodes = systemStatus[0][1] === 'primary' ? systemStatus[3][1] : systemStatus[4][1]; + var node_count = parseInt(nodes, 10); $scope.swarm[systemStatus[3][0]] = node_count; $scope.swarm.Status = []; @@ -55,9 +56,10 @@ function ($scope, Info, Version, Node) { } function extractNodesInfo(info, node_count) { - // First information for node1 available at element #4 of SystemStatus + // First information for node1 available at element #4 of SystemStatus if connected to a primary + // If connected to a replica, information for node1 is available at element #5 // The next 10 elements are information related to the node - var node_offset = 4; + var node_offset = info[0][1] === 'primary' ? 4 : 5; for (i = 0; i < node_count; i++) { extractNodeInfo(info, node_offset); node_offset += 9; diff --git a/app/components/templates/templates.html b/app/components/templates/templates.html index 40a42bedc..a53bd09af 100644 --- a/app/components/templates/templates.html +++ b/app/components/templates/templates.html @@ -7,31 +7,11 @@ Templates -
-
- - -
- -
-
- -
-
- -
{{ tpl.title }}
-
{{ tpl.description }}
-
-
-
-
-
-
-
- + +
@@ -62,15 +42,21 @@
- -
+
+
+ + +
+
@@ -78,10 +64,26 @@
-
-
- -
- + +
+ +
+
+ + +
+ +
+
+ +
+
+ +
{{ tpl.title }}
+
{{ tpl.description }}
+
+
+
+
diff --git a/app/directives/widget-custom-header.js b/app/directives/widget-custom-header.js new file mode 100644 index 000000000..c1444b3f6 --- /dev/null +++ b/app/directives/widget-custom-header.js @@ -0,0 +1,15 @@ +angular +.module('portainer') +.directive('rdWidgetCustomHeader', function rdWidgetCustomHeader() { + var directive = { + requires: '^rdWidget', + scope: { + title: '=', + icon: '=' + }, + transclude: true, + template: '
{{title}}
', + restrict: 'E' + }; + return directive; +}); diff --git a/app/shared/filters.js b/app/shared/filters.js index 339b7f85a..2de2e49c8 100644 --- a/app/shared/filters.js +++ b/app/shared/filters.js @@ -123,15 +123,13 @@ angular.module('portainer.filters', []) }) .filter('humansize', function () { 'use strict'; - return function (bytes) { - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes === 0) { - return 'n/a'; + return function (bytes, round) { + if (!round) { + round = 1; + } + if (bytes || bytes === 0) { + return filesize(bytes, {base: 10, round: round}); } - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10); - var value = bytes / Math.pow(1024, i); - var decimalPlaces = (i < 1) ? 0 : (i - 1); - return value.toFixed(decimalPlaces) + ' ' + sizes[[i]]; }; }) .filter('containername', function () { diff --git a/app/shared/viewmodel.js b/app/shared/viewmodel.js index b505ac162..921df1ff2 100644 --- a/app/shared/viewmodel.js +++ b/app/shared/viewmodel.js @@ -105,6 +105,9 @@ function createEventDetails(event) { case 'unpause': details = 'Container ' + eventAttr.name + ' unpaused'; break; + case 'attach': + details = 'Container ' + eventAttr.name + ' attached'; + break; default: if (event.Action.indexOf('exec_create') === 0) { details = 'Exec instance created'; @@ -159,6 +162,12 @@ function createEventDetails(event) { case 'destroy': details = 'Volume ' + event.Actor.ID + ' deleted'; break; + case 'mount': + details = 'Volume ' + event.Actor.ID + ' mounted'; + break; + case 'unmount': + details = 'Volume ' + event.Actor.ID + ' unmounted'; + break; default: details = 'Unsupported event'; } diff --git a/assets/css/app.css b/assets/css/app.css index 38711bdb9..c993c6230 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -216,6 +216,11 @@ input[type="radio"] { flex-wrap: wrap; } +.custom-header-ico { + max-width: 16px; + max-height: 16px; +} + .container-template { font-size: 1em; width: 256px; diff --git a/assets/ico/apple-touch-icon-precomposed.png b/assets/ico/apple-touch-icon-precomposed.png index 074c906a8..942ba394b 100644 Binary files a/assets/ico/apple-touch-icon-precomposed.png and b/assets/ico/apple-touch-icon-precomposed.png differ diff --git a/assets/ico/favicon.ico b/assets/ico/favicon.ico index 074c906a8..942ba394b 100644 Binary files a/assets/ico/favicon.ico and b/assets/ico/favicon.ico differ diff --git a/bower.json b/bower.json index f04b4f56f..0e811c6fb 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "portainer", - "version": "1.9.0", + "version": "1.9.1", "homepage": "https://github.com/portainer/portainer", "authors": [ "Anthony Lapenna " @@ -34,13 +34,14 @@ "angular-ui-select": "~0.17.1", "bootstrap": "~3.3.6", "font-awesome": "~4.6.3", + "filesize": "~3.3.0", "Hover": "2.0.2", "jquery": "1.11.1", "jquery.gritter": "1.7.4", "lodash": "4.12.0", "rdash-ui": "1.0.*", "moment": "~2.14.1", - "xterm.js": "~1.0.0" + "xterm.js": "~1.1.3" }, "resolutions": { "angular": "1.5.5" diff --git a/gruntFile.js b/gruntFile.js index 4b9ae9fb8..f1e4db93b 100644 --- a/gruntFile.js +++ b/gruntFile.js @@ -71,6 +71,7 @@ module.exports = function (grunt) { 'bower_components/bootstrap/dist/js/bootstrap.min.js', 'bower_components/Chart.js/Chart.min.js', 'bower_components/lodash/dist/lodash.min.js', + 'bower_components/filesize/lib/filesize.min.js', 'bower_components/moment/min/moment.min.js', 'bower_components/xterm.js/src/xterm.js', 'assets/js/jquery.gritter.js', // Using custom version to fix error in minified build due to "use strict" @@ -274,7 +275,7 @@ module.exports = function (grunt) { command: [ 'docker stop portainer', 'docker rm portainer', - 'docker run -d -p 9000:9000 -v /tmp/portainer:/data --name portainer portainer -H tcp://10.0.7.10:4000 --swarm -d /data' + 'docker run -d -p 9000:9000 -v /tmp/portainer:/data --name portainer portainer -H tcp://10.0.7.10:2375 --swarm -d /data' ].join(';') }, runSsl: { diff --git a/index.html b/index.html index e3db77937..71859a52d 100644 --- a/index.html +++ b/index.html @@ -59,13 +59,13 @@ - - diff --git a/package.json b/package.json index e434261d9..62bfd505b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Portainer.io", "name": "portainer", "homepage": "http://portainer.io", - "version": "1.9.0", + "version": "1.9.1", "repository": { "type": "git", "url": "git@github.com:portainer/portainer.git" diff --git a/test/unit/app/shared/filters.spec.js b/test/unit/app/shared/filters.spec.js index 5b8bb17d8..ad45d2ace 100644 --- a/test/unit/app/shared/filters.spec.js +++ b/test/unit/app/shared/filters.spec.js @@ -82,32 +82,6 @@ describe('filters', function () { })); }); - describe('humansize', function () { - it('should return n/a when size is zero', inject(function (humansizeFilter) { - expect(humansizeFilter(0)).toBe('n/a'); - })); - - it('should handle Bytes values', inject(function (humansizeFilter) { - expect(humansizeFilter(512)).toBe('512 Bytes'); - })); - - it('should handle KB values', inject(function (humansizeFilter) { - expect(humansizeFilter(5 * 1024)).toBe('5 KB'); - })); - - it('should handle MB values', inject(function (humansizeFilter) { - expect(humansizeFilter(5 * 1024 * 1024)).toBe('5.0 MB'); - })); - - it('should handle GB values', inject(function (humansizeFilter) { - expect(humansizeFilter(5 * 1024 * 1024 * 1024)).toBe('5.00 GB'); - })); - - it('should handle TB values', inject(function (humansizeFilter) { - expect(humansizeFilter(5 * 1024 * 1024 * 1024 * 1024)).toBe('5.000 TB'); - })); - }); - describe('containername', function () { it('should strip the leading slash from container name', inject(function (containernameFilter) { var container = {