Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65cde27334 | |||
| 2275467bdc | |||
| 688b15fb4b | |||
| 3362ba0c8c | |||
| 39cf4d75ff | |||
| 13d8d38bf9 | |||
| e51246ee78 | |||
| 4ab580923f | |||
| 547511c8aa | |||
| 8a101f67f6 | |||
| 3ee2e20f8e | |||
| 6b9f3dad7a | |||
| a2d41e5316 | |||
| 3548f0db6f | |||
| 521cc3d6ab | |||
| b044aa9a84 | |||
| d9262d4b7f | |||
| efc3154617 | |||
| d68708add7 | |||
| 9bef7cd69f |
@@ -127,6 +127,7 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||
if err == portainer.ErrSettingsNotFound {
|
||||
settings := &portainer.Settings{
|
||||
LogoURL: *flags.Logo,
|
||||
DisplayDonationHeader: true,
|
||||
DisplayExternalContributors: false,
|
||||
AuthenticationMethod: portainer.AuthenticationInternal,
|
||||
LDAPSettings: portainer.LDAPSettings{
|
||||
|
||||
@@ -46,6 +46,7 @@ func NewSettingsHandler(bouncer *security.RequestBouncer) *SettingsHandler {
|
||||
type (
|
||||
publicSettingsResponse struct {
|
||||
LogoURL string `json:"LogoURL"`
|
||||
DisplayDonationHeader bool `json:"DisplayDonationHeader"`
|
||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||
AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"`
|
||||
AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"`
|
||||
@@ -56,6 +57,7 @@ type (
|
||||
TemplatesURL string `valid:"required"`
|
||||
LogoURL string `valid:""`
|
||||
BlackListedLabels []portainer.Pair `valid:""`
|
||||
DisplayDonationHeader bool `valid:""`
|
||||
DisplayExternalContributors bool `valid:""`
|
||||
AuthenticationMethod int `valid:"required"`
|
||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||
@@ -90,6 +92,7 @@ func (handler *SettingsHandler) handleGetPublicSettings(w http.ResponseWriter, r
|
||||
|
||||
publicSettings := &publicSettingsResponse{
|
||||
LogoURL: settings.LogoURL,
|
||||
DisplayDonationHeader: settings.DisplayDonationHeader,
|
||||
DisplayExternalContributors: settings.DisplayExternalContributors,
|
||||
AuthenticationMethod: settings.AuthenticationMethod,
|
||||
AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers,
|
||||
@@ -118,6 +121,7 @@ func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http
|
||||
TemplatesURL: req.TemplatesURL,
|
||||
LogoURL: req.LogoURL,
|
||||
BlackListedLabels: req.BlackListedLabels,
|
||||
DisplayDonationHeader: req.DisplayDonationHeader,
|
||||
DisplayExternalContributors: req.DisplayExternalContributors,
|
||||
LDAPSettings: req.LDAPSettings,
|
||||
AllowBindMountsForRegularUsers: req.AllowBindMountsForRegularUsers,
|
||||
|
||||
+2
-1
@@ -73,6 +73,7 @@ type (
|
||||
TemplatesURL string `json:"TemplatesURL"`
|
||||
LogoURL string `json:"LogoURL"`
|
||||
BlackListedLabels []Pair `json:"BlackListedLabels"`
|
||||
DisplayDonationHeader bool `json:"DisplayDonationHeader"`
|
||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||
AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"`
|
||||
LDAPSettings LDAPSettings `json:"LDAPSettings"`
|
||||
@@ -389,7 +390,7 @@ type (
|
||||
|
||||
const (
|
||||
// APIVersion is the version number of the Portainer API.
|
||||
APIVersion = "1.15.1"
|
||||
APIVersion = "1.15.3"
|
||||
// DBVersion is the version number of the Portainer database.
|
||||
DBVersion = 6
|
||||
// DefaultTemplatesURL represents the default URL for the templates definitions.
|
||||
|
||||
+14
-2
@@ -56,7 +56,7 @@ info:
|
||||
|
||||
**NOTE**: You can find more information on how to query the Docker API in the [Docker official documentation](https://docs.docker.com/engine/api/v1.30/) as well as in [this Portainer example](https://gist.github.com/deviantony/77026d402366b4b43fa5918d41bc42f8).
|
||||
|
||||
version: "1.15.1"
|
||||
version: "1.15.3"
|
||||
title: "Portainer API"
|
||||
contact:
|
||||
email: "info@portainer.io"
|
||||
@@ -1869,7 +1869,7 @@ definitions:
|
||||
description: "Is analytics enabled"
|
||||
Version:
|
||||
type: "string"
|
||||
example: "1.15.1"
|
||||
example: "1.15.3"
|
||||
description: "Portainer API version"
|
||||
PublicSettingsInspectResponse:
|
||||
type: "object"
|
||||
@@ -1880,6 +1880,10 @@ definitions:
|
||||
description: "URL to a logo that will be displayed on the login page as well\
|
||||
\ as on top of the sidebar. Will use default Portainer logo when value is\
|
||||
\ empty string"
|
||||
DisplayDonationHeader:
|
||||
type: "boolean"
|
||||
example: true
|
||||
description: "Whether to display or not the donation message in the header."\
|
||||
DisplayExternalContributors:
|
||||
type: "boolean"
|
||||
example: false
|
||||
@@ -1983,6 +1987,10 @@ definitions:
|
||||
\ when querying containers"
|
||||
items:
|
||||
$ref: "#/definitions/Settings_BlackListedLabels"
|
||||
DisplayDonationHeader:
|
||||
type: "boolean"
|
||||
example: true
|
||||
description: "Whether to display or not the donation message in the header."
|
||||
DisplayExternalContributors:
|
||||
type: "boolean"
|
||||
example: false
|
||||
@@ -2398,6 +2406,10 @@ definitions:
|
||||
\ when querying containers"
|
||||
items:
|
||||
$ref: "#/definitions/Settings_BlackListedLabels"
|
||||
DisplayDonationHeader:
|
||||
type: "boolean"
|
||||
example: true
|
||||
description: "Whether to display or not the donation message in the header."
|
||||
DisplayExternalContributors:
|
||||
type: "boolean"
|
||||
example: false
|
||||
|
||||
@@ -9,6 +9,7 @@ angular.module('portainer', [
|
||||
'LocalStorageModule',
|
||||
'angular-jwt',
|
||||
'angular-google-analytics',
|
||||
'angular-loading-bar',
|
||||
'portainer.templates',
|
||||
'portainer.filters',
|
||||
'portainer.rest',
|
||||
|
||||
+10
-1
@@ -1,5 +1,5 @@
|
||||
angular.module('portainer')
|
||||
.run(['$rootScope', '$state', 'Authentication', 'authManager', 'StateManager', 'EndpointProvider', 'Notifications', 'Analytics', function ($rootScope, $state, Authentication, authManager, StateManager, EndpointProvider, Notifications, Analytics) {
|
||||
.run(['$rootScope', '$state', 'Authentication', 'authManager', 'StateManager', 'EndpointProvider', 'Notifications', 'Analytics', 'cfpLoadingBar', function ($rootScope, $state, Authentication, authManager, StateManager, EndpointProvider, Notifications, Analytics, cfpLoadingBar) {
|
||||
'use strict';
|
||||
|
||||
EndpointProvider.initialize();
|
||||
@@ -18,6 +18,15 @@ angular.module('portainer')
|
||||
});
|
||||
|
||||
$rootScope.$state = $state;
|
||||
|
||||
// Workaround to prevent the loading bar from going backward
|
||||
// https://github.com/chieffancypants/angular-loading-bar/issues/273
|
||||
var originalSet = cfpLoadingBar.set;
|
||||
cfpLoadingBar.set = function overrideSet(n) {
|
||||
if (n > cfpLoadingBar.status()) {
|
||||
originalSet.apply(cfpLoadingBar, arguments);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="About">
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
About Portainer
|
||||
</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<b>Portainer</b> is a <a href="https://github.com/portainer/portainer/blob/develop/LICENSE" target="_blank" >free and open-source software</a> brought to you with <span class="menu-icon fa fa-heart red-icon "></span> by <a href="https://portainer.io/" target="_blank">portainer.io</a> and <a href="https://github.com/portainer/portainer/graphs/contributors" target="_blank">contributors.</a>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header title="Help support portainer" icon="fa-heartbeat"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<div class="small" style="line-height:1.65;">
|
||||
<p>
|
||||
It is a community effort to make <b>Portainer</b> as feature-rich as simple it is to deploy and use. We need all the help we can get!
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Fund our work</u>
|
||||
<ul>
|
||||
<li>Become a <a href="https://www.patreon.com/Portainerio" target="_blank"><i class="fa fa-money" aria-hidden="true"></i> patron</a></li>
|
||||
<li>Consider a <a href="https://portainer.io/support.html" target="_blank">paid support plan</a></li>
|
||||
<li>Make a <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YHXZJQNJQ36H6" target="_blank"><i class="fa fa-paypal" aria-hidden="true"></i> donation</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Contribute</u>
|
||||
<ul>
|
||||
<li>Found a bug or got a feature idea? Let's talk about it on <a href="https://github.com/portainer/portainer/issues" target="_blank"><i class="fa fa-github" aria-hidden="true"></i> Github</a></li>
|
||||
<li>Follow our <a href="https://portainer.readthedocs.io/en/latest/contribute.html" target="_blank">contribution guidelines</a> to build it locally and make a <a target="_blank" href="https://github.com/portainer/portainer/compare"><i class="fa fa-github" aria-hidden="true"></i> pull request</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Spread the word</u>
|
||||
<ul>
|
||||
<li>Talk to your friends and colleagues about how awesome Portainer is!</li>
|
||||
<li>Follow us on <a href="https://twitter.com/portainerio" target="_blank"><i class="fa fa-twitter" aria-hidden="true"></i> Twitter</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header title="Support and services" icon="fa-building-o"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<div class="small" style="line-height:1.65;">
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Documentation</u>
|
||||
<ul>
|
||||
<li>Checkout our <a target="_blank" href="http://portainer.readthedocs.io"><i class="fa fa-book" aria-hidden="true"></i> online documentation</a></li>
|
||||
<li>Be sure to have a look at our <a href="https://portainer.readthedocs.io/en/latest/faq.html" target="_blank">FAQ</a> and our list of <a href="https://github.com/portainer/portainer/issues" target="_blank">open issues</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Community support</u>
|
||||
<ul>
|
||||
<li>Join us on <a href="https://portainer.io/slack/" target="_blank"><i class="fa fa-slack" aria-hidden="true"></i> Slack</a></li>
|
||||
<li>We're also on <a href="https://gitter.im/portainer/Lobby" target="_blank"><i class="fa fa-github-alt" aria-hidden="true"></i> Gitter</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<i class="fa fa-chevron-circle-right" aria-hidden="true"></i> <u>Services</u>
|
||||
<ul>
|
||||
<li>Find out more about our <a href="https://portainer.io/support.html" target="_blank">consulting and commercial support plans</a></li>
|
||||
<li>We also propose a fund-a-feature plan, reach out to us at <a target="_blank" href="mailto:info@portainer.io"><i class="fa fa-envelope-o" aria-hidden="true"></i> portainer.io</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header title="Limitations" icon="fa-plug"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<div class="small">
|
||||
Portainer has full support for Docker >=1.10 and Docker Swarm >= 1.2.3, and partial support for Docker 1.9 (some features may not be available).
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="config({id: config.Id})" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="configs">Configs</a> > <a ui-sref="config({id: config.Id})">{{ config.Name }}</a>
|
||||
|
||||
@@ -3,7 +3,6 @@ angular.module('config', [])
|
||||
function ($scope, $transition$, $state, $document, ConfigService, Notifications, CodeMirrorService) {
|
||||
|
||||
$scope.removeConfig = function removeConfig(configId) {
|
||||
$('#loadingViewSpinner').show();
|
||||
ConfigService.remove(configId)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Config successfully removed');
|
||||
@@ -11,9 +10,6 @@ function ($scope, $transition$, $state, $document, ConfigService, Notifications,
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove config');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -27,7 +23,6 @@ function ($scope, $transition$, $state, $document, ConfigService, Notifications,
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
ConfigService.config($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.config = data;
|
||||
@@ -35,9 +30,6 @@ function ($scope, $transition$, $state, $document, ConfigService, Notifications,
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve config details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="configs" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Configs</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -52,7 +51,7 @@
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="config in (state.filteredConfigs = ( configs | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: pagination_count))">
|
||||
<tr dir-paginate="config in (state.filteredConfigs = ( configs | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: pagination_count))" ng-class="{active: config.Checked}">
|
||||
<td><input type="checkbox" ng-model="config.Checked" ng-change="selectItem(config)"/></td>
|
||||
<td><a ui-sref="config({id: config.Id})">{{ config.Name }}</a></td>
|
||||
<td>{{ config.CreatedAt | getisodate }}</td>
|
||||
|
||||
@@ -30,17 +30,8 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
|
||||
};
|
||||
|
||||
$scope.removeAction = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.configs, function (config) {
|
||||
if (config.Checked) {
|
||||
counter = counter + 1;
|
||||
ConfigService.remove(config.Id)
|
||||
.then(function success() {
|
||||
Notifications.success('Config deleted', config.Id);
|
||||
@@ -49,16 +40,12 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove config');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
ConfigService.configs()
|
||||
.then(function success(data) {
|
||||
$scope.configs = data;
|
||||
@@ -66,9 +53,6 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
|
||||
.catch(function error(err) {
|
||||
$scope.configs = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve configs');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,330 +1,336 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Container details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="containers">Containers</a> > <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a>
|
||||
</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-cogs" title="Actions"></rd-widget-header>
|
||||
<rd-widget-body classes="padding">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button class="btn btn-success" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
|
||||
<button class="btn btn-danger" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
|
||||
<button class="btn btn-danger" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
|
||||
<button class="btn btn-primary" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Restart</button>
|
||||
<button class="btn btn-primary" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
|
||||
<button class="btn btn-primary" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
|
||||
<button class="btn btn-danger" ng-click="confirmRemove()"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button>
|
||||
<button class="btn btn-danger" ng-click="recreate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Recreate</button>
|
||||
<button class="btn btn-primary" ng-click="duplicate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-files-o space-right" aria-hidden="true"></i>Duplicate/Edit</button>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container status"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>{{ container.Id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td ng-if="!container.edit">
|
||||
{{ container.Name|trimcontainername }}
|
||||
<a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
|
||||
</td>
|
||||
<td ng-if="container.edit">
|
||||
<form ng-submit="renameContainer()">
|
||||
<input type="text" class="containerNameInput" ng-model="container.newContainerName">
|
||||
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
|
||||
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.NetworkSettings.IPAddress">
|
||||
<td>IP address</td>
|
||||
<td>{{ container.NetworkSettings.IPAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
|
||||
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
|
||||
{{ container.State|getstatetext }} since {{ activityTime }}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Created</td>
|
||||
<td>{{ container.Created|getisodate }}</td>
|
||||
</tr>
|
||||
<tr ng-if="container.State.Running">
|
||||
<td>Start time</td>
|
||||
<td>{{ container.State.StartedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
|
||||
<td>Finished</td>
|
||||
<td>{{ container.State.FinishedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="stats({id: container.Id})"><i class="fa fa-area-chart space-right" aria-hidden="true"></i>Stats</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="containerlogs({id: container.Id})"><i class="fa fa-exclamation-circle space-right" aria-hidden="true"></i>Logs</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="console({id: container.Id})"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="inspect({id: container.Id})"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- access-control-panel -->
|
||||
<por-access-control-panel
|
||||
ng-if="container && applicationState.application.authentication"
|
||||
resource-id="container.Id"
|
||||
resource-control="container.ResourceControl"
|
||||
resource-type="'container'">
|
||||
</por-access-control-panel>
|
||||
<!-- !access-control-panel -->
|
||||
|
||||
<div ng-if="container.State.Health" class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container health"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<i ng-class="{'healthy': 'fa fa-heartbeat space-right green-icon', 'unhealthy': 'fa fa-heartbeat space-right red-icon', 'starting': 'fa fa-heartbeat space-right orange-icon'}[container.State.Health.Status]"></i>
|
||||
{{ container.State.Health.Status }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Failure count</td>
|
||||
<td>{{ container.State.Health.FailingStreak }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last output</td>
|
||||
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<!-- tag-description -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">
|
||||
You can create an image from this container, this allows you to backup important data or save
|
||||
helpful configurations. You'll be able to spin up another container based on this image afterward.
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-cogs" title="Actions"></rd-widget-header>
|
||||
<rd-widget-body classes="padding">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button class="btn btn-success btn-responsive" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
|
||||
<button class="btn btn-danger btn-responsive" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
|
||||
<button class="btn btn-danger btn-responsive" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
|
||||
<button class="btn btn-primary btn-responsive" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Restart</button>
|
||||
<button class="btn btn-primary btn-responsive" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
|
||||
<button class="btn btn-primary btn-responsive" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
|
||||
<button class="btn btn-danger btn-responsive" ng-click="confirmRemove()"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button>
|
||||
</div>
|
||||
<!-- !tag-description -->
|
||||
<!-- image-and-registry -->
|
||||
<div class="form-group">
|
||||
<por-image-registry image="config.Image" registry="config.Registry"></por-image-registry>
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button class="btn btn-danger btn-responsive" ng-click="recreate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Recreate</button>
|
||||
<button class="btn btn-primary btn-responsive" ng-click="duplicate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-files-o space-right" aria-hidden="true"></i>Duplicate/Edit</button>
|
||||
</div>
|
||||
<!-- !image-and-registry -->
|
||||
<!-- tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button>
|
||||
<i id="createImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container details"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
|
||||
</tr>
|
||||
<tr ng-if="portBindings.length > 0">
|
||||
<td>Port configuration</td>
|
||||
<td>
|
||||
<div ng-repeat="portMapping in portBindings">
|
||||
{{ portMapping.container }} <i class="fa fa-long-arrow-right"></i> {{ portMapping.host }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CMD</td>
|
||||
<td><code>{{ container.Config.Cmd|command }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENV</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="var in container.Config.Env track by $index">
|
||||
<td>{{ var|key: '=' }}</td>
|
||||
<td>{{ var|value: '=' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="!(container.Config.Labels | emptyobject)">
|
||||
<td>Labels</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="(k, v) in container.Config.Labels">
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ v }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.HostConfig.RestartPolicy.Name !== 'no'">
|
||||
<td>Restart policies</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr>
|
||||
<td class="col-md-3">Name</td>
|
||||
<td>{{ container.HostConfig.RestartPolicy.Name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="col-md-3">MaximumRetryCount</td>
|
||||
<td>
|
||||
{{ container.HostConfig.RestartPolicy.MaximumRetryCount }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container status"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>{{ container.Id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td ng-if="!container.edit">
|
||||
{{ container.Name|trimcontainername }}
|
||||
<a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
|
||||
</td>
|
||||
<td ng-if="container.edit">
|
||||
<form ng-submit="renameContainer()">
|
||||
<input type="text" class="containerNameInput" ng-model="container.newContainerName">
|
||||
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
|
||||
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.NetworkSettings.IPAddress">
|
||||
<td>IP address</td>
|
||||
<td>{{ container.NetworkSettings.IPAddress }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
|
||||
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
|
||||
{{ container.State|getstatetext }} since {{ activityTime }}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Created</td>
|
||||
<td>{{ container.Created|getisodate }}</td>
|
||||
</tr>
|
||||
<tr ng-if="container.State.Running">
|
||||
<td>Start time</td>
|
||||
<td>{{ container.State.StartedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
|
||||
<td>Finished</td>
|
||||
<td>{{ container.State.FinishedAt|getisodate }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="stats({id: container.Id})"><i class="fa fa-area-chart space-right" aria-hidden="true"></i>Stats</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="containerlogs({id: container.Id})"><i class="fa fa-exclamation-circle space-right" aria-hidden="true"></i>Logs</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="console({id: container.Id})"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
|
||||
<a class="btn btn-outline-secondary" type="button" ui-sref="inspect({id: container.Id})"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="container.Mounts.length > 0">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Host/volume</th>
|
||||
<th>Path in container</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="vol in container.Mounts">
|
||||
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
|
||||
<td ng-if="vol.Type === 'volume'"><a ui-sref="volume({id: vol.Name})">{{ vol.Name }}</a></td>
|
||||
<td>{{ vol.Destination }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
<!-- access-control-panel -->
|
||||
<por-access-control-panel
|
||||
ng-if="container && applicationState.application.authentication"
|
||||
resource-id="container.Id"
|
||||
resource-control="container.ResourceControl"
|
||||
resource-type="'container'">
|
||||
</por-access-control-panel>
|
||||
<!-- !access-control-panel -->
|
||||
|
||||
<div ng-if="container.State.Health" class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container health"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<i ng-class="{'healthy': 'fa fa-heartbeat space-right green-icon', 'unhealthy': 'fa fa-heartbeat space-right red-icon', 'starting': 'fa fa-heartbeat space-right orange-icon'}[container.State.Health.Status]"></i>
|
||||
{{ container.State.Health.Status }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Failure count</td>
|
||||
<td>{{ container.State.Health.FailingStreak }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last output</td>
|
||||
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-sitemap" title="Connected networks">
|
||||
<div class="pull-right">
|
||||
Items per page:
|
||||
<select ng-model="state.pagination_count" ng-change="changePaginationCount()">
|
||||
<option value="0">All</option>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Network Name</th>
|
||||
<th>IP Address</th>
|
||||
<th>Gateway</th>
|
||||
<th>MacAddress</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="(key, value) in container.NetworkSettings.Networks | itemsPerPage: state.pagination_count">
|
||||
<td><a ui-sref="network({id: value.NetworkID})">{{ key }}</a></td>
|
||||
<td>{{ value.IPAddress || '-' }}</td>
|
||||
<td>{{ value.Gateway || '-' }}</td>
|
||||
<td>{{ value.MacAddress || '-' }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-xs btn-danger" ng-click="containerLeaveNetwork(container, value.NetworkID)"><i class="fa fa-trash space-right" aria-hidden="true"></i>Leave Network</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="(container.NetworkSettings.Networks | emptyobject)">
|
||||
<td colspan="5" class="text-center text-muted">No networks connected.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pagination-controls">
|
||||
<dir-pagination-controls></dir-pagination-controls>
|
||||
</div>
|
||||
<hr />
|
||||
<form class="form-horizontal">
|
||||
<!-- network-input -->
|
||||
<div class="row">
|
||||
<label for="container_network" class="col-sm-3 col-lg-2 control-label text-left">Join a Network</label>
|
||||
<div class="col-sm-5 col-lg-4">
|
||||
<select class="form-control" ng-model="selectedNetwork" id="container_network">
|
||||
<option selected disabled hidden value="">Select a network</option>
|
||||
<option ng-repeat="net in availableNetworks" ng-value="net.Id">{{ net.Name }}</option>
|
||||
</select>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<!-- tag-description -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">
|
||||
You can create an image from this container, this allows you to backup important data or save
|
||||
helpful configurations. You'll be able to spin up another container based on this image afterward.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!selectedNetwork" ng-click="containerJoinNetwork(container, selectedNetwork)">Join Network</button>
|
||||
<!-- !tag-description -->
|
||||
<!-- image-and-registry -->
|
||||
<div class="form-group">
|
||||
<por-image-registry image="config.Image" registry="config.Registry"></por-image-registry>
|
||||
</div>
|
||||
<!-- !image-and-registry -->
|
||||
<!-- tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-server" title="Container details"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
|
||||
</tr>
|
||||
<tr ng-if="portBindings.length > 0">
|
||||
<td>Port configuration</td>
|
||||
<td>
|
||||
<div ng-repeat="portMapping in portBindings">
|
||||
{{ portMapping.container }} <i class="fa fa-long-arrow-right"></i> {{ portMapping.host }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CMD</td>
|
||||
<td><code>{{ container.Config.Cmd|command }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENV</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="var in container.Config.Env track by $index">
|
||||
<td>{{ var|key: '=' }}</td>
|
||||
<td>{{ var|value: '=' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="!(container.Config.Labels | emptyobject)">
|
||||
<td>Labels</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="(k, v) in container.Config.Labels">
|
||||
<td>{{ k }}</td>
|
||||
<td>{{ v }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="container.HostConfig.RestartPolicy.Name !== 'no'">
|
||||
<td>Restart policies</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr>
|
||||
<td class="col-md-3">Name</td>
|
||||
<td>{{ container.HostConfig.RestartPolicy.Name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="col-md-3">MaximumRetryCount</td>
|
||||
<td>
|
||||
{{ container.HostConfig.RestartPolicy.MaximumRetryCount }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="container.Mounts.length > 0">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Host/volume</th>
|
||||
<th>Path in container</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="vol in container.Mounts">
|
||||
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
|
||||
<td ng-if="vol.Type === 'volume'"><a ui-sref="volume({id: vol.Name})">{{ vol.Name }}</a></td>
|
||||
<td>{{ vol.Destination }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-sitemap" title="Connected networks">
|
||||
<div class="pull-right">
|
||||
Items per page:
|
||||
<select ng-model="state.pagination_count" ng-change="changePaginationCount()">
|
||||
<option value="0">All</option>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Network Name</th>
|
||||
<th>IP Address</th>
|
||||
<th>Gateway</th>
|
||||
<th>MacAddress</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="(key, value) in container.NetworkSettings.Networks | itemsPerPage: state.pagination_count">
|
||||
<td><a ui-sref="network({id: value.NetworkID})">{{ key }}</a></td>
|
||||
<td>{{ value.IPAddress || '-' }}</td>
|
||||
<td>{{ value.Gateway || '-' }}</td>
|
||||
<td>{{ value.MacAddress || '-' }}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-xs btn-danger" ng-disabled="state.leaveNetworkInProgress" button-spinner="state.leaveNetworkInProgress" ng-click="containerLeaveNetwork(container, value.NetworkID)">
|
||||
<span ng-hide="state.leaveNetworkInProgress"><i class="fa fa-trash space-right" aria-hidden="true"></i> Leave network</span>
|
||||
<span ng-show="state.leaveNetworkInProgress">Leaving network...</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="(container.NetworkSettings.Networks | emptyobject)">
|
||||
<td colspan="5" class="text-center text-muted">No networks connected.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pagination-controls">
|
||||
<dir-pagination-controls></dir-pagination-controls>
|
||||
</div>
|
||||
<hr />
|
||||
<form class="form-horizontal">
|
||||
<!-- network-input -->
|
||||
<div class="row">
|
||||
<label for="container_network" class="col-sm-3 col-lg-2 control-label text-left">Join a Network</label>
|
||||
<div class="col-sm-5 col-lg-4">
|
||||
<select class="form-control" ng-model="selectedNetwork" id="container_network">
|
||||
<option selected disabled hidden value="">Select a network</option>
|
||||
<option ng-repeat="net in availableNetworks" ng-value="net.Id">{{ net.Name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.joinNetworkInProgress || !selectedNetwork" ng-click="containerJoinNetwork(container, selectedNetwork)" button-spinner="state.joinNetworkInProgress">
|
||||
<span ng-hide="state.joinNetworkInProgress">Join network</span>
|
||||
<span ng-show="state.joinNetworkInProgress">Joining network...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,15 +7,17 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
Image: '',
|
||||
Registry: ''
|
||||
};
|
||||
$scope.state = {};
|
||||
$scope.state.pagination_count = Pagination.getPaginationCount('container_networks');
|
||||
$scope.state = {
|
||||
joinNetworkInProgress: false,
|
||||
leaveNetworkInProgress: false,
|
||||
pagination_count: Pagination.getPaginationCount('container_networks')
|
||||
};
|
||||
|
||||
$scope.changePaginationCount = function() {
|
||||
Pagination.setPaginationCount('container_networks', $scope.state.pagination_count);
|
||||
};
|
||||
|
||||
var update = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.get({id: $transition$.params().id}, function (d) {
|
||||
var container = new ContainerDetailsViewModel(d);
|
||||
$scope.container = container;
|
||||
@@ -41,15 +43,12 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
}
|
||||
});
|
||||
}
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to retrieve container info');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.start = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.start({id: $scope.container.Id}, {}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container started', $transition$.params().id);
|
||||
@@ -60,7 +59,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.stop = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.stop({id: $transition$.params().id}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container stopped', $transition$.params().id);
|
||||
@@ -71,7 +69,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.kill = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.kill({id: $transition$.params().id}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container killed', $transition$.params().id);
|
||||
@@ -82,23 +79,19 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.commit = function () {
|
||||
$('#createImageSpinner').show();
|
||||
var image = $scope.config.Image;
|
||||
var registry = $scope.config.Registry;
|
||||
var imageConfig = ImageHelper.createImageConfigForCommit(image, registry.URL);
|
||||
ContainerCommit.commit({id: $transition$.params().id, tag: imageConfig.tag, repo: imageConfig.repo}, function (d) {
|
||||
$('#createImageSpinner').hide();
|
||||
update();
|
||||
Notifications.success('Container commited', $transition$.params().id);
|
||||
}, function (e) {
|
||||
$('#createImageSpinner').hide();
|
||||
update();
|
||||
Notifications.error('Failure', e, 'Unable to commit container');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.pause = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.pause({id: $transition$.params().id}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container paused', $transition$.params().id);
|
||||
@@ -109,7 +102,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.unpause = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.unpause({id: $transition$.params().id}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container unpaused', $transition$.params().id);
|
||||
@@ -138,7 +130,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.remove = function(cleanAssociatedVolumes) {
|
||||
$('#loadingViewSpinner').show();
|
||||
ContainerService.remove($scope.container, cleanAssociatedVolumes)
|
||||
.then(function success() {
|
||||
Notifications.success('Container successfully removed');
|
||||
@@ -146,14 +137,10 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove container');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.restart = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.restart({id: $transition$.params().id}, function (d) {
|
||||
update();
|
||||
Notifications.success('Container restarted', $transition$.params().id);
|
||||
@@ -180,19 +167,18 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) {
|
||||
$('#loadingViewSpinner').show();
|
||||
$scope.state.leaveNetworkInProgress = true;
|
||||
Network.disconnect({id: networkId}, { Container: $transition$.params().id, Force: false }, function (d) {
|
||||
if (container.message) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Error', d, 'Unable to disconnect container from network');
|
||||
} else {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.success('Container left network', $transition$.params().id);
|
||||
$state.go('container', {id: $transition$.params().id}, {reload: true});
|
||||
}
|
||||
$scope.state.leaveNetworkInProgress = false;
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to disconnect container from network');
|
||||
$scope.state.leaveNetworkInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -219,7 +205,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
function recreateContainer(pullImage) {
|
||||
$('#loadingViewSpinner').show();
|
||||
var container = $scope.container;
|
||||
var config = ContainerHelper.configFromContainer(container.Model);
|
||||
ContainerService.remove(container, true)
|
||||
@@ -254,9 +239,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to re-create container');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -272,19 +254,18 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
|
||||
};
|
||||
|
||||
$scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) {
|
||||
$('#joinNetworkSpinner').show();
|
||||
$scope.state.joinNetworkInProgress = true;
|
||||
Network.connect({id: networkId}, { Container: $transition$.params().id }, function (d) {
|
||||
if (container.message) {
|
||||
$('#joinNetworkSpinner').hide();
|
||||
Notifications.error('Error', d, 'Unable to connect container to network');
|
||||
} else {
|
||||
$('#joinNetworkSpinner').hide();
|
||||
Notifications.success('Container joined network', $transition$.params().id);
|
||||
$state.go('container', {id: $transition$.params().id}, {reload: true});
|
||||
}
|
||||
$scope.state.joinNetworkInProgress = false;
|
||||
}, function (e) {
|
||||
$('#joinNetworkSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to connect container to network');
|
||||
$scope.state.joinNetworkInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Container console">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Container console"></rd-header-title>
|
||||
<rd-header-content ng-if="state.loaded">
|
||||
<a ui-sref="containers">Containers</a> > <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> > Console
|
||||
</rd-header-content>
|
||||
@@ -10,11 +8,7 @@
|
||||
<div class="row" ng-if="state.loaded">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-terminal" title="Console">
|
||||
<div class="pull-right">
|
||||
<i id="loadConsoleSpinner" class="fa fa-cog fa-2x fa-spin" style="margin-top: 5px; display: none;"></i>
|
||||
</div>
|
||||
</rd-widget-header>
|
||||
<rd-widget-header icon="fa-terminal" title="Console"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<div ng-if="!state.connected">
|
||||
@@ -54,8 +48,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-lg-offset-1 col-sm-offset-2 col-lg-11 col-sm-10">
|
||||
<button type="button" class="btn btn-primary" ng-click="connect()">Connect</button>
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary" ng-disabled="state.connected" button-spinner="state.connected" ng-click="connect()">
|
||||
<span ng-hide="state.leaveNetworkInProgress">Connect</span>
|
||||
<span ng-show="state.leaveNetworkInProgress">Connecting...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
angular.module('containerConsole', [])
|
||||
.controller('ContainerConsoleController', ['$scope', '$transition$', 'Container', 'Image', 'EndpointProvider', 'Notifications', 'ContainerHelper', 'ContainerService', 'ExecService',
|
||||
function ($scope, $transition$, Container, Image, EndpointProvider, Notifications, ContainerHelper, ContainerService, ExecService) {
|
||||
$scope.state = {};
|
||||
$scope.state.loaded = false;
|
||||
$scope.state.connected = false;
|
||||
$scope.state = {
|
||||
loaded: false,
|
||||
connected: false
|
||||
};
|
||||
|
||||
$scope.formValues = {};
|
||||
|
||||
var socket, term;
|
||||
@@ -19,25 +21,20 @@ function ($scope, $transition$, Container, Image, EndpointProvider, Notification
|
||||
$scope.container = d;
|
||||
if (d.message) {
|
||||
Notifications.error('Error', d, 'Unable to retrieve container details');
|
||||
$('#loadingViewSpinner').hide();
|
||||
} else {
|
||||
Image.get({id: d.Image}, function(imgData) {
|
||||
$scope.imageOS = imgData.Os;
|
||||
$scope.formValues.command = imgData.Os === 'windows' ? 'powershell' : 'bash';
|
||||
$scope.state.loaded = true;
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function (e) {
|
||||
Notifications.error('Failure', e, 'Unable to retrieve image details');
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
}, function (e) {
|
||||
Notifications.error('Failure', e, 'Unable to retrieve container details');
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
|
||||
$scope.connect = function() {
|
||||
$('#loadConsoleSpinner').show();
|
||||
var termWidth = Math.floor(($('#terminal-container').width() - 20) / 8.39);
|
||||
var termHeight = 30;
|
||||
var command = $scope.formValues.isCustomCommand ?
|
||||
@@ -67,9 +64,6 @@ function ($scope, $transition$, Container, Image, EndpointProvider, Notification
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to exec into container');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadConsoleSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -88,7 +82,6 @@ function ($scope, $transition$, Container, Image, EndpointProvider, Notification
|
||||
|
||||
$scope.state.connected = true;
|
||||
socket.onopen = function(evt) {
|
||||
$('#loadConsoleSpinner').hide();
|
||||
term = new Terminal();
|
||||
|
||||
term.on('data', function (data) {
|
||||
|
||||
@@ -2,21 +2,18 @@ angular.module('containerInspect', ['angular-json-tree'])
|
||||
.controller('ContainerInspectController', ['$scope', '$transition$', 'Notifications', 'ContainerService',
|
||||
function ($scope, $transition$, Notifications, ContainerService) {
|
||||
|
||||
$scope.state = { DisplayTextView: false };
|
||||
$scope.state = {
|
||||
DisplayTextView: false
|
||||
};
|
||||
$scope.containerInfo = {};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
ContainerService.inspect($transition$.params().id)
|
||||
.then(function success(d) {
|
||||
$scope.containerInfo = d;
|
||||
})
|
||||
.catch(function error(e) {
|
||||
Notifications.error('Failure', e, 'Unable to inspect container');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,20 +8,15 @@ function ($scope, $transition$, $anchorScroll, ContainerLogs, Container) {
|
||||
$scope.stderr = '';
|
||||
$scope.tailLines = 2000;
|
||||
|
||||
$('#loadingViewSpinner').show();
|
||||
Container.get({id: $transition$.params().id}, function (d) {
|
||||
$scope.container = d;
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to retrieve container info');
|
||||
});
|
||||
|
||||
function getLogs() {
|
||||
$('#loadingViewSpinner').show();
|
||||
getLogsStdout();
|
||||
getLogsStderr();
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
|
||||
function getLogsStderr() {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Container logs">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Container logs"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="containers">Containers</a> > <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> > Logs
|
||||
</rd-header-content>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Container statistics">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Container statistics"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="containers">Containers</a> > <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> > Stats
|
||||
</rd-header-content>
|
||||
|
||||
@@ -80,7 +80,6 @@ function ($q, $scope, $transition$, $document, $interval, ContainerService, Char
|
||||
};
|
||||
|
||||
function startChartUpdate(networkChart, cpuChart, memoryChart) {
|
||||
$('#loadingViewSpinner').show();
|
||||
$q.all({
|
||||
stats: ContainerService.containerStats($transition$.params().id),
|
||||
top: ContainerService.containerTop($transition$.params().id)
|
||||
@@ -99,9 +98,6 @@ function ($q, $scope, $transition$, $document, $interval, ContainerService, Char
|
||||
.catch(function error(err) {
|
||||
stopRepeater();
|
||||
Notifications.error('Failure', err, 'Unable to retrieve container statistics');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,17 +139,12 @@ function ($q, $scope, $transition$, $document, $interval, ContainerService, Char
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
ContainerService.container($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.container = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve container information');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
|
||||
$document.ready(function() {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="containers" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadContainersSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Containers</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -33,7 +32,7 @@
|
||||
<button type="button" class="btn btn-primary btn-responsive" ng-click="unpauseAction()" ng-disabled="!state.selectedItemCount || state.noPausedItemsSelected"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
|
||||
<button type="button" class="btn btn-danger btn-responsive" ng-click="confirmRemoveAction()" ng-disabled="!state.selectedItemCount"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button>
|
||||
</div>
|
||||
<a class="btn btn-primary" type="button" ui-sref="actions.create.container"><i class="fa fa-plus space-right" aria-hidden="true"></i>Add container</a>
|
||||
<a class="btn btn-primary btn-responsive" type="button" ui-sref="actions.create.container"><i class="fa fa-plus space-right" aria-hidden="true"></i>Add container</a>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<input type="checkbox" ng-model="state.displayAll" id="displayAll" ng-change="toggleGetAll()" style="margin-top: -2px; margin-right: 5px;"/><label for="displayAll">Show all containers</label>
|
||||
@@ -110,7 +109,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="container in (state.filteredContainers = ( containers | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="container in (state.filteredContainers = ( containers | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: container.Checked}">
|
||||
<td><input type="checkbox" ng-model="container.Checked" ng-change="selectItem(container)"/></td>
|
||||
<td>
|
||||
<span ng-if="['starting','healthy','unhealthy'].indexOf(container.Status) !== -1" class="label label-{{ container.Status|containerstatusbadge }} interactive" uib-tooltip="This container has a health check">{{ container.Status }}</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module('containers', [])
|
||||
.controller('ContainersController', ['$q', '$scope', '$filter', 'Container', 'ContainerService', 'ContainerHelper', 'SystemService', 'Notifications', 'Pagination', 'EntityListService', 'ModalService', 'ResourceControlService', 'EndpointProvider', 'LocalStorage',
|
||||
function ($q, $scope, $filter, Container, ContainerService, ContainerHelper, SystemService, Notifications, Pagination, EntityListService, ModalService, ResourceControlService, EndpointProvider, LocalStorage) {
|
||||
.controller('ContainersController', ['$q', '$scope', '$state', '$filter', 'Container', 'ContainerService', 'ContainerHelper', 'SystemService', 'Notifications', 'Pagination', 'EntityListService', 'ModalService', 'ResourceControlService', 'EndpointProvider', 'LocalStorage',
|
||||
function ($q, $scope, $state, $filter, Container, ContainerService, ContainerHelper, SystemService, Notifications, Pagination, EntityListService, ModalService, ResourceControlService, EndpointProvider, LocalStorage) {
|
||||
$scope.state = {};
|
||||
$scope.state.pagination_count = Pagination.getPaginationCount('containers');
|
||||
$scope.state.displayAll = LocalStorage.getFilterContainerShowAll();
|
||||
@@ -24,7 +24,6 @@ angular.module('containers', [])
|
||||
$scope.cleanAssociatedVolumes = false;
|
||||
|
||||
var update = function (data) {
|
||||
$('#loadContainersSpinner').show();
|
||||
$scope.state.selectedItemCount = 0;
|
||||
Container.query(data, function (d) {
|
||||
var containers = d;
|
||||
@@ -45,21 +44,17 @@ angular.module('containers', [])
|
||||
return model;
|
||||
});
|
||||
updateSelectionFlags();
|
||||
$('#loadContainersSpinner').hide();
|
||||
}, function (e) {
|
||||
$('#loadContainersSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to retrieve containers');
|
||||
$scope.containers = [];
|
||||
});
|
||||
};
|
||||
|
||||
var batch = function (items, action, msg) {
|
||||
$('#loadContainersSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadContainersSpinner').hide();
|
||||
update({all: $scope.state.displayAll ? 1 : 0});
|
||||
}
|
||||
};
|
||||
@@ -78,12 +73,13 @@ angular.module('containers', [])
|
||||
else if (action === Container.remove) {
|
||||
ContainerService.remove(c, $scope.cleanAssociatedVolumes)
|
||||
.then(function success() {
|
||||
var index = items.indexOf(c);
|
||||
items.splice(index, 1);
|
||||
Notifications.success('Container successfully removed');
|
||||
complete();
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove container');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
@@ -108,13 +104,9 @@ angular.module('containers', [])
|
||||
Notifications.error('Failure', e, 'An error occured');
|
||||
complete();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
if (counter === 0) {
|
||||
$('#loadContainersSpinner').hide();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.selectItems = function (allSelected) {
|
||||
|
||||
@@ -58,14 +58,11 @@ function ($scope, $state, $document, Notifications, ConfigService, Authenticatio
|
||||
}
|
||||
|
||||
$scope.create = function () {
|
||||
$('#createResourceSpinner').show();
|
||||
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createResourceSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,9 +80,6 @@ function ($scope, $state, $document, Notifications, ConfigService, Authenticatio
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to create config');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -62,8 +62,6 @@
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name" ng-click="create()">Create config</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="configs">Cancel</a>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
|
||||
@@ -20,7 +20,8 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.refreshSlider = function () {
|
||||
@@ -348,6 +349,12 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
|
||||
}
|
||||
}
|
||||
|
||||
$scope.resetNetworkConfig = function() {
|
||||
$scope.config.NetworkingConfig = {
|
||||
EndpointsConfig: {}
|
||||
};
|
||||
};
|
||||
|
||||
function loadFromContainerNetworkConfig(d) {
|
||||
$scope.config.NetworkingConfig = {
|
||||
EndpointsConfig: {}
|
||||
@@ -549,7 +556,7 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
|
||||
});
|
||||
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
$scope.isAdmin = userDetails.role === 1 ? true : false;
|
||||
$scope.isAdmin = userDetails.role === 1;
|
||||
}
|
||||
|
||||
function validateForm(accessControlData, isAdmin) {
|
||||
@@ -570,16 +577,16 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
|
||||
if (!confirm) {
|
||||
return false;
|
||||
}
|
||||
$('#createContainerSpinner').show();
|
||||
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createContainerSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
var config = prepareConfiguration();
|
||||
createContainer(config, accessControlData);
|
||||
})
|
||||
@@ -605,7 +612,7 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
|
||||
Notifications.error('Failure', err, 'Unable to create container');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createContainerSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<form class="form-horizontal" autocomplete="off">
|
||||
<!-- name-input -->
|
||||
<div class="form-group">
|
||||
<label for="container_name" class="col-sm-1 control-label text-left">Name</label>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div ng-if="formValues.Registry || !fromContainer">
|
||||
<!-- image-and-registry -->
|
||||
<div class="form-group">
|
||||
<por-image-registry image="config.Image" registry="formValues.Registry" ng-if="formValues.Registry"></por-image-registry>
|
||||
<por-image-registry image="config.Image" registry="formValues.Registry" ng-if="formValues.Registry" auto-complete="true"></por-image-registry>
|
||||
</div>
|
||||
<!-- !image-and-registry -->
|
||||
<!-- always-pull -->
|
||||
@@ -112,9 +112,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image || (!formValues.Registry && fromContainer)" ng-click="create()">Start container</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="containers">Cancel</a>
|
||||
<i id="createContainerSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !config.Image || (!formValues.Registry && fromContainer)" ng-click="create()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Deploy the container</span>
|
||||
<span ng-show="state.actionInProgress">Deployment in progress...</span>
|
||||
</button>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
<span ng-if="fromContainerMultipleNetworks" style="margin-left: 10px">
|
||||
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
|
||||
@@ -295,7 +296,7 @@
|
||||
<div class="form-group">
|
||||
<label for="container_network" class="col-sm-2 col-lg-1 control-label text-left">Network</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control" ng-model="config.HostConfig.NetworkMode" id="container_network">
|
||||
<select class="form-control" ng-model="config.HostConfig.NetworkMode" id="container_network" ng-change="resetNetworkConfig()">
|
||||
<option selected disabled hidden value="">Select a network</option>
|
||||
<option ng-repeat="net in availableNetworks" ng-value="net.Name">{{ net.Name }}</option>
|
||||
</select>
|
||||
|
||||
@@ -11,7 +11,8 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.availableNetworkDrivers = [];
|
||||
@@ -89,18 +90,16 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
|
||||
}
|
||||
|
||||
$scope.create = function () {
|
||||
$('#createResourceSpinner').show();
|
||||
|
||||
var networkConfiguration = prepareConfiguration();
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createResourceSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
NetworkService.create(networkConfiguration)
|
||||
.then(function success(data) {
|
||||
var networkIdentifier = data.Id;
|
||||
@@ -115,12 +114,11 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
|
||||
Notifications.error('Failure', err, 'An error occured during network creation');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
if(endpointProvider !== 'DOCKER_SWARM') {
|
||||
@@ -130,9 +128,6 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve network drivers');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Create network">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Create network"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="networks">Networks</a> > Add network
|
||||
</rd-header-content>
|
||||
@@ -130,8 +128,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Name" ng-click="create()">Create network</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="networks">Cancel</a>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !config.Name" ng-click="create()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Create the network</span>
|
||||
<span ng-show="state.actionInProgress">Creating network...</span>
|
||||
</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,8 @@ angular.module('createRegistry', [])
|
||||
function ($scope, $state, RegistryService, Notifications) {
|
||||
|
||||
$scope.state = {
|
||||
RegistryType: 'quay'
|
||||
RegistryType: 'quay',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
@@ -27,13 +28,13 @@ function ($scope, $state, RegistryService, Notifications) {
|
||||
};
|
||||
|
||||
$scope.addRegistry = function() {
|
||||
$('#createRegistrySpinner').show();
|
||||
var registryName = $scope.formValues.Name;
|
||||
var registryURL = $scope.formValues.URL.replace(/^https?\:\/\//i, '');
|
||||
var authentication = $scope.formValues.Authentication;
|
||||
var username = $scope.formValues.Username;
|
||||
var password = $scope.formValues.Password;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
RegistryService.createRegistry(registryName, registryURL, authentication, username, password)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Registry successfully created');
|
||||
@@ -43,7 +44,7 @@ function ($scope, $state, RegistryService, Notifications) {
|
||||
Notifications.error('Failure', err, 'Unable to create registry');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createRegistrySpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Create registry">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="display:none"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Create registry"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="registries">Registries</a> > Add registry
|
||||
</rd-header-content>
|
||||
@@ -104,10 +102,15 @@
|
||||
<!-- !credentials-password -->
|
||||
</div>
|
||||
<!-- !authentication-credentials -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Actions
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name || !formValues.URL || (formValues.Authentication && (!formValues.Username || !formValues.Password))" ng-click="addRegistry()">Add registry</button>
|
||||
<i id="createRegistrySpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Name || !formValues.URL || (formValues.Authentication && (!formValues.Username || !formValues.Password))" ng-click="addRegistry()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Add registry</span>
|
||||
<span ng-show="state.actionInProgress">Adding registry...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -11,7 +11,8 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.addLabel = function() {
|
||||
@@ -55,17 +56,16 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
|
||||
}
|
||||
|
||||
$scope.create = function () {
|
||||
$('#createResourceSpinner').show();
|
||||
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createResourceSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
var secretConfiguration = prepareConfiguration();
|
||||
SecretService.create(secretConfiguration)
|
||||
.then(function success(data) {
|
||||
@@ -81,7 +81,7 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
|
||||
Notifications.error('Failure', err, 'Unable to create secret');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -75,9 +75,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name || !formValues.Data" ng-click="create()">Create secret</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="secrets">Cancel</a>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Name || !formValues.Data" ng-click="create()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Create the secret</span>
|
||||
<span ng-show="state.actionInProgress">Creating secret...</span>
|
||||
</button>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,8 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.refreshSlider = function () {
|
||||
@@ -81,7 +82,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
};
|
||||
|
||||
$scope.addSecret = function() {
|
||||
$scope.formValues.Secrets.push({});
|
||||
$scope.formValues.Secrets.push({ overrideTarget: false });
|
||||
};
|
||||
|
||||
$scope.removeSecret = function(index) {
|
||||
@@ -242,7 +243,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
function prepareUpdateConfig(config, input) {
|
||||
config.UpdateConfig = {
|
||||
Parallelism: input.Parallelism || 0,
|
||||
Delay: input.UpdateDelay || 0,
|
||||
Delay: input.UpdateDelay * 1000000000 || 0,
|
||||
FailureAction: input.FailureAction,
|
||||
Order: input.UpdateOrder
|
||||
};
|
||||
@@ -274,6 +275,9 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
if (secret.model) {
|
||||
var s = SecretHelper.secretConfig(secret.model);
|
||||
s.File.Name = s.SecretName;
|
||||
if (secret.overrideTarget && secret.target && secret.target !== '') {
|
||||
s.File.Name = secret.target;
|
||||
}
|
||||
secrets.push(s);
|
||||
}
|
||||
});
|
||||
@@ -366,7 +370,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
Notifications.error('Failure', err, 'Unable to create service');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createServiceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -383,17 +387,16 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
}
|
||||
|
||||
$scope.create = function createService() {
|
||||
$('#createServiceSpinner').show();
|
||||
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createServiceSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
var config = prepareConfiguration();
|
||||
createNewService(config, accessControlData);
|
||||
};
|
||||
@@ -422,7 +425,6 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
var provider = $scope.applicationState.endpoint.mode.provider;
|
||||
|
||||
@@ -444,13 +446,10 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
|
||||
var settings = data.settings;
|
||||
$scope.allowBindMounts = settings.AllowBindMountsForRegularUsers;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
$scope.isAdmin = userDetails.role === 1 ? true : false;
|
||||
$scope.isAdmin = userDetails.role === 1;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to initialize view');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Create service">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Create service"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="services">Services</a> > Add service
|
||||
</rd-header-content>
|
||||
@@ -11,7 +9,7 @@
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<form class="form-horizontal" autocomplete="off">
|
||||
<!-- name-input -->
|
||||
<div class="form-group">
|
||||
<label for="service_name" class="col-sm-1 control-label text-left">Name</label>
|
||||
@@ -25,7 +23,7 @@
|
||||
</div>
|
||||
<!-- image-and-registry -->
|
||||
<div class="form-group">
|
||||
<por-image-registry image="formValues.Image" registry="formValues.Registry"></por-image-registry>
|
||||
<por-image-registry image="formValues.Image" registry="formValues.Registry" auto-complete="true"></por-image-registry>
|
||||
</div>
|
||||
<!-- !image-and-registry -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
@@ -109,9 +107,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="create()">Create service</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="services">Cancel</a>
|
||||
<i id="createServiceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Image" ng-click="create()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Create the service</span>
|
||||
<span ng-show="state.actionInProgress">Creating service...</span>
|
||||
</button>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -396,7 +395,7 @@
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
<p class="small text-muted">
|
||||
Amount of time between updates.
|
||||
Amount of time between updates. Time in seconds.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<form class="form-horizontal" style="margin-top: 15px;">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 small text-muted">
|
||||
Secrets will be available under <code>/run/secrets/$SECRET_NAME</code> in containers.
|
||||
By default, secrets will be available under <code>/run/secrets/$SECRET_NAME</code> in containers.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -12,16 +12,26 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||
<div ng-repeat="secret in formValues.Secrets" style="margin-top: 2px;">
|
||||
<div ng-repeat="secret in formValues.Secrets track by $index" style="margin-top: 4px;">
|
||||
<div class="input-group col-sm-4 input-group-sm">
|
||||
<span class="input-group-addon">secret</span>
|
||||
<select class="form-control" ng-model="secret.model" ng-options="secret.Name for secret in availableSecrets">
|
||||
<option value="" selected="selected">Select a secret</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-danger" type="button" ng-click="removeSecret($index)">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="input-group col-sm-4 input-group-sm" ng-if="applicationState.endpoint.apiVersion >= 1.30 && secret.overrideTarget">
|
||||
<span class="input-group-addon">target</span>
|
||||
<input class="form-control" ng-model="secret.target" placeholder="/path/in/container">
|
||||
</div>
|
||||
<div class="input-group col-sm-3 input-group-sm">
|
||||
<div class="btn-group btn-group-sm" ng-if="applicationState.endpoint.apiVersion >= 1.30">
|
||||
<label class="btn btn-primary" ng-model="secret.overrideTarget" uib-btn-radio="false">Default location</label>
|
||||
<label class="btn btn-primary" ng-model="secret.overrideTarget" uib-btn-radio="true">Override</label>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-danger" type="button" ng-click="removeSecret($index)">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,8 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||
|
||||
$scope.state = {
|
||||
Method: 'editor',
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.addEnvironmentVariable = function() {
|
||||
@@ -62,20 +63,18 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||
}
|
||||
|
||||
$scope.deployStack = function () {
|
||||
$('#createResourceSpinner').show();
|
||||
|
||||
var name = $scope.formValues.Name;
|
||||
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
var userId = userDetails.ID;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createResourceSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
createStack(name)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
@@ -93,7 +92,7 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
|
||||
Notifications.error('Failure', err, 'Unable to apply resource control on the stack');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Create stack">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="display: none;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Create stack"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="stacks">Stacks</a> > Add stack
|
||||
</rd-header-content>
|
||||
@@ -169,12 +167,13 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="(state.Method === 'editor' && !formValues.StackFileContent)
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || (state.Method === 'editor' && !formValues.StackFileContent)
|
||||
|| (state.Method === 'upload' && !formValues.StackFile)
|
||||
|| (state.Method === 'repository' && (!formValues.RepositoryURL || !formValues.RepositoryPath))
|
||||
|| !formValues.Name" ng-click="deployStack()">Deploy the stack</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="stacks">Cancel</a>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
|| !formValues.Name" ng-click="deployStack()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Deploy the stack</span>
|
||||
<span ng-show="state.actionInProgress">Deployment in progress...</span>
|
||||
</button>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,8 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
formValidationError: ''
|
||||
formValidationError: '',
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.availableVolumeDrivers = [];
|
||||
@@ -35,7 +36,6 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
|
||||
}
|
||||
|
||||
$scope.create = function () {
|
||||
$('#createVolumeSpinner').show();
|
||||
|
||||
var name = $scope.formValues.Name;
|
||||
var driver = $scope.formValues.Driver;
|
||||
@@ -43,13 +43,13 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
|
||||
var volumeConfiguration = VolumeService.createVolumeConfiguration(name, driver, driverOptions);
|
||||
var accessControlData = $scope.formValues.AccessControlData;
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true : false;
|
||||
var isAdmin = userDetails.role === 1;
|
||||
|
||||
if (!validateForm(accessControlData, isAdmin)) {
|
||||
$('#createVolumeSpinner').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
VolumeService.createVolume(volumeConfiguration)
|
||||
.then(function success(data) {
|
||||
var volumeIdentifier = data.Id;
|
||||
@@ -64,12 +64,11 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
|
||||
Notifications.error('Failure', err, 'An error occured during volume creation');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createVolumeSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
if (endpointProvider !== 'DOCKER_SWARM') {
|
||||
@@ -79,9 +78,6 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve volume drivers');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Create volume">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Create volume"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="volumes">Volumes</a> > Add volume
|
||||
</rd-header-content>
|
||||
@@ -73,9 +71,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="create()">Create volume</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="volumes">Cancel</a>
|
||||
<i id="createVolumeSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="create()" ng-disabled="state.actionInProgress" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Create the volume</span>
|
||||
<span ng-show="state.actionInProgress">Creating volume...</span>
|
||||
</button>
|
||||
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Home">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Home"></rd-header-title>
|
||||
<rd-header-content>Dashboard</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -171,6 +169,3 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
</div>
|
||||
|
||||
@@ -65,8 +65,6 @@ function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, System
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
var endpointRole = $scope.applicationState.endpoint.mode.role;
|
||||
|
||||
@@ -86,9 +84,7 @@ function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, System
|
||||
prepareInfoData(d[4]);
|
||||
$scope.serviceCount = d[5].length;
|
||||
$scope.stackCount = d[6].length;
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function(e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to load dashboard data');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Endpoint details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Endpoint details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="endpoints">Endpoints</a> > <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a>
|
||||
</rd-header-content>
|
||||
@@ -55,9 +53,11 @@
|
||||
<!-- !endpoint-security -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!endpoint.Name || !endpoint.URL || (endpoint.TLS && ((endpoint.TLSVerify && !formValues.TLSCACert) || (endpoint.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="updateEndpoint()">Update endpoint</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !endpoint.Name || !endpoint.URL || (endpoint.TLS && ((endpoint.TLSVerify && !formValues.TLSCACert) || (endpoint.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="updateEndpoint()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Update endpoint</span>
|
||||
<span ng-show="state.actionInProgress">Updating endpoint...</span>
|
||||
</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="endpoints">Cancel</a>
|
||||
<i id="updateResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -7,7 +7,8 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
|
||||
}
|
||||
|
||||
$scope.state = {
|
||||
uploadInProgress: false
|
||||
uploadInProgress: false,
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
@@ -35,13 +36,14 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
|
||||
type: $scope.endpointType
|
||||
};
|
||||
|
||||
$('updateResourceSpinner').show();
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.updateEndpoint(endpoint.Id, endpointParams)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Endpoint updated', $scope.endpoint.Name);
|
||||
$state.go('endpoints');
|
||||
}, function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update endpoint');
|
||||
$scope.state.actionInProgress = false;
|
||||
}, function update(evt) {
|
||||
if (evt.upload) {
|
||||
$scope.state.uploadInProgress = evt.upload;
|
||||
@@ -50,7 +52,6 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
EndpointService.endpoint($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
var endpoint = data;
|
||||
@@ -64,9 +65,6 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve endpoint details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Endpoint access">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Endpoint access"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="endpoints">Endpoints</a> > <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a> > Access management
|
||||
</rd-header-content>
|
||||
|
||||
@@ -7,16 +7,12 @@ function ($scope, $transition$, EndpointService, Notifications) {
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
EndpointService.endpoint($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.endpoint = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve endpoint details');
|
||||
})
|
||||
.finally(function final(){
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="endpoints" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadEndpointsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Endpoint management</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -66,8 +65,11 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (formValues.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="addEndpoint()"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (formValues.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="addEndpoint()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
|
||||
<span ng-show="state.actionInProgress">Creating endpoint...</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
@@ -126,7 +128,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="endpoint in (state.filteredEndpoints = (endpoints | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="endpoint in (state.filteredEndpoints = (endpoints | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: endpoint.Checked}">
|
||||
<td ng-if="applicationState.application.endpointManagement"><input type="checkbox" ng-model="endpoint.Checked" ng-change="selectItem(endpoint)" /></td>
|
||||
<td><i class="fa fa-star" aria-hidden="true" ng-if="endpoint.Id === activeEndpoint.Id"></i> {{ endpoint.Name }}</td>
|
||||
<td>{{ endpoint.URL | stripprotocol }}</td>
|
||||
|
||||
@@ -4,7 +4,8 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
|
||||
$scope.state = {
|
||||
uploadInProgress: false,
|
||||
selectedItemCount: 0,
|
||||
pagination_count: Pagination.getPaginationCount('endpoints')
|
||||
pagination_count: Pagination.getPaginationCount('endpoints'),
|
||||
actionInProgress: false
|
||||
};
|
||||
$scope.sortType = 'Name';
|
||||
$scope.sortReverse = true;
|
||||
@@ -59,11 +60,13 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
|
||||
var TLSCertFile = TLSSkipClientVerify ? null : securityData.TLSCert;
|
||||
var TLSKeyFile = TLSSkipClientVerify ? null : securityData.TLSKey;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
|
||||
Notifications.success('Endpoint created', name);
|
||||
$state.reload();
|
||||
}, function error(err) {
|
||||
$scope.state.uploadInProgress = false;
|
||||
$scope.state.actionInProgress = false;
|
||||
Notifications.error('Failure', err, 'Unable to create endpoint');
|
||||
}, function update(evt) {
|
||||
if (evt.upload) {
|
||||
@@ -73,32 +76,20 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
|
||||
};
|
||||
|
||||
$scope.removeAction = function () {
|
||||
$('#loadEndpointsSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadEndpointsSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.endpoints, function (endpoint) {
|
||||
if (endpoint.Checked) {
|
||||
counter = counter + 1;
|
||||
EndpointService.deleteEndpoint(endpoint.Id).then(function success(data) {
|
||||
Notifications.success('Endpoint deleted', endpoint.Name);
|
||||
var index = $scope.endpoints.indexOf(endpoint);
|
||||
$scope.endpoints.splice(index, 1);
|
||||
complete();
|
||||
}, function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove endpoint');
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function fetchEndpoints() {
|
||||
$('#loadEndpointsSpinner').show();
|
||||
EndpointService.endpoints()
|
||||
.then(function success(data) {
|
||||
$scope.endpoints = data;
|
||||
@@ -106,9 +97,6 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve endpoints');
|
||||
$scope.endpoints = [];
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadEndpointsSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="engine" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Docker</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
angular.module('engine', [])
|
||||
.controller('EngineController', ['$q', '$scope', 'SystemService', 'Notifications',
|
||||
function ($q, $scope, SystemService, Notifications) {
|
||||
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
$q.all({
|
||||
version: SystemService.version(),
|
||||
info: SystemService.info()
|
||||
@@ -16,9 +15,6 @@ function ($q, $scope, SystemService, Notifications) {
|
||||
$scope.info = {};
|
||||
$scope.version = {};
|
||||
Notifications.error('Failure', err, 'Unable to retrieve engine details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="events" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadEventsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Events</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -19,16 +19,12 @@ function ($scope, Notifications, SystemService, Pagination) {
|
||||
var from = moment().subtract(24, 'hour').unix();
|
||||
var to = moment().unix();
|
||||
|
||||
$('#loadEventsSpinner').show();
|
||||
SystemService.events(from, to)
|
||||
.then(function success(data) {
|
||||
$scope.events = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to load events');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadEventsSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Image details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Image details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="images">Images</a> > <a ui-sref="image({id: image.Id})">{{ image.Id }}</a>
|
||||
</rd-header-content>
|
||||
@@ -41,6 +39,16 @@
|
||||
or on the trash icon <span class="fa fa-trash-o" aria-hidden="true"></span> to delete a tag.
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<span id="downloadResourceHint" class="createResource" style="display: none; margin-left: 0;">
|
||||
Download in progress...
|
||||
<i class="fa fa-circle-o-notch fa-spin" aria-hidden="true" style="margin-left: 2px;"></i>
|
||||
</span>
|
||||
<span id="uploadResourceHint" class="createResource" style="display: none; margin-left: 0;">
|
||||
Upload in progress...
|
||||
<i class="fa fa-circle-o-notch fa-spin" aria-hidden="true" style="margin-left: 2px;"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
@@ -69,7 +77,6 @@
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="tagImage()">Tag</button>
|
||||
<i id="pullImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -21,7 +21,6 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
};
|
||||
|
||||
$scope.tagImage = function() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var image = $scope.formValues.Image;
|
||||
var registry = $scope.formValues.Registry;
|
||||
|
||||
@@ -32,14 +31,11 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to tag image');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.pushTag = function(repository) {
|
||||
$('#loadingViewSpinner').show();
|
||||
$('#uploadResourceHint').show();
|
||||
RegistryService.retrieveRegistryFromRepository(repository)
|
||||
.then(function success(data) {
|
||||
var registry = data;
|
||||
@@ -52,12 +48,12 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
Notifications.error('Failure', err, 'Unable to push image to repository');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
$('#uploadResourceHint').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.pullTag = function(repository) {
|
||||
$('#loadingViewSpinner').show();
|
||||
$('#downloadResourceHint').show();
|
||||
RegistryService.retrieveRegistryFromRepository(repository)
|
||||
.then(function success(data) {
|
||||
var registry = data;
|
||||
@@ -70,12 +66,11 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
Notifications.error('Failure', err, 'Unable to pull image');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
$('#downloadResourceHint').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeTag = function(repository) {
|
||||
$('#loadingViewSpinner').show();
|
||||
ImageService.deleteImage(repository, false)
|
||||
.then(function success() {
|
||||
if ($scope.image.RepoTags.length === 1) {
|
||||
@@ -88,14 +83,10 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove image');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeImage = function (id) {
|
||||
$('#loadingViewSpinner').show();
|
||||
ImageService.deleteImage(id, false)
|
||||
.then(function success() {
|
||||
Notifications.success('Image successfully deleted', id);
|
||||
@@ -103,14 +94,10 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove image');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
$q.all({
|
||||
image: ImageService.image($transition$.params().id),
|
||||
@@ -123,9 +110,6 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve image details');
|
||||
$state.go('images');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="images" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadImagesSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Images</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -29,8 +28,10 @@
|
||||
<!-- !tag-note -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="pullImage()">Pull</button>
|
||||
<i id="pullImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Image" ng-click="pullImage()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Pull the image</span>
|
||||
<span ng-show="state.actionInProgress">Download in progress...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -121,7 +122,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="image in (state.filteredImages = (images | filter:{ ContainerCount: state.containersCountFilter } | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="image in (state.filteredImages = (images | filter:{ ContainerCount: state.containersCountFilter } | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: image.Checked}">
|
||||
<td><input type="checkbox" ng-model="image.Checked" ng-change="selectItem(image)" /></td>
|
||||
<td>
|
||||
<a class="monospaced" ui-sref="image({id: image.Id})">{{ image.Id|truncate:20}}</a>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
angular.module('images', [])
|
||||
.controller('ImagesController', ['$scope', '$state', 'ImageService', 'Notifications', 'Pagination', 'ModalService',
|
||||
function ($scope, $state, ImageService, Notifications, Pagination, ModalService) {
|
||||
$scope.state = {};
|
||||
$scope.state.pagination_count = Pagination.getPaginationCount('images');
|
||||
$scope.state = {
|
||||
pagination_count: Pagination.getPaginationCount('images'),
|
||||
actionInProgress: false,
|
||||
selectedItemCount: 0
|
||||
};
|
||||
|
||||
$scope.sortType = 'RepoTags';
|
||||
$scope.sortReverse = true;
|
||||
$scope.state.selectedItemCount = 0;
|
||||
|
||||
$scope.formValues = {
|
||||
Image: '',
|
||||
@@ -39,9 +42,10 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
|
||||
};
|
||||
|
||||
$scope.pullImage = function() {
|
||||
$('#pullImageSpinner').show();
|
||||
var image = $scope.formValues.Image;
|
||||
var registry = $scope.formValues.Registry;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
ImageService.pullImage(image, registry, false)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Image successfully pulled', image);
|
||||
@@ -51,7 +55,7 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
|
||||
Notifications.error('Failure', err, 'Unable to pull image');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#pullImageSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -64,17 +68,8 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
|
||||
|
||||
$scope.removeAction = function (force) {
|
||||
force = !!force;
|
||||
$('#loadImagesSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadImagesSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.images, function (i) {
|
||||
if (i.Checked) {
|
||||
counter = counter + 1;
|
||||
ImageService.deleteImage(i.Id, force)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Image deleted', i.Id);
|
||||
@@ -83,16 +78,12 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove image');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function fetchImages() {
|
||||
$('#loadImagesSpinner').show();
|
||||
var endpointProvider = $scope.applicationState.endpoint.mode.provider;
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
ImageService.images(true)
|
||||
@@ -102,9 +93,6 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve images');
|
||||
$scope.images = [];
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadImagesSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,10 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="formValues.Password.length < 8 || formValues.Password !== formValues.ConfirmPassword" ng-click="createAdminUser()"><i class="fa fa-user-plus" aria-hidden="true"></i> Create user</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || formValues.Password.length < 8 || formValues.Password !== formValues.ConfirmPassword" ng-click="createAdminUser()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress"><i class="fa fa-user-plus" aria-hidden="true"></i> Create user</span>
|
||||
<span ng-show="state.actionInProgress">Creating user...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
|
||||
@@ -10,11 +10,15 @@ function ($scope, $state, $sanitize, Notifications, Authentication, StateManager
|
||||
ConfirmPassword: ''
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.createAdminUser = function() {
|
||||
$('#createResourceSpinner').show();
|
||||
var username = $sanitize($scope.formValues.Username);
|
||||
var password = $sanitize($scope.formValues.Password);
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
UserService.initAdministrator(username, password)
|
||||
.then(function success() {
|
||||
return Authentication.login(username, password);
|
||||
@@ -41,7 +45,7 @@ function ($scope, $state, $sanitize, Notifications, Authentication, StateManager
|
||||
Notifications.error('Failure', err, 'Unable to create administrator user');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -66,8 +66,10 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-click="createLocalEndpoint()"><i class="fa fa-bolt" aria-hidden="true"></i> Connect</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress" ng-click="createLocalEndpoint()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress"><i class="fa fa-bolt" aria-hidden="true"></i> Connect</span>
|
||||
<span ng-show="state.actionInProgress">Connecting...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
@@ -184,8 +186,10 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (!formValues.TLSSKipClientVerify && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="createRemoteEndpoint()"><i class="fa fa-plug" aria-hidden="true"></i> Connect</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (!formValues.TLSSKipClientVerify && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="createRemoteEndpoint()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress"><i class="fa fa-bolt" aria-hidden="true"></i> Connect</span>
|
||||
<span ng-show="state.actionInProgress">Connecting...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
|
||||
@@ -9,7 +9,8 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
|
||||
$scope.logo = StateManager.getState().application.logo;
|
||||
|
||||
$scope.state = {
|
||||
uploadInProgress: false
|
||||
uploadInProgress: false,
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
@@ -25,11 +26,11 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
|
||||
};
|
||||
|
||||
$scope.createLocalEndpoint = function() {
|
||||
$('#createResourceSpinner').show();
|
||||
var name = 'local';
|
||||
var URL = 'unix:///var/run/docker.sock';
|
||||
|
||||
var endpointID = 1;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.createLocalEndpoint(name, URL, false, true)
|
||||
.then(function success(data) {
|
||||
endpointID = data.Id;
|
||||
@@ -44,12 +45,11 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
|
||||
EndpointService.deleteEndpoint(endpointID);
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.createRemoteEndpoint = function() {
|
||||
$('#createResourceSpinner').show();
|
||||
var name = $scope.formValues.Name;
|
||||
var URL = $scope.formValues.URL;
|
||||
var PublicURL = URL.split(':')[0];
|
||||
@@ -59,8 +59,9 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
|
||||
var TLSCAFile = TLSSkipVerify ? null : $scope.formValues.TLSCACert;
|
||||
var TLSCertFile = TLSSKipClientVerify ? null : $scope.formValues.TLSCert;
|
||||
var TLSKeyFile = TLSSKipClientVerify ? null : $scope.formValues.TLSKey;
|
||||
|
||||
var endpointID = 1;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSKipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
|
||||
.then(function success(data) {
|
||||
endpointID = data.Id;
|
||||
@@ -75,7 +76,7 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
|
||||
EndpointService.deleteEndpoint(endpointID);
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Network details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Network details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="networks">Networks</a> > <a ui-sref="network({id: network.Id})">{{ network.Name }}</a>
|
||||
</rd-header-content>
|
||||
|
||||
@@ -3,35 +3,27 @@ angular.module('network', [])
|
||||
function ($scope, $state, $transition$, $filter, Network, NetworkService, Container, ContainerHelper, Notifications) {
|
||||
|
||||
$scope.removeNetwork = function removeNetwork(networkId) {
|
||||
$('#loadingViewSpinner').show();
|
||||
Network.remove({id: $transition$.params().id}, function (d) {
|
||||
if (d.message) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Error', d, 'Unable to remove network');
|
||||
} else {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.success('Network removed', $transition$.params().id);
|
||||
$state.go('networks', {});
|
||||
}
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to remove network');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.containerLeaveNetwork = function containerLeaveNetwork(network, containerId) {
|
||||
$('#loadingViewSpinner').show();
|
||||
Network.disconnect({id: $transition$.params().id}, { Container: containerId, Force: false }, function (d) {
|
||||
if (d.message) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Error', d, 'Unable to disconnect container from network');
|
||||
} else {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.success('Container left network', $transition$.params().id);
|
||||
$state.go('network', {id: network.Id}, {reload: true});
|
||||
}
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to disconnect container from network');
|
||||
});
|
||||
};
|
||||
@@ -63,9 +55,7 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
|
||||
}
|
||||
});
|
||||
filterContainersInNetwork(network, containersInNetwork);
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function error(err) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', err, 'Unable to retrieve containers in network');
|
||||
});
|
||||
} else {
|
||||
@@ -73,9 +63,7 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
|
||||
filters: { network: [$transition$.params().id] }
|
||||
}, function success(data) {
|
||||
filterContainersInNetwork(network, data);
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function error(err) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', err, 'Unable to retrieve containers in network');
|
||||
});
|
||||
}
|
||||
@@ -83,7 +71,6 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
NetworkService.network($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.network = data;
|
||||
@@ -93,11 +80,7 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
|
||||
}
|
||||
})
|
||||
.catch(function error(err) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', err, 'Unable to retrieve network info');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="networks" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadNetworksSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Networks</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -99,7 +98,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="network in ( state.filteredNetworks = (networks | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="network in ( state.filteredNetworks = (networks | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: network.Checked}">
|
||||
<td><input type="checkbox" ng-model="network.Checked" ng-change="selectItem(network)"/></td>
|
||||
<td><a ui-sref="network({id: network.Id})">{{ network.Name | truncate:40 }}</a></td>
|
||||
<td>{{ network.StackName ? network.StackName : '-' }}</td>
|
||||
|
||||
@@ -35,17 +35,8 @@ function ($scope, $state, Network, NetworkService, Notifications, Pagination) {
|
||||
};
|
||||
|
||||
$scope.removeAction = function () {
|
||||
$('#loadNetworksSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadNetworksSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.networks, function (network) {
|
||||
if (network.Checked) {
|
||||
counter = counter + 1;
|
||||
Network.remove({id: network.Id}, function (d) {
|
||||
if (d.message) {
|
||||
Notifications.error('Error', d, 'Unable to remove network');
|
||||
@@ -54,18 +45,14 @@ function ($scope, $state, Network, NetworkService, Notifications, Pagination) {
|
||||
var index = $scope.networks.indexOf(network);
|
||||
$scope.networks.splice(index, 1);
|
||||
}
|
||||
complete();
|
||||
}, function (e) {
|
||||
Notifications.error('Failure', e, 'Unable to remove network');
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadNetworksSpinner').show();
|
||||
|
||||
NetworkService.networks(true, true, true, true)
|
||||
.then(function success(data) {
|
||||
$scope.networks = data;
|
||||
@@ -73,9 +60,6 @@ function ($scope, $state, Network, NetworkService, Notifications, Pagination) {
|
||||
.catch(function error(err) {
|
||||
$scope.networks = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve networks');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadNetworksSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -68,11 +68,9 @@ function ($scope, $state, $transition$, LabelHelper, Node, NodeHelper, Task, Pag
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash(node.Labels);
|
||||
|
||||
Node.update({ id: node.Id, version: node.Version }, config, function (data) {
|
||||
$('#loadServicesSpinner').hide();
|
||||
Notifications.success('Node successfully updated', 'Node updated');
|
||||
$state.go('node', {id: node.Id}, {reload: true});
|
||||
}, function (e) {
|
||||
$('#loadServicesSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Failed to update node');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="registries" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Registry management</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -57,8 +56,10 @@
|
||||
<!-- !authentication-credentials -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="dockerhub.Authentication && (!dockerhub.Username || !dockerhub.Password)" ng-click="updateDockerHub()">Update</button>
|
||||
<i id="updateDockerhubSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || dockerhub.Authentication && (!dockerhub.Username || !dockerhub.Password)" ng-click="updateDockerHub()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Update</span>
|
||||
<span ng-show="state.actionInProgress">Updating DockerHub settings...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -117,7 +118,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="registry in (state.filteredRegistries = (registries | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="registry in (state.filteredRegistries = (registries | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: registry.Checked}">
|
||||
<td><input type="checkbox" ng-model="registry.Checked" ng-change="selectItem(registry)" /></td>
|
||||
<td>
|
||||
<a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a>
|
||||
|
||||
@@ -4,14 +4,15 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
|
||||
|
||||
$scope.state = {
|
||||
selectedItemCount: 0,
|
||||
pagination_count: Pagination.getPaginationCount('registries')
|
||||
pagination_count: Pagination.getPaginationCount('registries'),
|
||||
actionInProgress: false
|
||||
};
|
||||
$scope.sortType = 'Name';
|
||||
$scope.sortReverse = true;
|
||||
|
||||
$scope.updateDockerHub = function() {
|
||||
$('#updateDockerhubSpinner').show();
|
||||
var dockerhub = $scope.dockerhub;
|
||||
$scope.state.actionInProgress = true;
|
||||
DockerHubService.update(dockerhub)
|
||||
.then(function success(data) {
|
||||
Notifications.success('DockerHub registry updated');
|
||||
@@ -20,7 +21,7 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
|
||||
Notifications.error('Failure', err, 'Unable to update DockerHub details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#updateDockerhubSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -61,19 +62,9 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
|
||||
};
|
||||
|
||||
function removeRegistries() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
};
|
||||
|
||||
var registries = $scope.registries;
|
||||
angular.forEach(registries, function (registry) {
|
||||
if (registry.Checked) {
|
||||
counter = counter + 1;
|
||||
RegistryService.deleteRegistry(registry.Id)
|
||||
.then(function success(data) {
|
||||
var index = registries.indexOf(registry);
|
||||
@@ -82,16 +73,12 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove registry');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
$q.all({
|
||||
registries: RegistryService.registries(),
|
||||
dockerhub: DockerHubService.dockerhub()
|
||||
@@ -103,9 +90,6 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
|
||||
.catch(function error(err) {
|
||||
$scope.registries = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve registries');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Registry details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Registry details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="registries">Registries</a> > <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a>
|
||||
</rd-header-content>
|
||||
@@ -66,9 +64,11 @@
|
||||
<!-- !authentication-credentials -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!registry.Name || !registry.URL || (registry.Authentication && (!registry.Username || !registry.Password))" ng-click="updateRegistry()">Update registry</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress || !registry.Name || !registry.URL || (registry.Authentication && (!registry.Username || !registry.Password))" ng-click="updateRegistry()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Update registry</span>
|
||||
<span ng-show="state.actionInProgress">Updating registry...</span>
|
||||
</button>
|
||||
<a type="button" class="btn btn-default btn-sm" ui-sref="registries">Cancel</a>
|
||||
<i id="updateRegistrySpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -2,9 +2,13 @@ angular.module('registry', [])
|
||||
.controller('RegistryController', ['$scope', '$state', '$transition$', '$filter', 'RegistryService', 'Notifications',
|
||||
function ($scope, $state, $transition$, $filter, RegistryService, Notifications) {
|
||||
|
||||
$scope.state = {
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.updateRegistry = function() {
|
||||
$('#updateRegistrySpinner').show();
|
||||
var registry = $scope.registry;
|
||||
$scope.state.actionInProgress = true;
|
||||
RegistryService.updateRegistry(registry)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Registry successfully updated');
|
||||
@@ -14,12 +18,11 @@ function ($scope, $state, $transition$, $filter, RegistryService, Notifications)
|
||||
Notifications.error('Failure', err, 'Unable to update registry');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#updateRegistrySpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var registryID = $transition$.params().id;
|
||||
RegistryService.registry(registryID)
|
||||
.then(function success(data) {
|
||||
@@ -27,9 +30,6 @@ function ($scope, $state, $transition$, $filter, RegistryService, Notifications)
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve registry details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Registry access">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Registry access"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="registries">Registries</a> > <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a> > Access management
|
||||
</rd-header-content>
|
||||
|
||||
@@ -7,16 +7,12 @@ function ($scope, $transition$, RegistryService, Notifications) {
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
RegistryService.registry($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.registry = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve registry details');
|
||||
})
|
||||
.finally(function final(){
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="secret({id: secret.Id})" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="secrets">Secrets</a> > <a ui-sref="secret({id: secret.Id})">{{ secret.Name }}</a>
|
||||
|
||||
@@ -3,7 +3,6 @@ angular.module('secret', [])
|
||||
function ($scope, $transition$, $state, SecretService, Notifications) {
|
||||
|
||||
$scope.removeSecret = function removeSecret(secretId) {
|
||||
$('#loadingViewSpinner').show();
|
||||
SecretService.remove(secretId)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Secret successfully removed');
|
||||
@@ -11,23 +10,16 @@ function ($scope, $transition$, $state, SecretService, Notifications) {
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove secret');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
SecretService.secret($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
$scope.secret = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve secret details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="secrets" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Secrets</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -30,17 +30,8 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
|
||||
};
|
||||
|
||||
$scope.removeAction = function () {
|
||||
$('#loadingViewSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.secrets, function (secret) {
|
||||
if (secret.Checked) {
|
||||
counter = counter + 1;
|
||||
SecretService.remove(secret.Id)
|
||||
.then(function success() {
|
||||
Notifications.success('Secret deleted', secret.Id);
|
||||
@@ -49,16 +40,12 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove secret');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
SecretService.secrets()
|
||||
.then(function success(data) {
|
||||
$scope.secrets = data;
|
||||
@@ -66,9 +53,6 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
|
||||
.catch(function error(err) {
|
||||
$scope.secrets = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve secrets');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<p class="small text-muted" style="margin-top: 10px;">
|
||||
The time window used to evaluate the restart policy (default value is 0, which is unbounded).
|
||||
The time window used to evaluate the restart policy (default value is 0, which is unbounded). Time in seconds.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -5,10 +5,18 @@
|
||||
<rd-widget-body classes="no-padding">
|
||||
<div class="form-inline" style="padding: 10px;">
|
||||
Add a secret:
|
||||
<select class="form-control" ng-options="secret.Name for secret in secrets" ng-model="newSecret">
|
||||
<select class="form-control" ng-options="secret.Name for secret in secrets" ng-model="state.addSecret.secret">
|
||||
<option selected disabled hidden value="">Select a secret</option>
|
||||
</select>
|
||||
<a class="btn btn-default btn-sm" ng-click="addSecret(service, newSecret)">
|
||||
<div class="form-group" ng-if="applicationState.endpoint.apiVersion >= 1.30 && state.addSecret.override">
|
||||
Target:
|
||||
<input class="form-control" ng-model="state.addSecret.target" placeholder="/path/in/container">
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm" ng-if="applicationState.endpoint.apiVersion >= 1.30">
|
||||
<label class="btn btn-primary" ng-model="state.addSecret.override" uib-btn-radio="false">Default location</label>
|
||||
<label class="btn btn-primary" ng-model="state.addSecret.override" uib-btn-radio="true">Override</label>
|
||||
</div>
|
||||
<a class="btn btn-default btn-sm" ng-click="addSecret(service, state.addSecret)">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> add secret
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<p class="small text-muted" style="margin-top: 10px;">
|
||||
Amount of time between updates.
|
||||
Amount of time between updates. Time in seconds.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="service({id: service.Id})" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="services">Services</a> > <a ui-sref="service({id: service.Id})">{{ service.Name }}</a>
|
||||
@@ -69,7 +68,8 @@
|
||||
<tr>
|
||||
<td>Image</td>
|
||||
<td>
|
||||
<input type="text" class="form-control" ng-model="service.Image" ng-change="updateServiceAttribute(service, 'Image')" ng-disabled="isUpdating" />
|
||||
<input type="text" class="form-control" uib-typeahead="image for image in availableImages | filter:$viewValue | limitTo:5"
|
||||
ng-model="service.Image" ng-change="updateServiceAttribute(service, 'Image')" id="image_name" ng-disabled="isUpdating">
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="applicationState.endpoint.apiVersion >= 1.30">
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
angular.module('service', [])
|
||||
.controller('ServiceController', ['$q', '$scope', '$transition$', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'ConfigService', 'ConfigHelper', 'SecretService', 'SecretHelper', 'Service', 'ServiceHelper', 'LabelHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService',
|
||||
function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll, ServiceService, ConfigService, ConfigHelper, SecretService, SecretHelper, Service, ServiceHelper, LabelHelper, TaskService, NodeService, Notifications, Pagination, ModalService) {
|
||||
.controller('ServiceController', ['$q', '$scope', '$transition$', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'ConfigService', 'ConfigHelper', 'SecretService', 'ImageService', 'SecretHelper', 'Service', 'ServiceHelper', 'LabelHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService',
|
||||
function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll, ServiceService, ConfigService, ConfigHelper, SecretService, ImageService, SecretHelper, Service, ServiceHelper, LabelHelper, TaskService, NodeService, Notifications, Pagination, ModalService) {
|
||||
|
||||
$scope.state = {};
|
||||
$scope.state.pagination_count = Pagination.getPaginationCount('service_tasks');
|
||||
$scope.tasks = [];
|
||||
$scope.sortType = 'Updated';
|
||||
$scope.sortReverse = true;
|
||||
$scope.availableImages = [];
|
||||
|
||||
$scope.lastVersion = 0;
|
||||
|
||||
@@ -74,10 +75,16 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
$scope.updateConfig = function updateConfig(service) {
|
||||
updateServiceArray(service, 'ServiceConfigs', service.ServiceConfigs);
|
||||
};
|
||||
$scope.addSecret = function addSecret(service, secret) {
|
||||
if (secret && service.ServiceSecrets.filter(function(serviceSecret) { return serviceSecret.Id === secret.Id;}).length === 0) {
|
||||
service.ServiceSecrets.push({ Id: secret.Id, Name: secret.Name, FileName: secret.Name, Uid: '0', Gid: '0', Mode: 444 });
|
||||
updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
|
||||
$scope.addSecret = function addSecret(service, newSecret) {
|
||||
if (newSecret.secret) {
|
||||
var filename = newSecret.secret.Name;
|
||||
if (newSecret.override) {
|
||||
filename = newSecret.target;
|
||||
}
|
||||
if (service.ServiceSecrets.filter(function(serviceSecret) { return serviceSecret.Id === newSecret.secret.Id && serviceSecret.FileName === filename;}).length === 0) {
|
||||
service.ServiceSecrets.push({ Id: newSecret.secret.Id, Name: newSecret.secret.Name, FileName: filename, Uid: '0', Gid: '0', Mode: 444 });
|
||||
updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
|
||||
}
|
||||
}
|
||||
};
|
||||
$scope.removeSecret = function removeSecret(service, index) {
|
||||
@@ -200,7 +207,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
};
|
||||
|
||||
$scope.updateService = function updateService(service) {
|
||||
$('#loadingViewSpinner').show();
|
||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||
config.Name = service.Name;
|
||||
config.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceLabels);
|
||||
@@ -238,16 +244,16 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
|
||||
config.UpdateConfig = {
|
||||
Parallelism: service.UpdateParallelism,
|
||||
Delay: service.UpdateDelay,
|
||||
Delay: service.UpdateDelay * 1000000000,
|
||||
FailureAction: service.UpdateFailureAction,
|
||||
Order: service.UpdateOrder
|
||||
};
|
||||
|
||||
config.TaskTemplate.RestartPolicy = {
|
||||
Condition: service.RestartCondition,
|
||||
Delay: service.RestartDelay,
|
||||
Delay: service.RestartDelay * 1000000000,
|
||||
MaxAttempts: service.RestartMaxAttempts,
|
||||
Window: service.RestartWindow
|
||||
Window: service.RestartWindow * 1000000000
|
||||
};
|
||||
|
||||
if (service.Ports) {
|
||||
@@ -264,7 +270,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
};
|
||||
|
||||
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
if (data.message && data.message.match(/^rpc error:/)) {
|
||||
Notifications.error(data.message, 'Error');
|
||||
} else {
|
||||
@@ -273,7 +278,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
$scope.cancelChanges({});
|
||||
initView();
|
||||
}, function (e) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
Notifications.error('Failure', e, 'Unable to update service');
|
||||
});
|
||||
};
|
||||
@@ -289,7 +293,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
};
|
||||
|
||||
function removeService() {
|
||||
$('#loadingViewSpinner').show();
|
||||
ServiceService.remove($scope.service)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Service successfully deleted');
|
||||
@@ -297,9 +300,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove service');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -320,9 +320,14 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
service.LimitMemoryBytes = service.LimitMemoryBytes / 1024 / 1024 || 0;
|
||||
service.ReservationMemoryBytes = service.ReservationMemoryBytes / 1024 / 1024 || 0;
|
||||
}
|
||||
|
||||
function transformDurations(service) {
|
||||
service.RestartDelay = service.RestartDelay / 1000000000 || 5;
|
||||
service.RestartWindow = service.RestartWindow / 1000000000 || 0;
|
||||
service.UpdateDelay = service.UpdateDelay / 1000000000 || 0;
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
ServiceService.service($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
@@ -334,6 +339,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
|
||||
transformResources(service);
|
||||
translateServiceArrays(service);
|
||||
transformDurations(service);
|
||||
$scope.service = service;
|
||||
originalService = angular.copy(service);
|
||||
|
||||
@@ -341,7 +347,8 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
tasks: TaskService.tasks({ service: [service.Name] }),
|
||||
nodes: NodeService.nodes(),
|
||||
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
|
||||
configs: apiVersion >= 1.30 ? ConfigService.configs() : []
|
||||
configs: apiVersion >= 1.30 ? ConfigService.configs() : [],
|
||||
availableImages: ImageService.images()
|
||||
});
|
||||
})
|
||||
.then(function success(data) {
|
||||
@@ -349,6 +356,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
$scope.nodes = data.nodes;
|
||||
$scope.configs = data.configs;
|
||||
$scope.secrets = data.secrets;
|
||||
$scope.availableImages = ImageService.getUniqueTagListFromImages(data.availableImages);
|
||||
|
||||
// Set max cpu value
|
||||
var maxCpus = 0;
|
||||
@@ -363,6 +371,9 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
$scope.state.sliderMaxCpu = 32;
|
||||
}
|
||||
|
||||
// Default values
|
||||
$scope.state.addSecret = {override: false};
|
||||
|
||||
$timeout(function() {
|
||||
$anchorScroll();
|
||||
});
|
||||
@@ -371,9 +382,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||
$scope.secrets = [];
|
||||
$scope.configs = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve service details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,8 @@ function ($scope, $transition$, $anchorScroll, ServiceLogs, Service) {
|
||||
$scope.tailLines = 2000;
|
||||
|
||||
function getLogs() {
|
||||
$('#loadingViewSpinner').show();
|
||||
getLogsStdout();
|
||||
getLogsStderr();
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
|
||||
function getLogsStderr() {
|
||||
@@ -48,13 +46,10 @@ function ($scope, $transition$, $anchorScroll, ServiceLogs, Service) {
|
||||
}
|
||||
|
||||
function getService() {
|
||||
$('#loadingViewSpinner').show();
|
||||
Service.get({id: $transition$.params().id}, function (d) {
|
||||
$scope.service = d;
|
||||
$('#loadingViewSpinner').hide();
|
||||
}, function (e) {
|
||||
Notifications.error('Failure', e, 'Unable to retrieve service info');
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Service logs">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Service logs"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="services">Services</a> > <a ui-sref="service({id: service.ID})">{{ service.Spec.Name }}</a> > Logs
|
||||
</rd-header-content>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="services" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadServicesSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Services</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -88,7 +87,7 @@
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="service in (state.filteredServices = ( services | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))">
|
||||
<tr dir-paginate="service in (state.filteredServices = ( services | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-class="{active: service.Checked}">
|
||||
<td><input type="checkbox" ng-model="service.Checked" ng-change="selectItem(service)"/></td>
|
||||
<td><a ui-sref="service({id: service.Id})">{{ service.Name }}</a></td>
|
||||
<td>{{ service.StackName ? service.StackName : '-' }}</td>
|
||||
@@ -108,7 +107,7 @@
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a ng-if="service.Ports && service.Ports.length > 0 && swarmManagerIP" ng-repeat="p in service.Ports" class="image-tag" ng-href="http://{{swarmManagerIP}}:{{p.PublishedPort}}" target="_blank">
|
||||
<a ng-if="service.Ports && service.Ports.length > 0 && swarmManagerIP && p.PublishedPort" ng-repeat="p in service.Ports" class="image-tag" ng-href="http://{{swarmManagerIP}}:{{p.PublishedPort}}" target="_blank">
|
||||
<i class="fa fa-external-link" aria-hidden="true"></i> {{ p.PublishedPort }}:{{ p.TargetPort }}
|
||||
</a>
|
||||
<span ng-if="!service.Ports || service.Ports.length === 0 || !swarmManagerIP" >-</span>
|
||||
|
||||
@@ -25,15 +25,12 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
|
||||
};
|
||||
|
||||
$scope.scaleService = function scaleService(service) {
|
||||
$('#loadServicesSpinner').show();
|
||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||
config.Mode.Replicated.Replicas = service.Replicas;
|
||||
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
||||
$('#loadServicesSpinner').hide();
|
||||
Notifications.success('Service successfully scaled', 'New replica count: ' + service.Replicas);
|
||||
$state.reload();
|
||||
}, function (e) {
|
||||
$('#loadServicesSpinner').hide();
|
||||
service.Scale = false;
|
||||
service.Replicas = service.ReplicaCount;
|
||||
Notifications.error('Failure', e, 'Unable to scale service');
|
||||
@@ -51,17 +48,8 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
|
||||
};
|
||||
|
||||
function removeServices() {
|
||||
$('#loadServicesSpinner').show();
|
||||
var counter = 0;
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadServicesSpinner').hide();
|
||||
}
|
||||
};
|
||||
angular.forEach($scope.services, function (service) {
|
||||
if (service.Checked) {
|
||||
counter = counter + 1;
|
||||
ServiceService.remove(service)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Service successfully deleted');
|
||||
@@ -70,9 +58,6 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove service');
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -94,7 +79,6 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadServicesSpinner').show();
|
||||
$q.all({
|
||||
services: Service.query({}).$promise,
|
||||
tasks: Task.query({filters: {'desired-state': ['running','accepted']}}).$promise,
|
||||
@@ -118,9 +102,6 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
|
||||
.catch(function error(err) {
|
||||
$scope.services = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve services');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadServicesSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Settings">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Settings"></rd-header-title>
|
||||
<rd-header-content>Settings</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -11,6 +9,43 @@
|
||||
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
|
||||
<rd-widget-body>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<label for="toggle_donation" class="control-label text-left">
|
||||
Disable donation header
|
||||
</label>
|
||||
<label class="switch" style="margin-left: 20px;">
|
||||
<input type="checkbox" name="toggle_donation" ng-model="formValues.donationHeader"><i></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- logo -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<label for="toggle_logo" class="control-label text-left">
|
||||
Use custom logo
|
||||
</label>
|
||||
<label class="switch" style="margin-left: 20px;">
|
||||
<input type="checkbox" name="toggle_logo" ng-model="formValues.customLogo"><i></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="formValues.customLogo">
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
You can specify the URL to your logo here. For an optimal display, logo dimensions should be 155px by 55px.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="logo_url" class="col-sm-1 control-label text-left">
|
||||
URL
|
||||
</label>
|
||||
<div class="col-sm-11">
|
||||
<input type="text" class="form-control" ng-model="settings.LogoURL" id="logo_url" placeholder="https://mycompany.com/logo.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !logo -->
|
||||
<!-- security -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Security
|
||||
@@ -38,36 +73,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- security -->
|
||||
<!-- logo -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Logo
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<label for="toggle_logo" class="control-label text-left">
|
||||
Use custom logo
|
||||
</label>
|
||||
<label class="switch" style="margin-left: 20px;">
|
||||
<input type="checkbox" name="toggle_logo" ng-model="formValues.customLogo"><i></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="formValues.customLogo">
|
||||
<div class="form-group">
|
||||
<span class="col-sm-12 text-muted small">
|
||||
You can specify the URL to your logo here. For an optimal display, logo dimensions should be 155px by 55px.
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="logo_url" class="col-sm-1 control-label text-left">
|
||||
URL
|
||||
</label>
|
||||
<div class="col-sm-11">
|
||||
<input type="text" class="form-control" ng-model="settings.LogoURL" id="logo_url" placeholder="https://mycompany.com/logo.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !logo -->
|
||||
<!-- app-templates -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
App Templates
|
||||
@@ -112,9 +117,10 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="saveApplicationSettings()">Save</button>
|
||||
<i id="updateSettingsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<!-- <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> -->
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="saveApplicationSettings()" ng-disabled="state.actionInProgress" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Save settings</span>
|
||||
<span ng-show="state.actionInProgress">Saving...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
|
||||
@@ -2,9 +2,14 @@ angular.module('settings', [])
|
||||
.controller('SettingsController', ['$scope', '$state', 'Notifications', 'SettingsService', 'StateManager', 'DEFAULT_TEMPLATES_URL',
|
||||
function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_TEMPLATES_URL) {
|
||||
|
||||
$scope.state = {
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
customLogo: false,
|
||||
customTemplates: false,
|
||||
donationHeader: true,
|
||||
externalContributions: false,
|
||||
restrictBindMounts: false,
|
||||
restrictPrivilegedMode: false,
|
||||
@@ -41,10 +46,12 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||
settings.TemplatesURL = DEFAULT_TEMPLATES_URL;
|
||||
}
|
||||
|
||||
settings.DisplayDonationHeader = !$scope.formValues.donationHeader;
|
||||
settings.DisplayExternalContributors = !$scope.formValues.externalContributions;
|
||||
settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts;
|
||||
settings.AllowPrivilegedModeForRegularUsers = !$scope.formValues.restrictPrivilegedMode;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
updateSettings(settings, false);
|
||||
};
|
||||
|
||||
@@ -54,12 +61,11 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||
}
|
||||
|
||||
function updateSettings(settings, resetForm) {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
SettingsService.update(settings)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Settings updated');
|
||||
StateManager.updateLogo(settings.LogoURL);
|
||||
StateManager.updateDonationHeader(settings.DisplayDonationHeader);
|
||||
StateManager.updateExternalContributions(settings.DisplayExternalContributors);
|
||||
if (resetForm) {
|
||||
resetFormValues();
|
||||
@@ -69,12 +75,11 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||
Notifications.error('Failure', err, 'Unable to update settings');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
SettingsService.settings()
|
||||
.then(function success(data) {
|
||||
var settings = data;
|
||||
@@ -85,15 +90,13 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||
if (settings.TemplatesURL !== DEFAULT_TEMPLATES_URL) {
|
||||
$scope.formValues.customTemplates = true;
|
||||
}
|
||||
$scope.formValues.donationHeader = !settings.DisplayDonationHeader;
|
||||
$scope.formValues.externalContributions = !settings.DisplayExternalContributors;
|
||||
$scope.formValues.restrictBindMounts = !settings.AllowBindMountsForRegularUsers;
|
||||
$scope.formValues.restrictPrivilegedMode = !settings.AllowPrivilegedModeForRegularUsers;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve application settings');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Authentication settings">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Authentication settings"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="settings">Settings</a> > Authentication
|
||||
</rd-header-content>
|
||||
@@ -100,8 +98,10 @@
|
||||
<i class="fa fa-times red-icon" style="margin-left: 5px;" ng-if="state.failedConnectivityCheck"></i>
|
||||
</label>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!LDAPSettings.URL || !LDAPSettings.ReaderDN || !LDAPSettings.Password" ng-click="LDAPConnectivityCheck()">Test connectivity</button>
|
||||
<i id="connectivityCheckSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.connectivityCheckInProgress || !LDAPSettings.URL || !LDAPSettings.ReaderDN || !LDAPSettings.Password" ng-click="LDAPConnectivityCheck()" button-spinner="state.connectivityCheckInProgress">
|
||||
<span ng-hide="state.connectivityCheckInProgress">Test connectivity</span>
|
||||
<span ng-show="state.connectivityCheckInProgress">Testing connectivity...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -240,9 +240,10 @@
|
||||
<!-- actions -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()">Save</button>
|
||||
<i id="updateSettingsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<!-- <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> -->
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()" ng-disabled="state.actionInProgress" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Save settings</span>
|
||||
<span ng-show="state.actionInProgress">Saving...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !actions -->
|
||||
|
||||
@@ -5,7 +5,9 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
|
||||
$scope.state = {
|
||||
successfulConnectivityCheck: false,
|
||||
failedConnectivityCheck: false,
|
||||
uploadInProgress: false
|
||||
uploadInProgress: false,
|
||||
connectivityCheckInProgress: false,
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
@@ -21,13 +23,13 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
|
||||
};
|
||||
|
||||
$scope.LDAPConnectivityCheck = function() {
|
||||
$('#connectivityCheckSpinner').show();
|
||||
var settings = $scope.settings;
|
||||
var TLSCAFile = $scope.formValues.TLSCACert !== settings.LDAPSettings.TLSConfig.TLSCACert ? $scope.formValues.TLSCACert : null;
|
||||
|
||||
var uploadRequired = ($scope.LDAPSettings.TLSConfig.TLS || $scope.LDAPSettings.StartTLS) && !$scope.LDAPSettings.TLSConfig.TLSSkipVerify;
|
||||
$scope.state.uploadInProgress = uploadRequired;
|
||||
|
||||
$scope.state.connectivityCheckInProgress = true;
|
||||
$q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null))
|
||||
.then(function success(data) {
|
||||
return SettingsService.checkLDAPConnectivity(settings);
|
||||
@@ -44,18 +46,18 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
|
||||
})
|
||||
.finally(function final() {
|
||||
$scope.state.uploadInProgress = false;
|
||||
$('#connectivityCheckSpinner').hide();
|
||||
$scope.state.connectivityCheckInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.saveSettings = function() {
|
||||
$('#updateSettingsSpinner').show();
|
||||
var settings = $scope.settings;
|
||||
var TLSCAFile = $scope.formValues.TLSCACert !== settings.LDAPSettings.TLSConfig.TLSCACert ? $scope.formValues.TLSCACert : null;
|
||||
|
||||
var uploadRequired = ($scope.LDAPSettings.TLSConfig.TLS || $scope.LDAPSettings.StartTLS) && !$scope.LDAPSettings.TLSConfig.TLSSkipVerify;
|
||||
$scope.state.uploadInProgress = uploadRequired;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
$q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null))
|
||||
.then(function success(data) {
|
||||
return SettingsService.update(settings);
|
||||
@@ -68,12 +70,11 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
|
||||
})
|
||||
.finally(function final() {
|
||||
$scope.state.uploadInProgress = false;
|
||||
$('#updateSettingsSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
SettingsService.settings()
|
||||
.then(function success(data) {
|
||||
var settings = data;
|
||||
@@ -83,9 +84,6 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve application settings');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,75 +9,75 @@
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
<ul class="sidebar">
|
||||
<li class="sidebar-title">
|
||||
<span>Active endpoint</span>
|
||||
</li>
|
||||
<li class="sidebar-title"><span>Active endpoint</span></li>
|
||||
<li class="sidebar-title">
|
||||
<select class="select-endpoint form-control" ng-options="endpoint.Name for endpoint in endpoints" ng-model="activeEndpoint" ng-change="switchEndpoint(activeEndpoint)">
|
||||
</select>
|
||||
</li>
|
||||
<li class="sidebar-title"><span>Endpoint actions</span></li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="dashboard" ui-sref-active="active">Dashboard <span class="menu-icon fa fa-tachometer"></span></a>
|
||||
<a ui-sref="dashboard" ui-sref-active="active">Dashboard <span class="menu-icon fa fa-tachometer fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="templates" ui-sref-active="active">App Templates <span class="menu-icon fa fa-rocket"></span></a>
|
||||
<a ui-sref="templates" ui-sref-active="active">App Templates <span class="menu-icon fa fa-rocket fa-fw"></span></a>
|
||||
<div class="sidebar-sublist" ng-if="toggle && displayExternalContributors && ($state.current.name === 'templates' || $state.current.name === 'templates_linuxserver')">
|
||||
<a ui-sref="templates_linuxserver" ui-sref-active="active">LinuxServer.io</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.apiVersion >= 1.25 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<a ui-sref="stacks" ui-sref-active="active">Stacks <span class="menu-icon fa fa-th-list"></span></a>
|
||||
<a ui-sref="stacks" ui-sref-active="active">Stacks <span class="menu-icon fa fa-th-list fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<a ui-sref="services" ui-sref-active="active">Services <span class="menu-icon fa fa-list-alt"></span></a>
|
||||
<a ui-sref="services" ui-sref-active="active">Services <span class="menu-icon fa fa-list-alt fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="containers" ui-sref-active="active">Containers <span class="menu-icon fa fa-server"></span></a>
|
||||
<a ui-sref="containers" ui-sref-active="active">Containers <span class="menu-icon fa fa-server fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="images" ui-sref-active="active">Images <span class="menu-icon fa fa-clone"></span></a>
|
||||
<a ui-sref="images" ui-sref-active="active">Images <span class="menu-icon fa fa-clone fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="networks" ui-sref-active="active">Networks <span class="menu-icon fa fa-sitemap"></span></a>
|
||||
<a ui-sref="networks" ui-sref-active="active">Networks <span class="menu-icon fa fa-sitemap fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list">
|
||||
<a ui-sref="volumes" ui-sref-active="active">Volumes <span class="menu-icon fa fa-cubes"></span></a>
|
||||
<a ui-sref="volumes" ui-sref-active="active">Volumes <span class="menu-icon fa fa-cubes fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.apiVersion >= 1.30 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<a ui-sref="configs" ui-sref-active="active">Configs <span class="menu-icon fa fa-file-code-o"></span></a>
|
||||
<a ui-sref="configs" ui-sref-active="active">Configs <span class="menu-icon fa fa-file-code-o fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.apiVersion >= 1.25 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'">
|
||||
<a ui-sref="secrets" ui-sref-active="active">Secrets <span class="menu-icon fa fa-user-secret"></span></a>
|
||||
<a ui-sref="secrets" ui-sref-active="active">Secrets <span class="menu-icon fa fa-user-secret fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="(applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE' || applicationState.endpoint.mode.provider === 'VMWARE_VIC') && isAdmin">
|
||||
<a ui-sref="events" ui-sref-active="active">Events <span class="menu-icon fa fa-history"></span></a>
|
||||
<a ui-sref="events" ui-sref-active="active">Events <span class="menu-icon fa fa-history fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.mode.provider === 'DOCKER_SWARM' || (applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER')">
|
||||
<a ui-sref="swarm" ui-sref-active="active">Swarm <span class="menu-icon fa fa-object-group"></span></a>
|
||||
<a ui-sref="swarm" ui-sref-active="active">Swarm <span class="menu-icon fa fa-object-group fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE' || applicationState.endpoint.mode.provider === 'VMWARE_VIC'">
|
||||
<a ui-sref="engine" ui-sref-active="active">Engine <span class="menu-icon fa fa-th"></span></a>
|
||||
<a ui-sref="engine" ui-sref-active="active">Engine <span class="menu-icon fa fa-th fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-title" ng-if="!applicationState.application.authentication || isAdmin || isTeamLeader">
|
||||
<span>Portainer settings</span>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="applicationState.application.authentication && (isAdmin || isTeamLeader)">
|
||||
<a ui-sref="users" ui-sref-active="active">User management <span class="menu-icon fa fa-users"></span></a>
|
||||
<a ui-sref="users" ui-sref-active="active">User management <span class="menu-icon fa fa-users fa-fw"></span></a>
|
||||
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'users' || $state.current.name === 'user' || $state.current.name === 'teams' || $state.current.name === 'team')">
|
||||
<a ui-sref="teams" ui-sref-active="active">Teams</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="!applicationState.application.authentication || isAdmin">
|
||||
<a ui-sref="endpoints" ui-sref-active="active">Endpoints <span class="menu-icon fa fa-plug"></span></a>
|
||||
<a ui-sref="endpoints" ui-sref-active="active">Endpoints <span class="menu-icon fa fa-plug fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="!applicationState.application.authentication || isAdmin">
|
||||
<a ui-sref="registries" ui-sref-active="active">Registries <span class="menu-icon fa fa-database"></span></a>
|
||||
<a ui-sref="registries" ui-sref-active="active">Registries <span class="menu-icon fa fa-database fa-fw"></span></a>
|
||||
</li>
|
||||
<li class="sidebar-list" ng-if="!applicationState.application.authentication || isAdmin">
|
||||
<a ui-sref="settings" ui-sref-active="active">Settings <span class="menu-icon fa fa-cogs"></span></a>
|
||||
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'settings' || $state.current.name === 'settings_authentication') && applicationState.application.authentication && isAdmin">
|
||||
<a ui-sref="settings_authentication" ui-sref-active="active">Authentication</a>
|
||||
<a ui-sref="settings" ui-sref-active="active">Settings <span class="menu-icon fa fa-cogs fa-fw"></span></a>
|
||||
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'settings' || $state.current.name === 'settings_authentication' || $state.current.name === 'settings_about') && applicationState.application.authentication && isAdmin">
|
||||
<a ui-sref="settings_authentication" ui-sref-active="active">Authentication</a></div>
|
||||
<div class="sidebar-sublist" ng-if="toggle && ($state.current.name === 'settings' || $state.current.name === 'settings_authentication' || $state.current.name === 'settings_about')">
|
||||
<a ui-sref="settings_about" ui-sref-active="active">About</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="stack({id: stack.Id})" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="stacks">Stacks</a> > <a ui-sref="stack({id: stack.Id})">{{ stack.Name }}</a>
|
||||
@@ -73,8 +72,10 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-sm btn-primary" ng-click="deployStack()">Update stack</button>
|
||||
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
<button type="button" class="btn btn-sm btn-primary" ng-disabled="state.actionInProgress" ng-click="deployStack()" button-spinner="state.actionInProgress">
|
||||
<span ng-hide="state.actionInProgress">Update the stack</span>
|
||||
<span ng-show="state.actionInProgress">Deployment in progress...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -2,14 +2,17 @@ angular.module('stack', [])
|
||||
.controller('StackController', ['$q', '$scope', '$state', '$stateParams', '$document', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ServiceHelper', 'CodeMirrorService', 'Notifications', 'FormHelper',
|
||||
function ($q, $scope, $state, $stateParams, $document, StackService, NodeService, ServiceService, TaskService, ServiceHelper, CodeMirrorService, Notifications, FormHelper) {
|
||||
|
||||
$scope.deployStack = function () {
|
||||
$('#createResourceSpinner').show();
|
||||
$scope.state = {
|
||||
actionInProgress: false
|
||||
};
|
||||
|
||||
$scope.deployStack = function () {
|
||||
// The codemirror editor does not work with ng-model so we need to retrieve
|
||||
// the value directly from the editor.
|
||||
var stackFile = $scope.editor.getValue();
|
||||
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
StackService.updateStack($scope.stack.Id, stackFile, env)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
@@ -19,7 +22,7 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
|
||||
Notifications.error('Failure', err, 'Unable to create stack');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#createResourceSpinner').hide();
|
||||
$scope.state.actionInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -32,7 +35,6 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var stackId = $stateParams.id;
|
||||
|
||||
StackService.stack(stackId)
|
||||
@@ -77,9 +79,6 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve tasks details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="stacks" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Stacks</rd-header-content>
|
||||
</rd-header>
|
||||
@@ -85,7 +84,7 @@
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="stack in (state.filteredStacks = ( stacks | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-if="state.DisplayExternalStacks || (!state.DisplayExternalStacks && !stack.External)">
|
||||
<tr dir-paginate="stack in (state.filteredStacks = ( stacks | filter:state.filter | orderBy:sortType:sortReverse | itemsPerPage: state.pagination_count))" ng-if="state.DisplayExternalStacks || (!state.DisplayExternalStacks && !stack.External)" ng-class="{active: stacks.Checked}">
|
||||
<td><input type="checkbox" ng-model="stack.Checked" ng-change="selectItem(stack)" ng-disabled="!stack.Id"/></td>
|
||||
<td>
|
||||
<span ng-if="stack.Id">
|
||||
|
||||
@@ -46,19 +46,8 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
|
||||
};
|
||||
|
||||
function deleteSelectedStacks() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var counter = 0;
|
||||
|
||||
var complete = function () {
|
||||
counter = counter - 1;
|
||||
if (counter === 0) {
|
||||
$('#loadingViewSpinner').hide();
|
||||
}
|
||||
};
|
||||
|
||||
angular.forEach($scope.stacks, function (stack) {
|
||||
if (stack.Checked) {
|
||||
counter = counter + 1;
|
||||
StackService.remove(stack)
|
||||
.then(function success() {
|
||||
Notifications.success('Stack deleted', stack.Name);
|
||||
@@ -67,17 +56,12 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove stack ' + stack.Name);
|
||||
})
|
||||
.finally(function final() {
|
||||
complete();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
StackService.stacks(true)
|
||||
.then(function success(data) {
|
||||
var stacks = data;
|
||||
@@ -93,9 +77,6 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
|
||||
.catch(function error(err) {
|
||||
$scope.stacks = [];
|
||||
Notifications.error('Failure', err, 'Unable to retrieve stacks');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="swarm" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>Swarm</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
@@ -72,8 +72,6 @@ function ($q, $scope, SystemService, NodeService, Pagination, Notifications, Sta
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
|
||||
if (StateManager.getState().application.authentication) {
|
||||
var userDetails = Authentication.getUserDetails();
|
||||
var isAdmin = userDetails.role === 1 ? true: false;
|
||||
@@ -99,9 +97,6 @@ function ($q, $scope, SystemService, NodeService, Pagination, Notifications, Sta
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve cluster details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<a data-toggle="tooltip" title="Refresh" ui-sref="swarm.visualizer" ui-sref-opts="{reload: true}">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i>
|
||||
</a>
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="swarm">Swarm</a> > <a ui-sref="swarm.visualizer">Cluster visualizer</a>
|
||||
|
||||
@@ -47,7 +47,6 @@ function ($q, $scope, $document, NodeService, ServiceService, TaskService, Notif
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
$q.all({
|
||||
nodes: NodeService.nodes(),
|
||||
services: ServiceService.services(),
|
||||
@@ -64,9 +63,6 @@ function ($q, $scope, $document, NodeService, ServiceService, TaskService, Notif
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to initialize cluster visualizer');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Task details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Task details"></rd-header-title>
|
||||
<rd-header-content ng-if="task && service">
|
||||
<a ui-sref="services">Services</a> > <a ui-sref="service({id: service.Id })">{{ service.Name }}</a> > {{ task.Id }}
|
||||
</rd-header-content>
|
||||
|
||||
@@ -3,7 +3,6 @@ angular.module('task', [])
|
||||
function ($scope, $transition$, TaskService, Service, Notifications) {
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
TaskService.task($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
var task = data;
|
||||
@@ -16,9 +15,6 @@ function ($scope, $transition$, TaskService, Service, Notifications) {
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve task details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<rd-header>
|
||||
<rd-header-title title="Team details">
|
||||
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
|
||||
</rd-header-title>
|
||||
<rd-header-title title="Team details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="teams">Teams</a> > <a ui-sref="team({id: team.Id})">{{ team.Name }}</a>
|
||||
</rd-header-content>
|
||||
|
||||
@@ -44,7 +44,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
};
|
||||
|
||||
$scope.promoteToLeader = function(user) {
|
||||
$('#loadingViewSpinner').show();
|
||||
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 1)
|
||||
.then(function success(data) {
|
||||
$scope.leaderCount++;
|
||||
@@ -53,14 +52,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update user role');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.demoteToMember = function(user) {
|
||||
$('#loadingViewSpinner').show();
|
||||
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 2)
|
||||
.then(function success(data) {
|
||||
user.TeamRole = 'Member';
|
||||
@@ -69,14 +64,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update user role');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addAllUsers = function() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var teamMembershipQueries = [];
|
||||
angular.forEach($scope.users, function (user) {
|
||||
teamMembershipQueries.push(TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2));
|
||||
@@ -95,14 +86,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update team members');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addUser = function(user) {
|
||||
$('#loadingViewSpinner').show();
|
||||
TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2)
|
||||
.then(function success(data) {
|
||||
removeUserFromArray(user.Id, $scope.users);
|
||||
@@ -113,14 +100,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update team members');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeAllUsers = function() {
|
||||
$('#loadingViewSpinner').show();
|
||||
var teamMembershipQueries = [];
|
||||
angular.forEach($scope.teamMembers, function (user) {
|
||||
teamMembershipQueries.push(TeamMembershipService.deleteMembership(user.MembershipId));
|
||||
@@ -133,14 +116,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update team members');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeUser = function(user) {
|
||||
$('#loadingViewSpinner').show();
|
||||
TeamMembershipService.deleteMembership(user.MembershipId)
|
||||
.then(function success() {
|
||||
removeUserFromArray(user.Id, $scope.teamMembers);
|
||||
@@ -149,14 +128,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update team members');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
};
|
||||
|
||||
function deleteTeam() {
|
||||
$('#loadingViewSpinner').show();
|
||||
TeamService.deleteTeam($scope.team.Id)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Team successfully deleted', $scope.team.Name);
|
||||
@@ -164,9 +139,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove team');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -205,7 +177,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
}
|
||||
|
||||
function initView() {
|
||||
$('#loadingViewSpinner').show();
|
||||
$scope.isAdmin = Authentication.getUserDetails().role === 1 ? true: false;
|
||||
$q.all({
|
||||
team: TeamService.team($transition$.params().id),
|
||||
@@ -219,9 +190,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve team details');
|
||||
})
|
||||
.finally(function final() {
|
||||
$('#loadingViewSpinner').hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user