mirror of https://github.com/portainer/portainer
commit
09a5534499
80
README.md
80
README.md
|
@ -1,79 +1,47 @@
|
||||||
# Portainer
|
|
||||||
|
|
||||||
The easiest way to manage Docker.
|
<p align="center">
|
||||||
|
<img title="portainer" src='http://portainer.io/images/logo_alt.png' />
|
||||||
|
</p>
|
||||||
|
|
||||||
[](https://microbadger.com/images/portainer/portainer "Latest version on Docker Hub")
|
[](https://microbadger.com/images/portainer/portainer "Latest version on Docker Hub")
|
||||||
[](http://microbadger.com/images/portainer/portainer "Image size")
|
[](http://microbadger.com/images/portainer/portainer "Image size")
|
||||||
[](http://portainer.readthedocs.io/en/stable/?badge=stable)
|
[](http://portainer.readthedocs.io/en/latest/?badge=latest)
|
||||||
[](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](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.
|
**_Portainer_** is a lightweight management UI which allows you to **easily** manage your Docker host or Swarm cluster.
|
||||||
|
|
||||||
# Usage
|
**_Portainer_** is meant to be as **simple** to deploy as it is to use. It consists of a single container that can run on any Docker for Linux engine. A Docker for Windows version is on its way !
|
||||||
|
|
||||||
It's really simple to deploy it using Docker:
|
**_Portainer_** allows you to manage your Docker containers, images, volumes, networks and more ! It is compatible with the *standalone Docker* engine and with *Docker Swarm*.
|
||||||
|
|
||||||
```shell
|
## Demo
|
||||||
$ docker run -d -p 9000:9000 portainer/portainer -H tcp://<DOCKER_HOST>:<DOCKER_PORT>
|
|
||||||
```
|
|
||||||
|
|
||||||
Just point it at your targeted Docker host and then access Portainer by hitting [http://localhost:9000](http://localhost:9000) with a web browser.
|
<img src="http://portainer.io/images/screenshots/portainer.gif" width="77%"/>
|
||||||
|
|
||||||
If your target is a Docker Swarm cluster or a Docker cluster using *swarm mode*, just add the flag `--swarm`:
|
You can try out the public demo instance: http://demo.portainer.io/ (login with the username **demo** and the password **tryportainer**).
|
||||||
|
|
||||||
```shell
|
Please note that the public demo cluster is **reset every 15min**.
|
||||||
$ docker run -d -p 9000:9000 portainer/portainer -H tcp://<SWARM_HOST>:<SWARM_PORT> --swarm
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't specify any target, its default behaviour is to use a bind mount on the Docker socket so you can easily deploy it to manage your local Docker host:
|
## Getting started
|
||||||
|
|
||||||
```shell
|
* [Deploy Portainer](https://portainer.readthedocs.io/en/latest/deployment.html)
|
||||||
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
|
* [Documentation](https://portainer.readthedocs.io)
|
||||||
```
|
|
||||||
|
|
||||||
Have a look at our [documentation](http://portainer.readthedocs.io/en/stable/deployment.html) for more deployment options.
|
## Getting help
|
||||||
|
|
||||||
# Configuration
|
* Issues: https://github.com/portainer/portainer/issues
|
||||||
|
* FAQ: https://portainer.readthedocs.io/en/latest/faq.html
|
||||||
|
* Gitter (chat): https://gitter.im/portainer/Lobby
|
||||||
|
* Slack: http://portainer.io/slack/
|
||||||
|
|
||||||
Portainer is easy to tune using CLI flags.
|
## Reporting bugs and contributing
|
||||||
|
|
||||||
## Hiding specific containers
|
* Want to report a bug or request a feature? Please open [an issue](https://github.com/portainer/portainer/issues/new).
|
||||||
|
* Want to help us build **_portainer_**? Follow our [contribution guidelines](https://portainer.readthedocs.io/en/latest/contribute.html) to build it locally and make a pull request. We need all the help we can get!
|
||||||
|
|
||||||
Portainer allows you to hide container with a specific label by using the `-l` flag.
|
## Limitations
|
||||||
|
|
||||||
For example, take a container started with the label `owner=acme`:
|
**_Portainer_** has full support for the following Docker versions:
|
||||||
```shell
|
|
||||||
$ docker run -d --label owner=acme nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
Simply add the `-l owner=acme` option on the CLI when starting Portainer:
|
|
||||||
```shell
|
|
||||||
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer -l owner=acme
|
|
||||||
```
|
|
||||||
|
|
||||||
## Use your own templates
|
|
||||||
|
|
||||||
Portainer allows you to rapidly deploy containers using `App Templates`.
|
|
||||||
|
|
||||||
By default [Portainer templates](https://raw.githubusercontent.com/portainer/templates/master/templates.json) will be used but you can also define your own templates.
|
|
||||||
|
|
||||||
Add the `--templates` flag and specify the external location of your templates when starting Portainer:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ 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 the [templates documentation](http://portainer.readthedocs.io/en/stable/templates.html).
|
|
||||||
|
|
||||||
Check our [documentation](http://portainer.readthedocs.io/en/stable/configuration.html) for more configuration options.
|
|
||||||
|
|
||||||
# FAQ
|
|
||||||
|
|
||||||
Be sure to check our [FAQ](http://portainer.readthedocs.io/en/stable/faq.html) if you are missing some information.
|
|
||||||
|
|
||||||
# Limitations
|
|
||||||
|
|
||||||
Portainer has full support for the following Docker versions:
|
|
||||||
|
|
||||||
* Docker 1.10 to Docker 1.12 (including `swarm-mode`)
|
* Docker 1.10 to Docker 1.12 (including `swarm-mode`)
|
||||||
* Docker Swarm >= 1.2.3
|
* Docker Swarm >= 1.2.3
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
// main is the entry point of the program
|
// main is the entry point of the program
|
||||||
func main() {
|
func main() {
|
||||||
kingpin.Version("1.9.2")
|
kingpin.Version("1.9.3")
|
||||||
var (
|
var (
|
||||||
endpoint = kingpin.Flag("host", "Dockerd endpoint").Default("unix:///var/run/docker.sock").Short('H').String()
|
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()
|
addr = kingpin.Flag("bind", "Address and port to serve Portainer").Default(":9000").Short('p').String()
|
||||||
|
|
|
@ -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('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('CONFIG_ENDPOINT', 'settings')
|
||||||
.constant('TEMPLATES_ENDPOINT', 'templates')
|
.constant('TEMPLATES_ENDPOINT', 'templates')
|
||||||
.constant('UI_VERSION', 'v1.9.2');
|
.constant('UI_VERSION', 'v1.9.3');
|
||||||
|
|
|
@ -98,6 +98,9 @@
|
||||||
<span ng-if="container.Ports.length == 0" >-</span>
|
<span ng-if="container.Ports.length == 0" >-</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!containers">
|
||||||
|
<td colspan="8" class="text-center text-muted">Loading...</td>
|
||||||
|
</tr>
|
||||||
<tr ng-if="containers.length == 0">
|
<tr ng-if="containers.length == 0">
|
||||||
<td colspan="8" class="text-center text-muted">No containers available.</td>
|
<td colspan="8" class="text-center text-muted">No containers available.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -8,7 +8,6 @@ function ($scope, Container, ContainerHelper, Info, Settings, Messages, Config)
|
||||||
$scope.sortReverse = false;
|
$scope.sortReverse = false;
|
||||||
$scope.state.selectedItemCount = 0;
|
$scope.state.selectedItemCount = 0;
|
||||||
$scope.swarm_mode = false;
|
$scope.swarm_mode = false;
|
||||||
$scope.containers = [];
|
|
||||||
|
|
||||||
$scope.order = function (sortType) {
|
$scope.order = function (sortType) {
|
||||||
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
|
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
|
||||||
|
@ -34,6 +33,10 @@ function ($scope, Container, ContainerHelper, Info, Settings, Messages, Config)
|
||||||
return model;
|
return model;
|
||||||
});
|
});
|
||||||
$('#loadContainersSpinner').hide();
|
$('#loadContainersSpinner').hide();
|
||||||
|
}, function (e) {
|
||||||
|
$('#loadContainersSpinner').hide();
|
||||||
|
Messages.error("Failure", e, "Unable to retrieve containers");
|
||||||
|
$scope.containers = [];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,9 @@
|
||||||
<td>{{ image.VirtualSize|humansize }}</td>
|
<td>{{ image.VirtualSize|humansize }}</td>
|
||||||
<td>{{ image.Created|getisodatefromtimestamp }}</td>
|
<td>{{ image.Created|getisodatefromtimestamp }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!images">
|
||||||
|
<td colspan="5" class="text-center text-muted">Loading...</td>
|
||||||
|
</tr>
|
||||||
<tr ng-if="images.length == 0">
|
<tr ng-if="images.length == 0">
|
||||||
<td colspan="5" class="text-center text-muted">No images available.</td>
|
<td colspan="5" class="text-center text-muted">No images available.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -5,7 +5,6 @@ function ($scope, $state, Config, Image, Messages) {
|
||||||
$scope.sortType = 'RepoTags';
|
$scope.sortType = 'RepoTags';
|
||||||
$scope.sortReverse = true;
|
$scope.sortReverse = true;
|
||||||
$scope.state.selectedItemCount = 0;
|
$scope.state.selectedItemCount = 0;
|
||||||
$scope.images = [];
|
|
||||||
|
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
Image: '',
|
Image: '',
|
||||||
|
@ -98,6 +97,7 @@ function ($scope, $state, Config, Image, Messages) {
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
$('#loadImagesSpinner').hide();
|
$('#loadImagesSpinner').hide();
|
||||||
Messages.error("Failure", e, "Unable to retrieve images");
|
Messages.error("Failure", e, "Unable to retrieve images");
|
||||||
|
$scope.images = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,9 @@
|
||||||
<td>{{ network.IPAM.Config[0].Subnet ? network.IPAM.Config[0].Subnet : '-' }}</td>
|
<td>{{ network.IPAM.Config[0].Subnet ? network.IPAM.Config[0].Subnet : '-' }}</td>
|
||||||
<td>{{ network.IPAM.Config[0].Gateway ? network.IPAM.Config[0].Gateway : '-' }}</td>
|
<td>{{ network.IPAM.Config[0].Gateway ? network.IPAM.Config[0].Gateway : '-' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!networks">
|
||||||
|
<td colspan="8" class="text-center text-muted">Loading...</td>
|
||||||
|
</tr>
|
||||||
<tr ng-if="networks.length == 0">
|
<tr ng-if="networks.length == 0">
|
||||||
<td colspan="8" class="text-center text-muted">No networks available.</td>
|
<td colspan="8" class="text-center text-muted">No networks available.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -6,8 +6,6 @@ function ($scope, $state, Network, Config, Messages) {
|
||||||
$scope.state.advancedSettings = false;
|
$scope.state.advancedSettings = false;
|
||||||
$scope.sortType = 'Name';
|
$scope.sortType = 'Name';
|
||||||
$scope.sortReverse = false;
|
$scope.sortReverse = false;
|
||||||
$scope.networks = [];
|
|
||||||
|
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
Name: ''
|
Name: ''
|
||||||
};
|
};
|
||||||
|
@ -93,6 +91,7 @@ function ($scope, $state, Network, Config, Messages) {
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
$('#loadNetworksSpinner').hide();
|
$('#loadNetworksSpinner').hide();
|
||||||
Messages.error("Failure", e, "Unable to retrieve networks");
|
Messages.error("Failure", e, "Unable to retrieve networks");
|
||||||
|
$scope.networks = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,12 @@
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!services">
|
||||||
|
<td colspan="4" class="text-center text-muted">Loading...</td>
|
||||||
|
</tr>
|
||||||
|
<tr ng-if="services.length == 0">
|
||||||
|
<td colspan="4" class="text-center text-muted">No services available.</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
angular.module('services', [])
|
angular.module('services', [])
|
||||||
.controller('ServicesController', ['$scope', '$stateParams', '$state', 'Service', 'ServiceHelper', 'Messages',
|
.controller('ServicesController', ['$scope', '$stateParams', '$state', 'Service', 'ServiceHelper', 'Messages',
|
||||||
function ($scope, $stateParams, $state, Service, ServiceHelper, Messages) {
|
function ($scope, $stateParams, $state, Service, ServiceHelper, Messages) {
|
||||||
|
|
||||||
$scope.services = [];
|
|
||||||
$scope.state = {};
|
$scope.state = {};
|
||||||
$scope.state.selectedItemCount = 0;
|
$scope.state.selectedItemCount = 0;
|
||||||
$scope.sortType = 'Name';
|
$scope.sortType = 'Name';
|
||||||
|
@ -77,6 +75,7 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Messages) {
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
$('#loadServicesSpinner').hide();
|
$('#loadServicesSpinner').hide();
|
||||||
Messages.error("Failure", e, "Unable to retrieve services");
|
Messages.error("Failure", e, "Unable to retrieve services");
|
||||||
|
$scope.services = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,14 @@
|
||||||
</rd-widget-header>
|
</rd-widget-header>
|
||||||
<rd-widget-body classes="padding">
|
<rd-widget-body classes="padding">
|
||||||
<div class="template-list">
|
<div class="template-list">
|
||||||
<div ng-repeat="tpl in templates" class="container-template hvr-grow" id="template_{{ $index }}" ng-click="selectTemplate($index)">
|
<div ng-repeat="tpl in templates" class="container-template hvr-underline-from-center" id="template_{{ $index }}" ng-click="selectTemplate($index)">
|
||||||
<img class="logo" ng-src="{{ tpl.logo }}" />
|
<img class="logo" ng-src="{{ tpl.logo }}" />
|
||||||
<div class="title">{{ tpl.title }}</div>
|
<div class="title">{{ tpl.title }}</div>
|
||||||
<div class="description">{{ tpl.description }}</div>
|
<div class="description">{{ tpl.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div ng-if="!templates" class="text-center text-muted">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
<div ng-if="templates.length == 0" class="text-center text-muted">
|
<div ng-if="templates.length == 0" class="text-center text-muted">
|
||||||
No templates available.
|
No templates available.
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
angular.module('templates', [])
|
angular.module('templates', [])
|
||||||
.controller('TemplatesController', ['$scope', '$q', '$state', '$filter', 'Config', 'Info', 'Container', 'ContainerHelper', 'Image', 'Volume', 'Network', 'Templates', 'Messages',
|
.controller('TemplatesController', ['$scope', '$q', '$state', '$filter', 'Config', 'Info', 'Container', 'ContainerHelper', 'Image', 'Volume', 'Network', 'Templates', 'Messages',
|
||||||
function ($scope, $q, $state, $filter, Config, Info, Container, ContainerHelper, Image, Volume, Network, Templates, Messages) {
|
function ($scope, $q, $state, $filter, Config, Info, Container, ContainerHelper, Image, Volume, Network, Templates, Messages) {
|
||||||
$scope.templates = [];
|
|
||||||
$scope.selectedTemplate = null;
|
$scope.selectedTemplate = null;
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
network: "",
|
network: "",
|
||||||
name: ""
|
name: ""
|
||||||
};
|
};
|
||||||
$scope.templates = [];
|
|
||||||
|
|
||||||
var selectedItem = -1;
|
var selectedItem = -1;
|
||||||
|
|
||||||
|
@ -161,6 +159,7 @@ function ($scope, $q, $state, $filter, Config, Info, Container, ContainerHelper,
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
$('#loadTemplatesSpinner').hide();
|
$('#loadTemplatesSpinner').hide();
|
||||||
Messages.error("Failure", e, "Unable to retrieve apps list");
|
Messages.error("Failure", e, "Unable to retrieve apps list");
|
||||||
|
$scope.templates = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,9 @@
|
||||||
<td>{{ volume.Driver }}</td>
|
<td>{{ volume.Driver }}</td>
|
||||||
<td>{{ volume.Mountpoint }}</td>
|
<td>{{ volume.Mountpoint }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="!volumes">
|
||||||
|
<td colspan="4" class="text-center text-muted">Loading...</td>
|
||||||
|
</tr>
|
||||||
<tr ng-if="volumes.length == 0">
|
<tr ng-if="volumes.length == 0">
|
||||||
<td colspan="4" class="text-center text-muted">No volumes available.</td>
|
<td colspan="4" class="text-center text-muted">No volumes available.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -5,8 +5,6 @@ function ($scope, $state, Volume, Messages) {
|
||||||
$scope.state.selectedItemCount = 0;
|
$scope.state.selectedItemCount = 0;
|
||||||
$scope.sortType = 'Name';
|
$scope.sortType = 'Name';
|
||||||
$scope.sortReverse = true;
|
$scope.sortReverse = true;
|
||||||
$scope.volumes = [];
|
|
||||||
|
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
Name: ''
|
Name: ''
|
||||||
};
|
};
|
||||||
|
@ -61,6 +59,7 @@ function ($scope, $state, Volume, Messages) {
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
$('#loadVolumesSpinner').hide();
|
$('#loadVolumesSpinner').hide();
|
||||||
Messages.error("Failure", e, "Unable to retrieve volumes");
|
Messages.error("Failure", e, "Unable to retrieve volumes");
|
||||||
|
$scope.volumes = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fetchVolumes();
|
fetchVolumes();
|
||||||
|
|
|
@ -8,7 +8,7 @@ angular
|
||||||
icon: '='
|
icon: '='
|
||||||
},
|
},
|
||||||
transclude: true,
|
transclude: true,
|
||||||
template: '<div class="widget-header"><div class="row"><span class="pull-left"><img class="custom-header-ico" ng-src="{{icon}}"></img> <span class="small text-muted"> {{title}} </span> </span><span class="pull-right col-xs-6 col-sm-4" ng-transclude></span></div></div>',
|
template: '<div class="widget-header"><div class="row"><span class="pull-left"><img class="custom-header-ico" ng-src="{{icon}}"></img> <span class="text-muted"> {{title}} </span> </span><span class="pull-right col-xs-6 col-sm-4" ng-transclude></span></div></div>',
|
||||||
restrict: 'E'
|
restrict: 'E'
|
||||||
};
|
};
|
||||||
return directive;
|
return directive;
|
||||||
|
|
|
@ -217,16 +217,67 @@ input[type="radio"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-header-ico {
|
.custom-header-ico {
|
||||||
max-width: 16px;
|
max-width: 32px;
|
||||||
max-height: 16px;
|
max-height: 32px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-responsive {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1107px) {
|
||||||
|
.btn-responsive {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.42857143;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Underline From Center */
|
||||||
|
.hvr-underline-from-center {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
|
transform: translateZ(0);
|
||||||
|
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hvr-underline-from-center:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
left: 50%;
|
||||||
|
right: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
background: #85898b;
|
||||||
|
height: 2px;
|
||||||
|
-webkit-transition-property: left, right;
|
||||||
|
transition-property: left, right;
|
||||||
|
-webkit-transition-duration: 0.3s;
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
-webkit-transition-timing-function: ease-out;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
.hvr-underline-from-center:hover:before, .hvr-underline-from-center:focus:before, .hvr-underline-from-center:active:before {
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-template {
|
.container-template {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
margin: 10px;
|
margin: 15px;
|
||||||
padding: 10px;
|
padding: 5px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -259,20 +310,5 @@ input[type="radio"] {
|
||||||
.container-template .description {
|
.container-template .description {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
margin-bottom: 5px;
|
||||||
|
|
||||||
.btn-responsive {
|
|
||||||
padding: 5px 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.5;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 1107px) {
|
|
||||||
.btn-responsive {
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.42857143;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "portainer",
|
"name": "portainer",
|
||||||
"version": "1.9.2",
|
"version": "1.9.3",
|
||||||
"homepage": "https://github.com/portainer/portainer",
|
"homepage": "https://github.com/portainer/portainer",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Anthony Lapenna <anthony.lapenna at gmail dot com>"
|
"Anthony Lapenna <anthony.lapenna at gmail dot com>"
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
"bootstrap": "~3.3.6",
|
"bootstrap": "~3.3.6",
|
||||||
"font-awesome": "~4.6.3",
|
"font-awesome": "~4.6.3",
|
||||||
"filesize": "~3.3.0",
|
"filesize": "~3.3.0",
|
||||||
"Hover": "2.0.2",
|
|
||||||
"jquery": "1.11.1",
|
"jquery": "1.11.1",
|
||||||
"jquery.gritter": "1.7.4",
|
"jquery.gritter": "1.7.4",
|
||||||
"lodash": "4.12.0",
|
"lodash": "4.12.0",
|
||||||
|
|
|
@ -88,8 +88,7 @@ module.exports = function (grunt) {
|
||||||
'bower_components/font-awesome/css/font-awesome.min.css',
|
'bower_components/font-awesome/css/font-awesome.min.css',
|
||||||
'bower_components/rdash-ui/dist/css/rdash.min.css',
|
'bower_components/rdash-ui/dist/css/rdash.min.css',
|
||||||
'bower_components/angular-ui-select/dist/select.min.css',
|
'bower_components/angular-ui-select/dist/select.min.css',
|
||||||
'bower_components/xterm.js/dist/xterm.css',
|
'bower_components/xterm.js/dist/xterm.css'
|
||||||
'bower_components/Hover/css/hover-min.css'
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
clean: {
|
clean: {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Portainer.io",
|
"author": "Portainer.io",
|
||||||
"name": "portainer",
|
"name": "portainer",
|
||||||
"homepage": "http://portainer.io",
|
"homepage": "http://portainer.io",
|
||||||
"version": "1.9.2",
|
"version": "1.9.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:portainer/portainer.git"
|
"url": "git@github.com:portainer/portainer.git"
|
||||||
|
|
Loading…
Reference in New Issue