feat(ux): replace spinners (#1383)

pull/1385/head
Anthony Lapenna 2017-11-12 20:27:28 +01:00 committed by GitHub
parent 9bef7cd69f
commit d68708add7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 701 additions and 1061 deletions

View File

@ -9,6 +9,7 @@ angular.module('portainer', [
'LocalStorageModule', 'LocalStorageModule',
'angular-jwt', 'angular-jwt',
'angular-google-analytics', 'angular-google-analytics',
'angular-loading-bar',
'portainer.templates', 'portainer.templates',
'portainer.filters', 'portainer.filters',
'portainer.rest', 'portainer.rest',

View File

@ -1,5 +1,5 @@
angular.module('portainer') 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'; 'use strict';
EndpointProvider.initialize(); EndpointProvider.initialize();
@ -18,6 +18,15 @@ angular.module('portainer')
}); });
$rootScope.$state = $state; $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);
}
};
}]); }]);

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="config({id: config.Id})" ui-sref-opts="{reload: true}"> <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> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="configs">Configs</a> &gt; <a ui-sref="config({id: config.Id})">{{ config.Name }}</a> <a ui-sref="configs">Configs</a> &gt; <a ui-sref="config({id: config.Id})">{{ config.Name }}</a>

View File

@ -3,7 +3,6 @@ angular.module('config', [])
function ($scope, $transition$, $state, $document, ConfigService, Notifications, CodeMirrorService) { function ($scope, $transition$, $state, $document, ConfigService, Notifications, CodeMirrorService) {
$scope.removeConfig = function removeConfig(configId) { $scope.removeConfig = function removeConfig(configId) {
$('#loadingViewSpinner').show();
ConfigService.remove(configId) ConfigService.remove(configId)
.then(function success(data) { .then(function success(data) {
Notifications.success('Config successfully removed'); Notifications.success('Config successfully removed');
@ -11,9 +10,6 @@ function ($scope, $transition$, $state, $document, ConfigService, Notifications,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove config'); 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() { function initView() {
$('#loadingViewSpinner').show();
ConfigService.config($transition$.params().id) ConfigService.config($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.config = data; $scope.config = data;
@ -35,9 +30,6 @@ function ($scope, $transition$, $state, $document, ConfigService, Notifications,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve config details'); Notifications.error('Failure', err, 'Unable to retrieve config details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="configs" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="configs" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Configs</rd-header-content> <rd-header-content>Configs</rd-header-content>
</rd-header> </rd-header>

View File

@ -30,17 +30,8 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
}; };
$scope.removeAction = function () { $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) { angular.forEach($scope.configs, function (config) {
if (config.Checked) { if (config.Checked) {
counter = counter + 1;
ConfigService.remove(config.Id) ConfigService.remove(config.Id)
.then(function success() { .then(function success() {
Notifications.success('Config deleted', config.Id); Notifications.success('Config deleted', config.Id);
@ -49,16 +40,12 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove config'); Notifications.error('Failure', err, 'Unable to remove config');
})
.finally(function final() {
complete();
}); });
} }
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
ConfigService.configs() ConfigService.configs()
.then(function success(data) { .then(function success(data) {
$scope.configs = data; $scope.configs = data;
@ -66,9 +53,6 @@ function ($scope, $stateParams, $state, ConfigService, Notifications, Pagination
.catch(function error(err) { .catch(function error(err) {
$scope.configs = []; $scope.configs = [];
Notifications.error('Failure', err, 'Unable to retrieve configs'); Notifications.error('Failure', err, 'Unable to retrieve configs');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,13 +1,12 @@
<rd-header> <rd-header>
<rd-header-title title="Container details"> <rd-header-title title="Container details">
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> <a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a>
</rd-header-content> </rd-header-content>
</rd-header> </rd-header>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-cogs" title="Actions"></rd-widget-header> <rd-widget-header icon="fa-cogs" title="Actions"></rd-widget-header>
@ -26,9 +25,9 @@
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-server" title="Container status"></rd-widget-header> <rd-widget-header icon="fa-server" title="Container status"></rd-widget-header>
@ -92,18 +91,18 @@
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<!-- access-control-panel --> <!-- access-control-panel -->
<por-access-control-panel <por-access-control-panel
ng-if="container && applicationState.application.authentication" ng-if="container && applicationState.application.authentication"
resource-id="container.Id" resource-id="container.Id"
resource-control="container.ResourceControl" resource-control="container.ResourceControl"
resource-type="'container'"> resource-type="'container'">
</por-access-control-panel> </por-access-control-panel>
<!-- !access-control-panel --> <!-- !access-control-panel -->
<div ng-if="container.State.Health" class="row"> <div ng-if="container.State.Health" class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-server" title="Container health"></rd-widget-header> <rd-widget-header icon="fa-server" title="Container health"></rd-widget-header>
@ -130,9 +129,9 @@
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header> <rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header>
@ -163,16 +162,15 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button> <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>
</div> </div>
</form> </form>
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-server" title="Container details"></rd-widget-header> <rd-widget-header icon="fa-server" title="Container details"></rd-widget-header>
@ -239,9 +237,9 @@
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<div class="row" ng-if="container.Mounts.length > 0"> <div class="row" ng-if="container.Mounts.length > 0">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header> <rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header>
@ -264,9 +262,9 @@
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-sitemap" title="Connected networks"> <rd-widget-header icon="fa-sitemap" title="Connected networks">
@ -297,7 +295,10 @@
<td>{{ value.Gateway || '-' }}</td> <td>{{ value.Gateway || '-' }}</td>
<td>{{ value.MacAddress || '-' }}</td> <td>{{ value.MacAddress || '-' }}</td>
<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> <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> </td>
</tr> </tr>
<tr ng-if="(container.NetworkSettings.Networks | emptyobject)"> <tr ng-if="(container.NetworkSettings.Networks | emptyobject)">
@ -320,11 +321,14 @@
</select> </select>
</div> </div>
<div class="col-sm-1"> <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> <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>
</div> </div>
</form> </form>
</rd-widget-body> </rd-widget-body>
</rd-widget> </rd-widget>
</div> </div>
</div> </div>

View File

@ -7,15 +7,17 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
Image: '', Image: '',
Registry: '' Registry: ''
}; };
$scope.state = {}; $scope.state = {
$scope.state.pagination_count = Pagination.getPaginationCount('container_networks'); joinNetworkInProgress: false,
leaveNetworkInProgress: false,
pagination_count: Pagination.getPaginationCount('container_networks')
};
$scope.changePaginationCount = function() { $scope.changePaginationCount = function() {
Pagination.setPaginationCount('container_networks', $scope.state.pagination_count); Pagination.setPaginationCount('container_networks', $scope.state.pagination_count);
}; };
var update = function () { var update = function () {
$('#loadingViewSpinner').show();
Container.get({id: $transition$.params().id}, function (d) { Container.get({id: $transition$.params().id}, function (d) {
var container = new ContainerDetailsViewModel(d); var container = new ContainerDetailsViewModel(d);
$scope.container = container; $scope.container = container;
@ -41,15 +43,12 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
} }
}); });
} }
$('#loadingViewSpinner').hide();
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to retrieve container info'); Notifications.error('Failure', e, 'Unable to retrieve container info');
}); });
}; };
$scope.start = function () { $scope.start = function () {
$('#loadingViewSpinner').show();
Container.start({id: $scope.container.Id}, {}, function (d) { Container.start({id: $scope.container.Id}, {}, function (d) {
update(); update();
Notifications.success('Container started', $transition$.params().id); Notifications.success('Container started', $transition$.params().id);
@ -60,7 +59,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}; };
$scope.stop = function () { $scope.stop = function () {
$('#loadingViewSpinner').show();
Container.stop({id: $transition$.params().id}, function (d) { Container.stop({id: $transition$.params().id}, function (d) {
update(); update();
Notifications.success('Container stopped', $transition$.params().id); Notifications.success('Container stopped', $transition$.params().id);
@ -71,7 +69,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}; };
$scope.kill = function () { $scope.kill = function () {
$('#loadingViewSpinner').show();
Container.kill({id: $transition$.params().id}, function (d) { Container.kill({id: $transition$.params().id}, function (d) {
update(); update();
Notifications.success('Container killed', $transition$.params().id); Notifications.success('Container killed', $transition$.params().id);
@ -82,23 +79,19 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}; };
$scope.commit = function () { $scope.commit = function () {
$('#createImageSpinner').show();
var image = $scope.config.Image; var image = $scope.config.Image;
var registry = $scope.config.Registry; var registry = $scope.config.Registry;
var imageConfig = ImageHelper.createImageConfigForCommit(image, registry.URL); var imageConfig = ImageHelper.createImageConfigForCommit(image, registry.URL);
ContainerCommit.commit({id: $transition$.params().id, tag: imageConfig.tag, repo: imageConfig.repo}, function (d) { ContainerCommit.commit({id: $transition$.params().id, tag: imageConfig.tag, repo: imageConfig.repo}, function (d) {
$('#createImageSpinner').hide();
update(); update();
Notifications.success('Container commited', $transition$.params().id); Notifications.success('Container commited', $transition$.params().id);
}, function (e) { }, function (e) {
$('#createImageSpinner').hide();
update(); update();
Notifications.error('Failure', e, 'Unable to commit container'); Notifications.error('Failure', e, 'Unable to commit container');
}); });
}; };
$scope.pause = function () { $scope.pause = function () {
$('#loadingViewSpinner').show();
Container.pause({id: $transition$.params().id}, function (d) { Container.pause({id: $transition$.params().id}, function (d) {
update(); update();
Notifications.success('Container paused', $transition$.params().id); Notifications.success('Container paused', $transition$.params().id);
@ -109,7 +102,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}; };
$scope.unpause = function () { $scope.unpause = function () {
$('#loadingViewSpinner').show();
Container.unpause({id: $transition$.params().id}, function (d) { Container.unpause({id: $transition$.params().id}, function (d) {
update(); update();
Notifications.success('Container unpaused', $transition$.params().id); Notifications.success('Container unpaused', $transition$.params().id);
@ -138,7 +130,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}; };
$scope.remove = function(cleanAssociatedVolumes) { $scope.remove = function(cleanAssociatedVolumes) {
$('#loadingViewSpinner').show();
ContainerService.remove($scope.container, cleanAssociatedVolumes) ContainerService.remove($scope.container, cleanAssociatedVolumes)
.then(function success() { .then(function success() {
Notifications.success('Container successfully removed'); Notifications.success('Container successfully removed');
@ -146,14 +137,10 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove container'); Notifications.error('Failure', err, 'Unable to remove container');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.restart = function () { $scope.restart = function () {
$('#loadingViewSpinner').show();
Container.restart({id: $transition$.params().id}, function (d) { Container.restart({id: $transition$.params().id}, function (d) {
update(); update();
Notifications.success('Container restarted', $transition$.params().id); 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) { $scope.containerLeaveNetwork = function containerLeaveNetwork(container, networkId) {
$('#loadingViewSpinner').show(); $scope.state.leaveNetworkInProgress = true;
Network.disconnect({id: networkId}, { Container: $transition$.params().id, Force: false }, function (d) { Network.disconnect({id: networkId}, { Container: $transition$.params().id, Force: false }, function (d) {
if (container.message) { if (container.message) {
$('#loadingViewSpinner').hide();
Notifications.error('Error', d, 'Unable to disconnect container from network'); Notifications.error('Error', d, 'Unable to disconnect container from network');
} else { } else {
$('#loadingViewSpinner').hide();
Notifications.success('Container left network', $transition$.params().id); Notifications.success('Container left network', $transition$.params().id);
$state.go('container', {id: $transition$.params().id}, {reload: true}); $state.go('container', {id: $transition$.params().id}, {reload: true});
} }
$scope.state.leaveNetworkInProgress = false;
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to disconnect container from network'); 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) { function recreateContainer(pullImage) {
$('#loadingViewSpinner').show();
var container = $scope.container; var container = $scope.container;
var config = ContainerHelper.configFromContainer(container.Model); var config = ContainerHelper.configFromContainer(container.Model);
ContainerService.remove(container, true) ContainerService.remove(container, true)
@ -254,9 +239,6 @@ function ($q, $scope, $state, $transition$, $filter, Container, ContainerCommit,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to re-create container'); 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) { $scope.containerJoinNetwork = function containerJoinNetwork(container, networkId) {
$('#joinNetworkSpinner').show(); $scope.state.joinNetworkInProgress = true;
Network.connect({id: networkId}, { Container: $transition$.params().id }, function (d) { Network.connect({id: networkId}, { Container: $transition$.params().id }, function (d) {
if (container.message) { if (container.message) {
$('#joinNetworkSpinner').hide();
Notifications.error('Error', d, 'Unable to connect container to network'); Notifications.error('Error', d, 'Unable to connect container to network');
} else { } else {
$('#joinNetworkSpinner').hide();
Notifications.success('Container joined network', $transition$.params().id); Notifications.success('Container joined network', $transition$.params().id);
$state.go('container', {id: $transition$.params().id}, {reload: true}); $state.go('container', {id: $transition$.params().id}, {reload: true});
} }
$scope.state.joinNetworkInProgress = false;
}, function (e) { }, function (e) {
$('#joinNetworkSpinner').hide();
Notifications.error('Failure', e, 'Unable to connect container to network'); Notifications.error('Failure', e, 'Unable to connect container to network');
$scope.state.joinNetworkInProgress = false;
}); });
}; };

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Container console"> <rd-header-title title="Container console"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content ng-if="state.loaded"> <rd-header-content ng-if="state.loaded">
<a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Console <a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Console
</rd-header-content> </rd-header-content>
@ -10,11 +8,7 @@
<div class="row" ng-if="state.loaded"> <div class="row" ng-if="state.loaded">
<div class="col-lg-12 col-md-12 col-xs-12"> <div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget> <rd-widget>
<rd-widget-header icon="fa-terminal" title="Console"> <rd-widget-header icon="fa-terminal" title="Console"></rd-widget-header>
<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-body> <rd-widget-body>
<form class="form-horizontal"> <form class="form-horizontal">
<div ng-if="!state.connected"> <div ng-if="!state.connected">
@ -54,8 +48,11 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-lg-offset-1 col-sm-offset-2 col-lg-11 col-sm-10"> <div class="col-sm-12">
<button type="button" class="btn btn-primary" ng-click="connect()">Connect</button> <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> </div>
</div> </div>

View File

@ -1,9 +1,11 @@
angular.module('containerConsole', []) angular.module('containerConsole', [])
.controller('ContainerConsoleController', ['$scope', '$transition$', 'Container', 'Image', 'EndpointProvider', 'Notifications', 'ContainerHelper', 'ContainerService', 'ExecService', .controller('ContainerConsoleController', ['$scope', '$transition$', 'Container', 'Image', 'EndpointProvider', 'Notifications', 'ContainerHelper', 'ContainerService', 'ExecService',
function ($scope, $transition$, Container, Image, EndpointProvider, Notifications, ContainerHelper, ContainerService, ExecService) { function ($scope, $transition$, Container, Image, EndpointProvider, Notifications, ContainerHelper, ContainerService, ExecService) {
$scope.state = {}; $scope.state = {
$scope.state.loaded = false; loaded: false,
$scope.state.connected = false; connected: false
};
$scope.formValues = {}; $scope.formValues = {};
var socket, term; var socket, term;
@ -19,25 +21,20 @@ function ($scope, $transition$, Container, Image, EndpointProvider, Notification
$scope.container = d; $scope.container = d;
if (d.message) { if (d.message) {
Notifications.error('Error', d, 'Unable to retrieve container details'); Notifications.error('Error', d, 'Unable to retrieve container details');
$('#loadingViewSpinner').hide();
} else { } else {
Image.get({id: d.Image}, function(imgData) { Image.get({id: d.Image}, function(imgData) {
$scope.imageOS = imgData.Os; $scope.imageOS = imgData.Os;
$scope.formValues.command = imgData.Os === 'windows' ? 'powershell' : 'bash'; $scope.formValues.command = imgData.Os === 'windows' ? 'powershell' : 'bash';
$scope.state.loaded = true; $scope.state.loaded = true;
$('#loadingViewSpinner').hide();
}, function (e) { }, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve image details'); Notifications.error('Failure', e, 'Unable to retrieve image details');
$('#loadingViewSpinner').hide();
}); });
} }
}, function (e) { }, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve container details'); Notifications.error('Failure', e, 'Unable to retrieve container details');
$('#loadingViewSpinner').hide();
}); });
$scope.connect = function() { $scope.connect = function() {
$('#loadConsoleSpinner').show();
var termWidth = Math.floor(($('#terminal-container').width() - 20) / 8.39); var termWidth = Math.floor(($('#terminal-container').width() - 20) / 8.39);
var termHeight = 30; var termHeight = 30;
var command = $scope.formValues.isCustomCommand ? var command = $scope.formValues.isCustomCommand ?
@ -67,9 +64,6 @@ function ($scope, $transition$, Container, Image, EndpointProvider, Notification
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to exec into container'); 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; $scope.state.connected = true;
socket.onopen = function(evt) { socket.onopen = function(evt) {
$('#loadConsoleSpinner').hide();
term = new Terminal(); term = new Terminal();
term.on('data', function (data) { term.on('data', function (data) {

View File

@ -2,21 +2,18 @@ angular.module('containerInspect', ['angular-json-tree'])
.controller('ContainerInspectController', ['$scope', '$transition$', 'Notifications', 'ContainerService', .controller('ContainerInspectController', ['$scope', '$transition$', 'Notifications', 'ContainerService',
function ($scope, $transition$, Notifications, ContainerService) { function ($scope, $transition$, Notifications, ContainerService) {
$scope.state = { DisplayTextView: false }; $scope.state = {
DisplayTextView: false
};
$scope.containerInfo = {}; $scope.containerInfo = {};
function initView() { function initView() {
$('#loadingViewSpinner').show();
ContainerService.inspect($transition$.params().id) ContainerService.inspect($transition$.params().id)
.then(function success(d) { .then(function success(d) {
$scope.containerInfo = d; $scope.containerInfo = d;
}) })
.catch(function error(e) { .catch(function error(e) {
Notifications.error('Failure', e, 'Unable to inspect container'); Notifications.error('Failure', e, 'Unable to inspect container');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -8,20 +8,15 @@ function ($scope, $transition$, $anchorScroll, ContainerLogs, Container) {
$scope.stderr = ''; $scope.stderr = '';
$scope.tailLines = 2000; $scope.tailLines = 2000;
$('#loadingViewSpinner').show();
Container.get({id: $transition$.params().id}, function (d) { Container.get({id: $transition$.params().id}, function (d) {
$scope.container = d; $scope.container = d;
$('#loadingViewSpinner').hide();
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to retrieve container info'); Notifications.error('Failure', e, 'Unable to retrieve container info');
}); });
function getLogs() { function getLogs() {
$('#loadingViewSpinner').show();
getLogsStdout(); getLogsStdout();
getLogsStderr(); getLogsStderr();
$('#loadingViewSpinner').hide();
} }
function getLogsStderr() { function getLogsStderr() {

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Container logs"> <rd-header-title title="Container logs"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Logs <a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Logs
</rd-header-content> </rd-header-content>

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Container statistics"> <rd-header-title title="Container statistics"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Stats <a ui-sref="containers">Containers</a> &gt; <a ui-sref="container({id: container.Id})">{{ container.Name|trimcontainername }}</a> &gt; Stats
</rd-header-content> </rd-header-content>

View File

@ -80,7 +80,6 @@ function ($q, $scope, $transition$, $document, $interval, ContainerService, Char
}; };
function startChartUpdate(networkChart, cpuChart, memoryChart) { function startChartUpdate(networkChart, cpuChart, memoryChart) {
$('#loadingViewSpinner').show();
$q.all({ $q.all({
stats: ContainerService.containerStats($transition$.params().id), stats: ContainerService.containerStats($transition$.params().id),
top: ContainerService.containerTop($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) { .catch(function error(err) {
stopRepeater(); stopRepeater();
Notifications.error('Failure', err, 'Unable to retrieve container statistics'); 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() { function initView() {
$('#loadingViewSpinner').show();
ContainerService.container($transition$.params().id) ContainerService.container($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.container = data; $scope.container = data;
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve container information'); Notifications.error('Failure', err, 'Unable to retrieve container information');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
$document.ready(function() { $document.ready(function() {

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="containers" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="containers" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadContainersSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Containers</rd-header-content> <rd-header-content>Containers</rd-header-content>
</rd-header> </rd-header>

View File

@ -1,6 +1,6 @@
angular.module('containers', []) angular.module('containers', [])
.controller('ContainersController', ['$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, $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 = {};
$scope.state.pagination_count = Pagination.getPaginationCount('containers'); $scope.state.pagination_count = Pagination.getPaginationCount('containers');
$scope.state.displayAll = LocalStorage.getFilterContainerShowAll(); $scope.state.displayAll = LocalStorage.getFilterContainerShowAll();
@ -24,7 +24,6 @@ angular.module('containers', [])
$scope.cleanAssociatedVolumes = false; $scope.cleanAssociatedVolumes = false;
var update = function (data) { var update = function (data) {
$('#loadContainersSpinner').show();
$scope.state.selectedItemCount = 0; $scope.state.selectedItemCount = 0;
Container.query(data, function (d) { Container.query(data, function (d) {
var containers = d; var containers = d;
@ -45,21 +44,17 @@ angular.module('containers', [])
return model; return model;
}); });
updateSelectionFlags(); updateSelectionFlags();
$('#loadContainersSpinner').hide();
}, function (e) { }, function (e) {
$('#loadContainersSpinner').hide();
Notifications.error('Failure', e, 'Unable to retrieve containers'); Notifications.error('Failure', e, 'Unable to retrieve containers');
$scope.containers = []; $scope.containers = [];
}); });
}; };
var batch = function (items, action, msg) { var batch = function (items, action, msg) {
$('#loadContainersSpinner').show();
var counter = 0; var counter = 0;
var complete = function () { var complete = function () {
counter = counter - 1; counter = counter - 1;
if (counter === 0) { if (counter === 0) {
$('#loadContainersSpinner').hide();
update({all: $scope.state.displayAll ? 1 : 0}); update({all: $scope.state.displayAll ? 1 : 0});
} }
}; };
@ -78,12 +73,13 @@ angular.module('containers', [])
else if (action === Container.remove) { else if (action === Container.remove) {
ContainerService.remove(c, $scope.cleanAssociatedVolumes) ContainerService.remove(c, $scope.cleanAssociatedVolumes)
.then(function success() { .then(function success() {
var index = items.indexOf(c);
items.splice(index, 1);
Notifications.success('Container successfully removed'); Notifications.success('Container successfully removed');
complete();
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove container'); Notifications.error('Failure', err, 'Unable to remove container');
})
.finally(function final() {
complete(); complete();
}); });
} }
@ -108,13 +104,9 @@ angular.module('containers', [])
Notifications.error('Failure', e, 'An error occured'); Notifications.error('Failure', e, 'An error occured');
complete(); complete();
}); });
} }
} }
}); });
if (counter === 0) {
$('#loadContainersSpinner').hide();
}
}; };
$scope.selectItems = function (allSelected) { $scope.selectItems = function (allSelected) {

View File

@ -58,14 +58,11 @@ function ($scope, $state, $document, Notifications, ConfigService, Authenticatio
} }
$scope.create = function () { $scope.create = function () {
$('#createResourceSpinner').show();
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createResourceSpinner').hide();
return; return;
} }
@ -83,9 +80,6 @@ function ($scope, $state, $document, Notifications, ConfigService, Authenticatio
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to create config'); Notifications.error('Failure', err, 'Unable to create config');
})
.finally(function final() {
$('#createResourceSpinner').hide();
}); });
}; };

View File

@ -62,8 +62,6 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Name" ng-click="create()">Create config</button> <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>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -20,7 +20,8 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
}; };
$scope.state = { $scope.state = {
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.refreshSlider = function () { $scope.refreshSlider = function () {
@ -570,16 +571,16 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
if (!confirm) { if (!confirm) {
return false; return false;
} }
$('#createContainerSpinner').show();
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createContainerSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
var config = prepareConfiguration(); var config = prepareConfiguration();
createContainer(config, accessControlData); createContainer(config, accessControlData);
}) })
@ -605,7 +606,7 @@ function ($q, $scope, $state, $timeout, $transition$, $filter, Container, Contai
Notifications.error('Failure', err, 'Unable to create container'); Notifications.error('Failure', err, 'Unable to create container');
}) })
.finally(function final() { .finally(function final() {
$('#createContainerSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}); });
} }

View File

@ -112,9 +112,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !config.Image || (!formValues.Registry && fromContainer)" ng-click="create()" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="containers">Cancel</a> <span ng-hide="state.deploymentInProgress">Deploy the container</span>
<i id="createContainerSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-show="state.deploymentInProgress">Deployment in progress...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
<span ng-if="fromContainerMultipleNetworks" style="margin-left: 10px"> <span ng-if="fromContainerMultipleNetworks" style="margin-left: 10px">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>

View File

@ -11,7 +11,8 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
}; };
$scope.state = { $scope.state = {
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.availableNetworkDrivers = []; $scope.availableNetworkDrivers = [];
@ -89,18 +90,16 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
} }
$scope.create = function () { $scope.create = function () {
$('#createResourceSpinner').show();
var networkConfiguration = prepareConfiguration(); var networkConfiguration = prepareConfiguration();
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createResourceSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
NetworkService.create(networkConfiguration) NetworkService.create(networkConfiguration)
.then(function success(data) { .then(function success(data) {
var networkIdentifier = data.Id; 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'); Notifications.error('Failure', err, 'An error occured during network creation');
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
var apiVersion = $scope.applicationState.endpoint.apiVersion; var apiVersion = $scope.applicationState.endpoint.apiVersion;
if(endpointProvider !== 'DOCKER_SWARM') { if(endpointProvider !== 'DOCKER_SWARM') {
@ -130,9 +128,6 @@ function ($q, $scope, $state, PluginService, Notifications, NetworkService, Labe
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve network drivers'); Notifications.error('Failure', err, 'Unable to retrieve network drivers');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Create network"> <rd-header-title title="Create network"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="networks">Networks</a> &gt; Add network <a ui-sref="networks">Networks</a> &gt; Add network
</rd-header-content> </rd-header-content>
@ -130,8 +128,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Name" ng-click="create()">Create network</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !config.Name" ng-click="create()" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="networks">Cancel</a> <span ng-hide="state.deploymentInProgress">Create the network</span>
<span ng-show="state.deploymentInProgress">Creating network...</span>
</button>
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <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> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>

View File

@ -3,7 +3,8 @@ angular.module('createRegistry', [])
function ($scope, $state, RegistryService, Notifications) { function ($scope, $state, RegistryService, Notifications) {
$scope.state = { $scope.state = {
RegistryType: 'quay' RegistryType: 'quay',
deploymentInProgress: false
}; };
$scope.formValues = { $scope.formValues = {
@ -27,13 +28,13 @@ function ($scope, $state, RegistryService, Notifications) {
}; };
$scope.addRegistry = function() { $scope.addRegistry = function() {
$('#createRegistrySpinner').show();
var registryName = $scope.formValues.Name; var registryName = $scope.formValues.Name;
var registryURL = $scope.formValues.URL.replace(/^https?\:\/\//i, ''); var registryURL = $scope.formValues.URL.replace(/^https?\:\/\//i, '');
var authentication = $scope.formValues.Authentication; var authentication = $scope.formValues.Authentication;
var username = $scope.formValues.Username; var username = $scope.formValues.Username;
var password = $scope.formValues.Password; var password = $scope.formValues.Password;
$scope.state.deploymentInProgress = true;
RegistryService.createRegistry(registryName, registryURL, authentication, username, password) RegistryService.createRegistry(registryName, registryURL, authentication, username, password)
.then(function success(data) { .then(function success(data) {
Notifications.success('Registry successfully created'); Notifications.success('Registry successfully created');
@ -43,7 +44,7 @@ function ($scope, $state, RegistryService, Notifications) {
Notifications.error('Failure', err, 'Unable to create registry'); Notifications.error('Failure', err, 'Unable to create registry');
}) })
.finally(function final() { .finally(function final() {
$('#createRegistrySpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
}]); }]);

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Create registry"> <rd-header-title title="Create registry"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="display:none"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="registries">Registries</a> &gt; Add registry <a ui-sref="registries">Registries</a> &gt; Add registry
</rd-header-content> </rd-header-content>
@ -104,10 +102,15 @@
<!-- !credentials-password --> <!-- !credentials-password -->
</div> </div>
<!-- !authentication-credentials --> <!-- !authentication-credentials -->
<div class="col-sm-12 form-section-title">
Actions
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Name || !formValues.URL || (formValues.Authentication && (!formValues.Username || !formValues.Password))" ng-click="addRegistry()" button-spinner="state.deploymentInProgress">
<i id="createRegistrySpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Add registry</span>
<span ng-show="state.deploymentInProgress">Adding registry...</span>
</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -11,7 +11,8 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
}; };
$scope.state = { $scope.state = {
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.addLabel = function() { $scope.addLabel = function() {
@ -55,17 +56,16 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
} }
$scope.create = function () { $scope.create = function () {
$('#createResourceSpinner').show();
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createResourceSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
var secretConfiguration = prepareConfiguration(); var secretConfiguration = prepareConfiguration();
SecretService.create(secretConfiguration) SecretService.create(secretConfiguration)
.then(function success(data) { .then(function success(data) {
@ -81,7 +81,7 @@ function ($scope, $state, Notifications, SecretService, LabelHelper, Authenticat
Notifications.error('Failure', err, 'Unable to create secret'); Notifications.error('Failure', err, 'Unable to create secret');
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
}]); }]);

View File

@ -75,9 +75,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Name || !formValues.Data" ng-click="create()" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="secrets">Cancel</a> <span ng-hide="state.deploymentInProgress">Create the secret</span>
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-show="state.deploymentInProgress">Creating secret...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>
</div> </div>

View File

@ -39,7 +39,8 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
}; };
$scope.state = { $scope.state = {
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.refreshSlider = function () { $scope.refreshSlider = function () {
@ -366,7 +367,7 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
Notifications.error('Failure', err, 'Unable to create service'); Notifications.error('Failure', err, 'Unable to create service');
}) })
.finally(function final() { .finally(function final() {
$('#createServiceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
} }
@ -383,17 +384,16 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
} }
$scope.create = function createService() { $scope.create = function createService() {
$('#createServiceSpinner').show();
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createServiceSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
var config = prepareConfiguration(); var config = prepareConfiguration();
createNewService(config, accessControlData); createNewService(config, accessControlData);
}; };
@ -422,7 +422,6 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
var apiVersion = $scope.applicationState.endpoint.apiVersion; var apiVersion = $scope.applicationState.endpoint.apiVersion;
var provider = $scope.applicationState.endpoint.mode.provider; var provider = $scope.applicationState.endpoint.mode.provider;
@ -448,9 +447,6 @@ function ($q, $scope, $state, $timeout, Service, ServiceHelper, ConfigService, C
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to initialize view'); Notifications.error('Failure', err, 'Unable to initialize view');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Create service"> <rd-header-title title="Create service"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="services">Services</a> &gt; Add service <a ui-sref="services">Services</a> &gt; Add service
</rd-header-content> </rd-header-content>
@ -109,9 +107,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="create()">Create service</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Image" ng-click="create()" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="services">Cancel</a> <span ng-hide="state.deploymentInProgress">Create the service</span>
<i id="createServiceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-show="state.deploymentInProgress">Creating service...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>
</div> </div>

View File

@ -18,7 +18,8 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
$scope.state = { $scope.state = {
Method: 'editor', Method: 'editor',
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.addEnvironmentVariable = function() { $scope.addEnvironmentVariable = function() {
@ -62,8 +63,6 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
} }
$scope.deployStack = function () { $scope.deployStack = function () {
$('#createResourceSpinner').show();
var name = $scope.formValues.Name; var name = $scope.formValues.Name;
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
@ -72,10 +71,10 @@ function ($scope, $state, $document, StackService, CodeMirrorService, Authentica
var userId = userDetails.ID; var userId = userDetails.ID;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createResourceSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
createStack(name) createStack(name)
.then(function success(data) { .then(function success(data) {
Notifications.success('Stack successfully deployed'); 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'); Notifications.error('Failure', err, 'Unable to apply resource control on the stack');
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Create stack"> <rd-header-title title="Create stack"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="display: none;"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="stacks">Stacks</a> > Add stack <a ui-sref="stacks">Stacks</a> > Add stack
</rd-header-content> </rd-header-content>
@ -169,12 +167,13 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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.deploymentInProgress || (state.Method === 'editor' && !formValues.StackFileContent)
|| (state.Method === 'upload' && !formValues.StackFile) || (state.Method === 'upload' && !formValues.StackFile)
|| (state.Method === 'repository' && (!formValues.RepositoryURL || !formValues.RepositoryPath)) || (state.Method === 'repository' && (!formValues.RepositoryURL || !formValues.RepositoryPath))
|| !formValues.Name" ng-click="deployStack()">Deploy the stack</button> || !formValues.Name" ng-click="deployStack()" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="stacks">Cancel</a> <span ng-hide="state.deploymentInProgress">Deploy the stack</span>
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-show="state.deploymentInProgress">Deployment in progress...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>
</div> </div>

View File

@ -9,7 +9,8 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
}; };
$scope.state = { $scope.state = {
formValidationError: '' formValidationError: '',
deploymentInProgress: false
}; };
$scope.availableVolumeDrivers = []; $scope.availableVolumeDrivers = [];
@ -35,7 +36,6 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
} }
$scope.create = function () { $scope.create = function () {
$('#createVolumeSpinner').show();
var name = $scope.formValues.Name; var name = $scope.formValues.Name;
var driver = $scope.formValues.Driver; var driver = $scope.formValues.Driver;
@ -46,10 +46,10 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createVolumeSpinner').hide();
return; return;
} }
$scope.state.deploymentInProgress = true;
VolumeService.createVolume(volumeConfiguration) VolumeService.createVolume(volumeConfiguration)
.then(function success(data) { .then(function success(data) {
var volumeIdentifier = data.Id; 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'); Notifications.error('Failure', err, 'An error occured during volume creation');
}) })
.finally(function final() { .finally(function final() {
$('#createVolumeSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
var apiVersion = $scope.applicationState.endpoint.apiVersion; var apiVersion = $scope.applicationState.endpoint.apiVersion;
if (endpointProvider !== 'DOCKER_SWARM') { if (endpointProvider !== 'DOCKER_SWARM') {
@ -79,9 +78,6 @@ function ($q, $scope, $state, VolumeService, PluginService, ResourceControlServi
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve volume drivers'); Notifications.error('Failure', err, 'Unable to retrieve volume drivers');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Create volume"> <rd-header-title title="Create volume"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="volumes">Volumes</a> &gt; Add volume <a ui-sref="volumes">Volumes</a> &gt; Add volume
</rd-header-content> </rd-header-content>
@ -73,9 +71,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-click="create()">Create volume</button> <button type="button" class="btn btn-primary btn-sm" ng-click="create()" ng-disabled="state.deploymentInProgress" button-spinner="state.deploymentInProgress">
<a type="button" class="btn btn-default btn-sm" ui-sref="volumes">Cancel</a> <span ng-hide="state.deploymentInProgress">Create the volume</span>
<i id="createVolumeSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-show="state.deploymentInProgress">Creating volume...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>
</div> </div>

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Home"> <rd-header-title title="Home"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content>Dashboard</rd-header-content> <rd-header-content>Dashboard</rd-header-content>
</rd-header> </rd-header>
@ -171,6 +169,3 @@
</a> </a>
</div> </div>
</div> </div>
<div class="row">
</div>

View File

@ -65,8 +65,6 @@ function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, System
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
var endpointRole = $scope.applicationState.endpoint.mode.role; var endpointRole = $scope.applicationState.endpoint.mode.role;
@ -86,9 +84,7 @@ function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, System
prepareInfoData(d[4]); prepareInfoData(d[4]);
$scope.serviceCount = d[5].length; $scope.serviceCount = d[5].length;
$scope.stackCount = d[6].length; $scope.stackCount = d[6].length;
$('#loadingViewSpinner').hide();
}, function(e) { }, function(e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to load dashboard data'); Notifications.error('Failure', e, 'Unable to load dashboard data');
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Endpoint details"> <rd-header-title title="Endpoint details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="endpoints">Endpoints</a> &gt; <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a> <a ui-sref="endpoints">Endpoints</a> &gt; <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a>
</rd-header-content> </rd-header-content>
@ -55,9 +53,11 @@
<!-- !endpoint-security --> <!-- !endpoint-security -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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.deploymentInProgress || !endpoint.Name || !endpoint.URL || (endpoint.TLS && ((endpoint.TLSVerify && !formValues.TLSCACert) || (endpoint.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="updateEndpoint()" button-spinner="state.deploymentInProgress">
<span ng-hide="state.deploymentInProgress">Update endpoint</span>
<span ng-show="state.deploymentInProgress">Updating endpoint...</span>
</button>
<a type="button" class="btn btn-default btn-sm" ui-sref="endpoints">Cancel</a> <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>
</div> </div>
</form> </form>

View File

@ -7,7 +7,8 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
} }
$scope.state = { $scope.state = {
uploadInProgress: false uploadInProgress: false,
deploymentInProgress: false
}; };
$scope.formValues = { $scope.formValues = {
@ -35,13 +36,14 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
type: $scope.endpointType type: $scope.endpointType
}; };
$('updateResourceSpinner').show(); $scope.state.deploymentInProgress = true;
EndpointService.updateEndpoint(endpoint.Id, endpointParams) EndpointService.updateEndpoint(endpoint.Id, endpointParams)
.then(function success(data) { .then(function success(data) {
Notifications.success('Endpoint updated', $scope.endpoint.Name); Notifications.success('Endpoint updated', $scope.endpoint.Name);
$state.go('endpoints'); $state.go('endpoints');
}, function error(err) { }, function error(err) {
Notifications.error('Failure', err, 'Unable to update endpoint'); Notifications.error('Failure', err, 'Unable to update endpoint');
$scope.state.deploymentInProgress = false;
}, function update(evt) { }, function update(evt) {
if (evt.upload) { if (evt.upload) {
$scope.state.uploadInProgress = evt.upload; $scope.state.uploadInProgress = evt.upload;
@ -50,7 +52,6 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
EndpointService.endpoint($transition$.params().id) EndpointService.endpoint($transition$.params().id)
.then(function success(data) { .then(function success(data) {
var endpoint = data; var endpoint = data;
@ -64,9 +65,6 @@ function ($scope, $state, $transition$, $filter, EndpointService, Notifications)
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint details'); Notifications.error('Failure', err, 'Unable to retrieve endpoint details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Endpoint access"> <rd-header-title title="Endpoint access"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="endpoints">Endpoints</a> &gt; <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a> &gt; Access management <a ui-sref="endpoints">Endpoints</a> &gt; <a ui-sref="endpoint({id: endpoint.Id})">{{ endpoint.Name }}</a> &gt; Access management
</rd-header-content> </rd-header-content>

View File

@ -7,16 +7,12 @@ function ($scope, $transition$, EndpointService, Notifications) {
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
EndpointService.endpoint($transition$.params().id) EndpointService.endpoint($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.endpoint = data; $scope.endpoint = data;
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint details'); Notifications.error('Failure', err, 'Unable to retrieve endpoint details');
})
.finally(function final(){
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="endpoints" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="endpoints" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadEndpointsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Endpoint management</rd-header-content> <rd-header-content>Endpoint management</rd-header-content>
</rd-header> </rd-header>
@ -66,8 +65,11 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (formValues.TLSClientCert && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="addEndpoint()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
<span ng-show="state.deploymentInProgress">Creating endpoint...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -4,7 +4,8 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
$scope.state = { $scope.state = {
uploadInProgress: false, uploadInProgress: false,
selectedItemCount: 0, selectedItemCount: 0,
pagination_count: Pagination.getPaginationCount('endpoints') pagination_count: Pagination.getPaginationCount('endpoints'),
deploymentInProgress: false
}; };
$scope.sortType = 'Name'; $scope.sortType = 'Name';
$scope.sortReverse = true; $scope.sortReverse = true;
@ -59,11 +60,13 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
var TLSCertFile = TLSSkipClientVerify ? null : securityData.TLSCert; var TLSCertFile = TLSSkipClientVerify ? null : securityData.TLSCert;
var TLSKeyFile = TLSSkipClientVerify ? null : securityData.TLSKey; var TLSKeyFile = TLSSkipClientVerify ? null : securityData.TLSKey;
$scope.state.deploymentInProgress = true;
EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) { EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile).then(function success(data) {
Notifications.success('Endpoint created', name); Notifications.success('Endpoint created', name);
$state.reload(); $state.reload();
}, function error(err) { }, function error(err) {
$scope.state.uploadInProgress = false; $scope.state.uploadInProgress = false;
$scope.state.deploymentInProgress = false;
Notifications.error('Failure', err, 'Unable to create endpoint'); Notifications.error('Failure', err, 'Unable to create endpoint');
}, function update(evt) { }, function update(evt) {
if (evt.upload) { if (evt.upload) {
@ -73,32 +76,20 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
}; };
$scope.removeAction = function () { $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) { angular.forEach($scope.endpoints, function (endpoint) {
if (endpoint.Checked) { if (endpoint.Checked) {
counter = counter + 1;
EndpointService.deleteEndpoint(endpoint.Id).then(function success(data) { EndpointService.deleteEndpoint(endpoint.Id).then(function success(data) {
Notifications.success('Endpoint deleted', endpoint.Name); Notifications.success('Endpoint deleted', endpoint.Name);
var index = $scope.endpoints.indexOf(endpoint); var index = $scope.endpoints.indexOf(endpoint);
$scope.endpoints.splice(index, 1); $scope.endpoints.splice(index, 1);
complete();
}, function error(err) { }, function error(err) {
Notifications.error('Failure', err, 'Unable to remove endpoint'); Notifications.error('Failure', err, 'Unable to remove endpoint');
complete();
}); });
} }
}); });
}; };
function fetchEndpoints() { function fetchEndpoints() {
$('#loadEndpointsSpinner').show();
EndpointService.endpoints() EndpointService.endpoints()
.then(function success(data) { .then(function success(data) {
$scope.endpoints = data; $scope.endpoints = data;
@ -106,9 +97,6 @@ function ($scope, $state, $filter, EndpointService, EndpointProvider, Notificati
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoints'); Notifications.error('Failure', err, 'Unable to retrieve endpoints');
$scope.endpoints = []; $scope.endpoints = [];
})
.finally(function final() {
$('#loadEndpointsSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="engine" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="engine" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Docker</rd-header-content> <rd-header-content>Docker</rd-header-content>
</rd-header> </rd-header>

View File

@ -3,7 +3,6 @@ angular.module('engine', [])
function ($q, $scope, SystemService, Notifications) { function ($q, $scope, SystemService, Notifications) {
function initView() { function initView() {
$('#loadingViewSpinner').show();
$q.all({ $q.all({
version: SystemService.version(), version: SystemService.version(),
info: SystemService.info() info: SystemService.info()
@ -16,9 +15,6 @@ function ($q, $scope, SystemService, Notifications) {
$scope.info = {}; $scope.info = {};
$scope.version = {}; $scope.version = {};
Notifications.error('Failure', err, 'Unable to retrieve engine details'); Notifications.error('Failure', err, 'Unable to retrieve engine details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="events" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="events" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadEventsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Events</rd-header-content> <rd-header-content>Events</rd-header-content>
</rd-header> </rd-header>

View File

@ -19,16 +19,12 @@ function ($scope, Notifications, SystemService, Pagination) {
var from = moment().subtract(24, 'hour').unix(); var from = moment().subtract(24, 'hour').unix();
var to = moment().unix(); var to = moment().unix();
$('#loadEventsSpinner').show();
SystemService.events(from, to) SystemService.events(from, to)
.then(function success(data) { .then(function success(data) {
$scope.events = data; $scope.events = data;
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to load events'); Notifications.error('Failure', err, 'Unable to load events');
})
.finally(function final() {
$('#loadEventsSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Image details"> <rd-header-title title="Image details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="images">Images</a> &gt; <a ui-sref="image({id: image.Id})">{{ image.Id }}</a> <a ui-sref="images">Images</a> &gt; <a ui-sref="image({id: image.Id})">{{ image.Id }}</a>
</rd-header-content> </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. or on the trash icon <span class="fa fa-trash-o" aria-hidden="true"></span> to delete a tag.
</span> </span>
</div> </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> </div>
</form> </form>
</rd-widget-body> </rd-widget-body>
@ -69,7 +77,6 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="tagImage()">Tag</button> <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>
</div> </div>
</form> </form>

View File

@ -21,7 +21,6 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
}; };
$scope.tagImage = function() { $scope.tagImage = function() {
$('#loadingViewSpinner').show();
var image = $scope.formValues.Image; var image = $scope.formValues.Image;
var registry = $scope.formValues.Registry; var registry = $scope.formValues.Registry;
@ -32,14 +31,11 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to tag image'); Notifications.error('Failure', err, 'Unable to tag image');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.pushTag = function(repository) { $scope.pushTag = function(repository) {
$('#loadingViewSpinner').show(); $('#uploadResourceHint').show();
RegistryService.retrieveRegistryFromRepository(repository) RegistryService.retrieveRegistryFromRepository(repository)
.then(function success(data) { .then(function success(data) {
var registry = 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'); Notifications.error('Failure', err, 'Unable to push image to repository');
}) })
.finally(function final() { .finally(function final() {
$('#loadingViewSpinner').hide(); $('#uploadResourceHint').hide();
}); });
}; };
$scope.pullTag = function(repository) { $scope.pullTag = function(repository) {
$('#loadingViewSpinner').show(); $('#downloadResourceHint').show();
RegistryService.retrieveRegistryFromRepository(repository) RegistryService.retrieveRegistryFromRepository(repository)
.then(function success(data) { .then(function success(data) {
var registry = data; var registry = data;
@ -70,12 +66,11 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
Notifications.error('Failure', err, 'Unable to pull image'); Notifications.error('Failure', err, 'Unable to pull image');
}) })
.finally(function final() { .finally(function final() {
$('#loadingViewSpinner').hide(); $('#downloadResourceHint').hide();
}); });
}; };
$scope.removeTag = function(repository) { $scope.removeTag = function(repository) {
$('#loadingViewSpinner').show();
ImageService.deleteImage(repository, false) ImageService.deleteImage(repository, false)
.then(function success() { .then(function success() {
if ($scope.image.RepoTags.length === 1) { if ($scope.image.RepoTags.length === 1) {
@ -88,14 +83,10 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove image'); Notifications.error('Failure', err, 'Unable to remove image');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.removeImage = function (id) { $scope.removeImage = function (id) {
$('#loadingViewSpinner').show();
ImageService.deleteImage(id, false) ImageService.deleteImage(id, false)
.then(function success() { .then(function success() {
Notifications.success('Image successfully deleted', id); Notifications.success('Image successfully deleted', id);
@ -103,14 +94,10 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove image'); Notifications.error('Failure', err, 'Unable to remove image');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
$q.all({ $q.all({
image: ImageService.image($transition$.params().id), image: ImageService.image($transition$.params().id),
@ -123,9 +110,6 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve image details'); Notifications.error('Failure', err, 'Unable to retrieve image details');
$state.go('images'); $state.go('images');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="images" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="images" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadImagesSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Images</rd-header-content> <rd-header-content>Images</rd-header-content>
</rd-header> </rd-header>
@ -29,8 +28,10 @@
<!-- !tag-note --> <!-- !tag-note -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.Image" ng-click="pullImage()">Pull</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Image" ng-click="pullImage()" button-spinner="state.deploymentInProgress">
<i id="pullImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Pull the image</span>
<span ng-show="state.deploymentInProgress">Download in progress...</span>
</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -1,11 +1,14 @@
angular.module('images', []) angular.module('images', [])
.controller('ImagesController', ['$scope', '$state', 'ImageService', 'Notifications', 'Pagination', 'ModalService', .controller('ImagesController', ['$scope', '$state', 'ImageService', 'Notifications', 'Pagination', 'ModalService',
function ($scope, $state, ImageService, Notifications, Pagination, ModalService) { function ($scope, $state, ImageService, Notifications, Pagination, ModalService) {
$scope.state = {}; $scope.state = {
$scope.state.pagination_count = Pagination.getPaginationCount('images'); pagination_count: Pagination.getPaginationCount('images'),
deploymentInProgress: false,
selectedItemCount: 0
};
$scope.sortType = 'RepoTags'; $scope.sortType = 'RepoTags';
$scope.sortReverse = true; $scope.sortReverse = true;
$scope.state.selectedItemCount = 0;
$scope.formValues = { $scope.formValues = {
Image: '', Image: '',
@ -39,9 +42,10 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
}; };
$scope.pullImage = function() { $scope.pullImage = function() {
$('#pullImageSpinner').show();
var image = $scope.formValues.Image; var image = $scope.formValues.Image;
var registry = $scope.formValues.Registry; var registry = $scope.formValues.Registry;
$scope.state.deploymentInProgress = true;
ImageService.pullImage(image, registry, false) ImageService.pullImage(image, registry, false)
.then(function success(data) { .then(function success(data) {
Notifications.success('Image successfully pulled', image); 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'); Notifications.error('Failure', err, 'Unable to pull image');
}) })
.finally(function final() { .finally(function final() {
$('#pullImageSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
@ -64,17 +68,8 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
$scope.removeAction = function (force) { $scope.removeAction = function (force) {
force = !!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) { angular.forEach($scope.images, function (i) {
if (i.Checked) { if (i.Checked) {
counter = counter + 1;
ImageService.deleteImage(i.Id, force) ImageService.deleteImage(i.Id, force)
.then(function success(data) { .then(function success(data) {
Notifications.success('Image deleted', i.Id); Notifications.success('Image deleted', i.Id);
@ -83,16 +78,12 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove image'); Notifications.error('Failure', err, 'Unable to remove image');
})
.finally(function final() {
complete();
}); });
} }
}); });
}; };
function fetchImages() { function fetchImages() {
$('#loadImagesSpinner').show();
var endpointProvider = $scope.applicationState.endpoint.mode.provider; var endpointProvider = $scope.applicationState.endpoint.mode.provider;
var apiVersion = $scope.applicationState.endpoint.apiVersion; var apiVersion = $scope.applicationState.endpoint.apiVersion;
ImageService.images(true) ImageService.images(true)
@ -102,9 +93,6 @@ function ($scope, $state, ImageService, Notifications, Pagination, ModalService)
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve images'); Notifications.error('Failure', err, 'Unable to retrieve images');
$scope.images = []; $scope.images = [];
})
.finally(function final() {
$('#loadImagesSpinner').hide();
}); });
} }

View File

@ -64,8 +64,10 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || formValues.Password.length < 8 || formValues.Password !== formValues.ConfirmPassword" ng-click="createAdminUser()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-user-plus" aria-hidden="true"></i> Create user</span>
<span ng-show="state.deploymentInProgress">Creating user...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -10,11 +10,15 @@ function ($scope, $state, $sanitize, Notifications, Authentication, StateManager
ConfirmPassword: '' ConfirmPassword: ''
}; };
$scope.state = {
deploymentInProgress: false
};
$scope.createAdminUser = function() { $scope.createAdminUser = function() {
$('#createResourceSpinner').show();
var username = $sanitize($scope.formValues.Username); var username = $sanitize($scope.formValues.Username);
var password = $sanitize($scope.formValues.Password); var password = $sanitize($scope.formValues.Password);
$scope.state.deploymentInProgress = true;
UserService.initAdministrator(username, password) UserService.initAdministrator(username, password)
.then(function success() { .then(function success() {
return Authentication.login(username, password); 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'); Notifications.error('Failure', err, 'Unable to create administrator user');
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };

View File

@ -66,8 +66,10 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress" ng-click="createLocalEndpoint()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-bolt" aria-hidden="true"></i> Connect</span>
<span ng-show="state.deploymentInProgress">Connecting...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->
@ -184,8 +186,10 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="submit" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.Name || !formValues.URL || (formValues.TLS && ((formValues.TLSVerify && !formValues.TLSCACert) || (!formValues.TLSSKipClientVerify && (!formValues.TLSCert || !formValues.TLSKey))))" ng-click="createRemoteEndpoint()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-bolt" aria-hidden="true"></i> Connect</span>
<span ng-show="state.deploymentInProgress">Connecting...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -9,7 +9,8 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
$scope.logo = StateManager.getState().application.logo; $scope.logo = StateManager.getState().application.logo;
$scope.state = { $scope.state = {
uploadInProgress: false uploadInProgress: false,
deploymentInProgress: false
}; };
$scope.formValues = { $scope.formValues = {
@ -25,11 +26,11 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
}; };
$scope.createLocalEndpoint = function() { $scope.createLocalEndpoint = function() {
$('#createResourceSpinner').show();
var name = 'local'; var name = 'local';
var URL = 'unix:///var/run/docker.sock'; var URL = 'unix:///var/run/docker.sock';
var endpointID = 1; var endpointID = 1;
$scope.state.deploymentInProgress = true;
EndpointService.createLocalEndpoint(name, URL, false, true) EndpointService.createLocalEndpoint(name, URL, false, true)
.then(function success(data) { .then(function success(data) {
endpointID = data.Id; endpointID = data.Id;
@ -44,12 +45,11 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
EndpointService.deleteEndpoint(endpointID); EndpointService.deleteEndpoint(endpointID);
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
$scope.createRemoteEndpoint = function() { $scope.createRemoteEndpoint = function() {
$('#createResourceSpinner').show();
var name = $scope.formValues.Name; var name = $scope.formValues.Name;
var URL = $scope.formValues.URL; var URL = $scope.formValues.URL;
var PublicURL = URL.split(':')[0]; var PublicURL = URL.split(':')[0];
@ -59,8 +59,9 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
var TLSCAFile = TLSSkipVerify ? null : $scope.formValues.TLSCACert; var TLSCAFile = TLSSkipVerify ? null : $scope.formValues.TLSCACert;
var TLSCertFile = TLSSKipClientVerify ? null : $scope.formValues.TLSCert; var TLSCertFile = TLSSKipClientVerify ? null : $scope.formValues.TLSCert;
var TLSKeyFile = TLSSKipClientVerify ? null : $scope.formValues.TLSKey; var TLSKeyFile = TLSSKipClientVerify ? null : $scope.formValues.TLSKey;
var endpointID = 1; var endpointID = 1;
$scope.state.deploymentInProgress = true;
EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSKipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) EndpointService.createRemoteEndpoint(name, URL, PublicURL, TLS, TLSSkipVerify, TLSSKipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
.then(function success(data) { .then(function success(data) {
endpointID = data.Id; endpointID = data.Id;
@ -75,7 +76,7 @@ function ($scope, $state, EndpointService, StateManager, EndpointProvider, Notif
EndpointService.deleteEndpoint(endpointID); EndpointService.deleteEndpoint(endpointID);
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
}]); }]);

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Network details"> <rd-header-title title="Network details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="networks">Networks</a> &gt; <a ui-sref="network({id: network.Id})">{{ network.Name }}</a> <a ui-sref="networks">Networks</a> &gt; <a ui-sref="network({id: network.Id})">{{ network.Name }}</a>
</rd-header-content> </rd-header-content>

View File

@ -3,35 +3,27 @@ angular.module('network', [])
function ($scope, $state, $transition$, $filter, Network, NetworkService, Container, ContainerHelper, Notifications) { function ($scope, $state, $transition$, $filter, Network, NetworkService, Container, ContainerHelper, Notifications) {
$scope.removeNetwork = function removeNetwork(networkId) { $scope.removeNetwork = function removeNetwork(networkId) {
$('#loadingViewSpinner').show();
Network.remove({id: $transition$.params().id}, function (d) { Network.remove({id: $transition$.params().id}, function (d) {
if (d.message) { if (d.message) {
$('#loadingViewSpinner').hide();
Notifications.error('Error', d, 'Unable to remove network'); Notifications.error('Error', d, 'Unable to remove network');
} else { } else {
$('#loadingViewSpinner').hide();
Notifications.success('Network removed', $transition$.params().id); Notifications.success('Network removed', $transition$.params().id);
$state.go('networks', {}); $state.go('networks', {});
} }
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to remove network'); Notifications.error('Failure', e, 'Unable to remove network');
}); });
}; };
$scope.containerLeaveNetwork = function containerLeaveNetwork(network, containerId) { $scope.containerLeaveNetwork = function containerLeaveNetwork(network, containerId) {
$('#loadingViewSpinner').show();
Network.disconnect({id: $transition$.params().id}, { Container: containerId, Force: false }, function (d) { Network.disconnect({id: $transition$.params().id}, { Container: containerId, Force: false }, function (d) {
if (d.message) { if (d.message) {
$('#loadingViewSpinner').hide();
Notifications.error('Error', d, 'Unable to disconnect container from network'); Notifications.error('Error', d, 'Unable to disconnect container from network');
} else { } else {
$('#loadingViewSpinner').hide();
Notifications.success('Container left network', $transition$.params().id); Notifications.success('Container left network', $transition$.params().id);
$state.go('network', {id: network.Id}, {reload: true}); $state.go('network', {id: network.Id}, {reload: true});
} }
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to disconnect container from network'); 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); filterContainersInNetwork(network, containersInNetwork);
$('#loadingViewSpinner').hide();
}, function error(err) { }, function error(err) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', err, 'Unable to retrieve containers in network'); Notifications.error('Failure', err, 'Unable to retrieve containers in network');
}); });
} else { } else {
@ -73,9 +63,7 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
filters: { network: [$transition$.params().id] } filters: { network: [$transition$.params().id] }
}, function success(data) { }, function success(data) {
filterContainersInNetwork(network, data); filterContainersInNetwork(network, data);
$('#loadingViewSpinner').hide();
}, function error(err) { }, function error(err) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', err, 'Unable to retrieve containers in network'); Notifications.error('Failure', err, 'Unable to retrieve containers in network');
}); });
} }
@ -83,7 +71,6 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
NetworkService.network($transition$.params().id) NetworkService.network($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.network = data; $scope.network = data;
@ -93,11 +80,7 @@ function ($scope, $state, $transition$, $filter, Network, NetworkService, Contai
} }
}) })
.catch(function error(err) { .catch(function error(err) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', err, 'Unable to retrieve network info'); Notifications.error('Failure', err, 'Unable to retrieve network info');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="networks" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="networks" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadNetworksSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Networks</rd-header-content> <rd-header-content>Networks</rd-header-content>
</rd-header> </rd-header>

View File

@ -35,17 +35,8 @@ function ($scope, $state, Network, NetworkService, Notifications, Pagination) {
}; };
$scope.removeAction = function () { $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) { angular.forEach($scope.networks, function (network) {
if (network.Checked) { if (network.Checked) {
counter = counter + 1;
Network.remove({id: network.Id}, function (d) { Network.remove({id: network.Id}, function (d) {
if (d.message) { if (d.message) {
Notifications.error('Error', d, 'Unable to remove network'); 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); var index = $scope.networks.indexOf(network);
$scope.networks.splice(index, 1); $scope.networks.splice(index, 1);
} }
complete();
}, function (e) { }, function (e) {
Notifications.error('Failure', e, 'Unable to remove network'); Notifications.error('Failure', e, 'Unable to remove network');
complete();
}); });
} }
}); });
}; };
function initView() { function initView() {
$('#loadNetworksSpinner').show();
NetworkService.networks(true, true, true, true) NetworkService.networks(true, true, true, true)
.then(function success(data) { .then(function success(data) {
$scope.networks = data; $scope.networks = data;
@ -73,9 +60,6 @@ function ($scope, $state, Network, NetworkService, Notifications, Pagination) {
.catch(function error(err) { .catch(function error(err) {
$scope.networks = []; $scope.networks = [];
Notifications.error('Failure', err, 'Unable to retrieve networks'); Notifications.error('Failure', err, 'Unable to retrieve networks');
})
.finally(function final() {
$('#loadNetworksSpinner').hide();
}); });
} }

View File

@ -68,11 +68,9 @@ function ($scope, $state, $transition$, LabelHelper, Node, NodeHelper, Task, Pag
config.Labels = LabelHelper.fromKeyValueToLabelHash(node.Labels); config.Labels = LabelHelper.fromKeyValueToLabelHash(node.Labels);
Node.update({ id: node.Id, version: node.Version }, config, function (data) { Node.update({ id: node.Id, version: node.Version }, config, function (data) {
$('#loadServicesSpinner').hide();
Notifications.success('Node successfully updated', 'Node updated'); Notifications.success('Node successfully updated', 'Node updated');
$state.go('node', {id: node.Id}, {reload: true}); $state.go('node', {id: node.Id}, {reload: true});
}, function (e) { }, function (e) {
$('#loadServicesSpinner').hide();
Notifications.error('Failure', e, 'Failed to update node'); Notifications.error('Failure', e, 'Failed to update node');
}); });
}; };

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="registries" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="registries" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Registry management</rd-header-content> <rd-header-content>Registry management</rd-header-content>
</rd-header> </rd-header>
@ -57,8 +56,10 @@
<!-- !authentication-credentials --> <!-- !authentication-credentials -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || dockerhub.Authentication && (!dockerhub.Username || !dockerhub.Password)" ng-click="updateDockerHub()" button-spinner="state.deploymentInProgress">
<i id="updateDockerhubSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Update</span>
<span ng-show="state.deploymentInProgress">Updating DockerHub settings...</span>
</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -4,14 +4,15 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
$scope.state = { $scope.state = {
selectedItemCount: 0, selectedItemCount: 0,
pagination_count: Pagination.getPaginationCount('registries') pagination_count: Pagination.getPaginationCount('registries'),
deploymentInProgress: false
}; };
$scope.sortType = 'Name'; $scope.sortType = 'Name';
$scope.sortReverse = true; $scope.sortReverse = true;
$scope.updateDockerHub = function() { $scope.updateDockerHub = function() {
$('#updateDockerhubSpinner').show();
var dockerhub = $scope.dockerhub; var dockerhub = $scope.dockerhub;
$scope.state.deploymentInProgress = true;
DockerHubService.update(dockerhub) DockerHubService.update(dockerhub)
.then(function success(data) { .then(function success(data) {
Notifications.success('DockerHub registry updated'); 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'); Notifications.error('Failure', err, 'Unable to update DockerHub details');
}) })
.finally(function final() { .finally(function final() {
$('#updateDockerhubSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
@ -61,19 +62,9 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
}; };
function removeRegistries() { function removeRegistries() {
$('#loadingViewSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadingViewSpinner').hide();
}
};
var registries = $scope.registries; var registries = $scope.registries;
angular.forEach(registries, function (registry) { angular.forEach(registries, function (registry) {
if (registry.Checked) { if (registry.Checked) {
counter = counter + 1;
RegistryService.deleteRegistry(registry.Id) RegistryService.deleteRegistry(registry.Id)
.then(function success(data) { .then(function success(data) {
var index = registries.indexOf(registry); var index = registries.indexOf(registry);
@ -82,16 +73,12 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove registry'); Notifications.error('Failure', err, 'Unable to remove registry');
})
.finally(function final() {
complete();
}); });
} }
}); });
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
$q.all({ $q.all({
registries: RegistryService.registries(), registries: RegistryService.registries(),
dockerhub: DockerHubService.dockerhub() dockerhub: DockerHubService.dockerhub()
@ -103,9 +90,6 @@ function ($q, $scope, $state, RegistryService, DockerHubService, ModalService, N
.catch(function error(err) { .catch(function error(err) {
$scope.registries = []; $scope.registries = [];
Notifications.error('Failure', err, 'Unable to retrieve registries'); Notifications.error('Failure', err, 'Unable to retrieve registries');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Registry details"> <rd-header-title title="Registry details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="registries">Registries</a> &gt; <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a> <a ui-sref="registries">Registries</a> &gt; <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a>
</rd-header-content> </rd-header-content>
@ -66,9 +64,11 @@
<!-- !authentication-credentials --> <!-- !authentication-credentials -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <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.deploymentInProgress || !registry.Name || !registry.URL || (registry.Authentication && (!registry.Username || !registry.Password))" ng-click="updateRegistry()" button-spinner="state.deploymentInProgress">
<span ng-hide="state.deploymentInProgress">Update registry</span>
<span ng-show="state.deploymentInProgress">Updating registry...</span>
</button>
<a type="button" class="btn btn-default btn-sm" ui-sref="registries">Cancel</a> <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>
</div> </div>
</form> </form>

View File

@ -2,9 +2,13 @@ angular.module('registry', [])
.controller('RegistryController', ['$scope', '$state', '$transition$', '$filter', 'RegistryService', 'Notifications', .controller('RegistryController', ['$scope', '$state', '$transition$', '$filter', 'RegistryService', 'Notifications',
function ($scope, $state, $transition$, $filter, RegistryService, Notifications) { function ($scope, $state, $transition$, $filter, RegistryService, Notifications) {
$scope.state = {
deploymentInProgress: false
};
$scope.updateRegistry = function() { $scope.updateRegistry = function() {
$('#updateRegistrySpinner').show();
var registry = $scope.registry; var registry = $scope.registry;
$scope.state.deploymentInProgress = true;
RegistryService.updateRegistry(registry) RegistryService.updateRegistry(registry)
.then(function success(data) { .then(function success(data) {
Notifications.success('Registry successfully updated'); Notifications.success('Registry successfully updated');
@ -14,12 +18,11 @@ function ($scope, $state, $transition$, $filter, RegistryService, Notifications)
Notifications.error('Failure', err, 'Unable to update registry'); Notifications.error('Failure', err, 'Unable to update registry');
}) })
.finally(function final() { .finally(function final() {
$('#updateRegistrySpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var registryID = $transition$.params().id; var registryID = $transition$.params().id;
RegistryService.registry(registryID) RegistryService.registry(registryID)
.then(function success(data) { .then(function success(data) {
@ -27,9 +30,6 @@ function ($scope, $state, $transition$, $filter, RegistryService, Notifications)
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve registry details'); Notifications.error('Failure', err, 'Unable to retrieve registry details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Registry access"> <rd-header-title title="Registry access"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="registries">Registries</a> &gt; <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a> &gt; Access management <a ui-sref="registries">Registries</a> &gt; <a ui-sref="registry({id: registry.Id})">{{ registry.Name }}</a> &gt; Access management
</rd-header-content> </rd-header-content>

View File

@ -7,16 +7,12 @@ function ($scope, $transition$, RegistryService, Notifications) {
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
RegistryService.registry($transition$.params().id) RegistryService.registry($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.registry = data; $scope.registry = data;
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve registry details'); Notifications.error('Failure', err, 'Unable to retrieve registry details');
})
.finally(function final(){
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="secret({id: secret.Id})" ui-sref-opts="{reload: true}"> <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> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="secrets">Secrets</a> &gt; <a ui-sref="secret({id: secret.Id})">{{ secret.Name }}</a> <a ui-sref="secrets">Secrets</a> &gt; <a ui-sref="secret({id: secret.Id})">{{ secret.Name }}</a>

View File

@ -3,7 +3,6 @@ angular.module('secret', [])
function ($scope, $transition$, $state, SecretService, Notifications) { function ($scope, $transition$, $state, SecretService, Notifications) {
$scope.removeSecret = function removeSecret(secretId) { $scope.removeSecret = function removeSecret(secretId) {
$('#loadingViewSpinner').show();
SecretService.remove(secretId) SecretService.remove(secretId)
.then(function success(data) { .then(function success(data) {
Notifications.success('Secret successfully removed'); Notifications.success('Secret successfully removed');
@ -11,23 +10,16 @@ function ($scope, $transition$, $state, SecretService, Notifications) {
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove secret'); Notifications.error('Failure', err, 'Unable to remove secret');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
SecretService.secret($transition$.params().id) SecretService.secret($transition$.params().id)
.then(function success(data) { .then(function success(data) {
$scope.secret = data; $scope.secret = data;
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve secret details'); Notifications.error('Failure', err, 'Unable to retrieve secret details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="secrets" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="secrets" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Secrets</rd-header-content> <rd-header-content>Secrets</rd-header-content>
</rd-header> </rd-header>

View File

@ -30,17 +30,8 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
}; };
$scope.removeAction = function () { $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) { angular.forEach($scope.secrets, function (secret) {
if (secret.Checked) { if (secret.Checked) {
counter = counter + 1;
SecretService.remove(secret.Id) SecretService.remove(secret.Id)
.then(function success() { .then(function success() {
Notifications.success('Secret deleted', secret.Id); Notifications.success('Secret deleted', secret.Id);
@ -49,16 +40,12 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove secret'); Notifications.error('Failure', err, 'Unable to remove secret');
})
.finally(function final() {
complete();
}); });
} }
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
SecretService.secrets() SecretService.secrets()
.then(function success(data) { .then(function success(data) {
$scope.secrets = data; $scope.secrets = data;
@ -66,9 +53,6 @@ function ($scope, $state, SecretService, Notifications, Pagination) {
.catch(function error(err) { .catch(function error(err) {
$scope.secrets = []; $scope.secrets = [];
Notifications.error('Failure', err, 'Unable to retrieve secrets'); Notifications.error('Failure', err, 'Unable to retrieve secrets');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="service({id: service.Id})" ui-sref-opts="{reload: true}"> <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> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="services">Services</a> &gt; <a ui-sref="service({id: service.Id})">{{ service.Name }}</a> <a ui-sref="services">Services</a> &gt; <a ui-sref="service({id: service.Id})">{{ service.Name }}</a>

View File

@ -200,7 +200,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
}; };
$scope.updateService = function updateService(service) { $scope.updateService = function updateService(service) {
$('#loadingViewSpinner').show();
var config = ServiceHelper.serviceToConfig(service.Model); var config = ServiceHelper.serviceToConfig(service.Model);
config.Name = service.Name; config.Name = service.Name;
config.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceLabels); config.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceLabels);
@ -264,7 +263,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
}; };
Service.update({ id: service.Id, version: service.Version }, config, function (data) { Service.update({ id: service.Id, version: service.Version }, config, function (data) {
$('#loadingViewSpinner').hide();
if (data.message && data.message.match(/^rpc error:/)) { if (data.message && data.message.match(/^rpc error:/)) {
Notifications.error(data.message, 'Error'); Notifications.error(data.message, 'Error');
} else { } else {
@ -273,7 +271,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.cancelChanges({}); $scope.cancelChanges({});
initView(); initView();
}, function (e) { }, function (e) {
$('#loadingViewSpinner').hide();
Notifications.error('Failure', e, 'Unable to update service'); Notifications.error('Failure', e, 'Unable to update service');
}); });
}; };
@ -289,7 +286,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
}; };
function removeService() { function removeService() {
$('#loadingViewSpinner').show();
ServiceService.remove($scope.service) ServiceService.remove($scope.service)
.then(function success(data) { .then(function success(data) {
Notifications.success('Service successfully deleted'); Notifications.success('Service successfully deleted');
@ -297,9 +293,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove service'); Notifications.error('Failure', err, 'Unable to remove service');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }
@ -322,7 +315,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
var apiVersion = $scope.applicationState.endpoint.apiVersion; var apiVersion = $scope.applicationState.endpoint.apiVersion;
ServiceService.service($transition$.params().id) ServiceService.service($transition$.params().id)
.then(function success(data) { .then(function success(data) {
@ -371,9 +363,6 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.secrets = []; $scope.secrets = [];
$scope.configs = []; $scope.configs = [];
Notifications.error('Failure', err, 'Unable to retrieve service details'); Notifications.error('Failure', err, 'Unable to retrieve service details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -9,10 +9,8 @@ function ($scope, $transition$, $anchorScroll, ServiceLogs, Service) {
$scope.tailLines = 2000; $scope.tailLines = 2000;
function getLogs() { function getLogs() {
$('#loadingViewSpinner').show();
getLogsStdout(); getLogsStdout();
getLogsStderr(); getLogsStderr();
$('#loadingViewSpinner').hide();
} }
function getLogsStderr() { function getLogsStderr() {
@ -48,13 +46,10 @@ function ($scope, $transition$, $anchorScroll, ServiceLogs, Service) {
} }
function getService() { function getService() {
$('#loadingViewSpinner').show();
Service.get({id: $transition$.params().id}, function (d) { Service.get({id: $transition$.params().id}, function (d) {
$scope.service = d; $scope.service = d;
$('#loadingViewSpinner').hide();
}, function (e) { }, function (e) {
Notifications.error('Failure', e, 'Unable to retrieve service info'); Notifications.error('Failure', e, 'Unable to retrieve service info');
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Service logs"> <rd-header-title title="Service logs"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="services">Services</a> > <a ui-sref="service({id: service.ID})">{{ service.Spec.Name }}</a> > Logs <a ui-sref="services">Services</a> > <a ui-sref="service({id: service.ID})">{{ service.Spec.Name }}</a> > Logs
</rd-header-content> </rd-header-content>

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="services" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="services" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadServicesSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Services</rd-header-content> <rd-header-content>Services</rd-header-content>
</rd-header> </rd-header>

View File

@ -25,15 +25,12 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
}; };
$scope.scaleService = function scaleService(service) { $scope.scaleService = function scaleService(service) {
$('#loadServicesSpinner').show();
var config = ServiceHelper.serviceToConfig(service.Model); var config = ServiceHelper.serviceToConfig(service.Model);
config.Mode.Replicated.Replicas = service.Replicas; config.Mode.Replicated.Replicas = service.Replicas;
Service.update({ id: service.Id, version: service.Version }, config, function (data) { Service.update({ id: service.Id, version: service.Version }, config, function (data) {
$('#loadServicesSpinner').hide();
Notifications.success('Service successfully scaled', 'New replica count: ' + service.Replicas); Notifications.success('Service successfully scaled', 'New replica count: ' + service.Replicas);
$state.reload(); $state.reload();
}, function (e) { }, function (e) {
$('#loadServicesSpinner').hide();
service.Scale = false; service.Scale = false;
service.Replicas = service.ReplicaCount; service.Replicas = service.ReplicaCount;
Notifications.error('Failure', e, 'Unable to scale service'); Notifications.error('Failure', e, 'Unable to scale service');
@ -51,17 +48,8 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
}; };
function removeServices() { function removeServices() {
$('#loadServicesSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadServicesSpinner').hide();
}
};
angular.forEach($scope.services, function (service) { angular.forEach($scope.services, function (service) {
if (service.Checked) { if (service.Checked) {
counter = counter + 1;
ServiceService.remove(service) ServiceService.remove(service)
.then(function success(data) { .then(function success(data) {
Notifications.success('Service successfully deleted'); Notifications.success('Service successfully deleted');
@ -70,9 +58,6 @@ function ($q, $scope, $transition$, $state, Service, ServiceService, ServiceHelp
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove service'); 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() { function initView() {
$('#loadServicesSpinner').show();
$q.all({ $q.all({
services: Service.query({}).$promise, services: Service.query({}).$promise,
tasks: Task.query({filters: {'desired-state': ['running','accepted']}}).$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) { .catch(function error(err) {
$scope.services = []; $scope.services = [];
Notifications.error('Failure', err, 'Unable to retrieve services'); Notifications.error('Failure', err, 'Unable to retrieve services');
})
.finally(function final() {
$('#loadServicesSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Settings"> <rd-header-title title="Settings"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title>
<rd-header-content>Settings</rd-header-content> <rd-header-content>Settings</rd-header-content>
</rd-header> </rd-header>
@ -112,9 +110,10 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveApplicationSettings()">Save</button> <button type="button" class="btn btn-primary btn-sm" ng-click="saveApplicationSettings()" ng-disabled="state.deploymentInProgress" button-spinner="state.deploymentInProgress">
<i id="updateSettingsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Save settings</span>
<!-- <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> --> <span ng-show="state.deploymentInProgress">Saving...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -2,6 +2,10 @@ angular.module('settings', [])
.controller('SettingsController', ['$scope', '$state', 'Notifications', 'SettingsService', 'StateManager', 'DEFAULT_TEMPLATES_URL', .controller('SettingsController', ['$scope', '$state', 'Notifications', 'SettingsService', 'StateManager', 'DEFAULT_TEMPLATES_URL',
function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_TEMPLATES_URL) { function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_TEMPLATES_URL) {
$scope.state = {
deploymentInProgress: false
};
$scope.formValues = { $scope.formValues = {
customLogo: false, customLogo: false,
customTemplates: false, customTemplates: false,
@ -45,6 +49,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts; settings.AllowBindMountsForRegularUsers = !$scope.formValues.restrictBindMounts;
settings.AllowPrivilegedModeForRegularUsers = !$scope.formValues.restrictPrivilegedMode; settings.AllowPrivilegedModeForRegularUsers = !$scope.formValues.restrictPrivilegedMode;
$scope.state.deploymentInProgress = true;
updateSettings(settings, false); updateSettings(settings, false);
}; };
@ -54,8 +59,6 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
} }
function updateSettings(settings, resetForm) { function updateSettings(settings, resetForm) {
$('#loadingViewSpinner').show();
SettingsService.update(settings) SettingsService.update(settings)
.then(function success(data) { .then(function success(data) {
Notifications.success('Settings updated'); Notifications.success('Settings updated');
@ -69,12 +72,11 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
Notifications.error('Failure', err, 'Unable to update settings'); Notifications.error('Failure', err, 'Unable to update settings');
}) })
.finally(function final() { .finally(function final() {
$('#loadingViewSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
SettingsService.settings() SettingsService.settings()
.then(function success(data) { .then(function success(data) {
var settings = data; var settings = data;
@ -91,9 +93,6 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve application settings'); Notifications.error('Failure', err, 'Unable to retrieve application settings');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Authentication settings"> <rd-header-title title="Authentication settings"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="settings">Settings</a> &gt; Authentication <a ui-sref="settings">Settings</a> &gt; Authentication
</rd-header-content> </rd-header-content>
@ -100,8 +98,10 @@
<i class="fa fa-times red-icon" style="margin-left: 5px;" ng-if="state.failedConnectivityCheck"></i> <i class="fa fa-times red-icon" style="margin-left: 5px;" ng-if="state.failedConnectivityCheck"></i>
</label> </label>
<div class="col-sm-9 col-lg-10"> <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> <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">
<i id="connectivityCheckSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.connectivityCheckInProgress">Test connectivity</span>
<span ng-show="state.connectivityCheckInProgress">Testing connectivity...</span>
</button>
</div> </div>
</div> </div>
@ -240,9 +240,10 @@
<!-- actions --> <!-- actions -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()">Save</button> <button type="button" class="btn btn-primary btn-sm" ng-click="saveSettings()" ng-disabled="state.deploymentInProgress" button-spinner="state.deploymentInProgress">
<i id="updateSettingsSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Save settings</span>
<!-- <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> --> <span ng-show="state.deploymentInProgress">Saving...</span>
</button>
</div> </div>
</div> </div>
<!-- !actions --> <!-- !actions -->

View File

@ -5,7 +5,9 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
$scope.state = { $scope.state = {
successfulConnectivityCheck: false, successfulConnectivityCheck: false,
failedConnectivityCheck: false, failedConnectivityCheck: false,
uploadInProgress: false uploadInProgress: false,
connectivityCheckInProgress: false,
deploymentInProgress: false
}; };
$scope.formValues = { $scope.formValues = {
@ -21,13 +23,13 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
}; };
$scope.LDAPConnectivityCheck = function() { $scope.LDAPConnectivityCheck = function() {
$('#connectivityCheckSpinner').show();
var settings = $scope.settings; var settings = $scope.settings;
var TLSCAFile = $scope.formValues.TLSCACert !== settings.LDAPSettings.TLSConfig.TLSCACert ? $scope.formValues.TLSCACert : null; 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; var uploadRequired = ($scope.LDAPSettings.TLSConfig.TLS || $scope.LDAPSettings.StartTLS) && !$scope.LDAPSettings.TLSConfig.TLSSkipVerify;
$scope.state.uploadInProgress = uploadRequired; $scope.state.uploadInProgress = uploadRequired;
$scope.state.connectivityCheckInProgress = true;
$q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null)) $q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null))
.then(function success(data) { .then(function success(data) {
return SettingsService.checkLDAPConnectivity(settings); return SettingsService.checkLDAPConnectivity(settings);
@ -44,18 +46,18 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
}) })
.finally(function final() { .finally(function final() {
$scope.state.uploadInProgress = false; $scope.state.uploadInProgress = false;
$('#connectivityCheckSpinner').hide(); $scope.state.connectivityCheckInProgress = false;
}); });
}; };
$scope.saveSettings = function() { $scope.saveSettings = function() {
$('#updateSettingsSpinner').show();
var settings = $scope.settings; var settings = $scope.settings;
var TLSCAFile = $scope.formValues.TLSCACert !== settings.LDAPSettings.TLSConfig.TLSCACert ? $scope.formValues.TLSCACert : null; 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; var uploadRequired = ($scope.LDAPSettings.TLSConfig.TLS || $scope.LDAPSettings.StartTLS) && !$scope.LDAPSettings.TLSConfig.TLSSkipVerify;
$scope.state.uploadInProgress = uploadRequired; $scope.state.uploadInProgress = uploadRequired;
$scope.state.deploymentInProgress = true;
$q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null)) $q.when(!uploadRequired || FileUploadService.uploadLDAPTLSFiles(TLSCAFile, null, null))
.then(function success(data) { .then(function success(data) {
return SettingsService.update(settings); return SettingsService.update(settings);
@ -68,12 +70,11 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
}) })
.finally(function final() { .finally(function final() {
$scope.state.uploadInProgress = false; $scope.state.uploadInProgress = false;
$('#updateSettingsSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
SettingsService.settings() SettingsService.settings()
.then(function success(data) { .then(function success(data) {
var settings = data; var settings = data;
@ -83,9 +84,6 @@ function ($q, $scope, Notifications, SettingsService, FileUploadService) {
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve application settings'); Notifications.error('Failure', err, 'Unable to retrieve application settings');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="stack({id: stack.Id})" ui-sref-opts="{reload: true}"> <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> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="stacks">Stacks</a> > <a ui-sref="stack({id: stack.Id})">{{ stack.Name }}</a> <a ui-sref="stacks">Stacks</a> > <a ui-sref="stack({id: stack.Id})">{{ stack.Name }}</a>
@ -73,8 +72,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-sm btn-primary" ng-click="deployStack()">Update stack</button> <button type="button" class="btn btn-sm btn-primary" ng-disabled="state.deploymentInProgress" ng-click="deployStack()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Update the stack</span>
<span ng-show="state.deploymentInProgress">Deployment in progress...</span>
</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -2,14 +2,17 @@ angular.module('stack', [])
.controller('StackController', ['$q', '$scope', '$state', '$stateParams', '$document', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ServiceHelper', 'CodeMirrorService', 'Notifications', 'FormHelper', .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) { function ($q, $scope, $state, $stateParams, $document, StackService, NodeService, ServiceService, TaskService, ServiceHelper, CodeMirrorService, Notifications, FormHelper) {
$scope.deployStack = function () { $scope.state = {
$('#createResourceSpinner').show(); deploymentInProgress: false
};
$scope.deployStack = function () {
// The codemirror editor does not work with ng-model so we need to retrieve // The codemirror editor does not work with ng-model so we need to retrieve
// the value directly from the editor. // the value directly from the editor.
var stackFile = $scope.editor.getValue(); var stackFile = $scope.editor.getValue();
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env); var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
$scope.state.deploymentInProgress = true;
StackService.updateStack($scope.stack.Id, stackFile, env) StackService.updateStack($scope.stack.Id, stackFile, env)
.then(function success(data) { .then(function success(data) {
Notifications.success('Stack successfully deployed'); 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'); Notifications.error('Failure', err, 'Unable to create stack');
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
@ -32,7 +35,6 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var stackId = $stateParams.id; var stackId = $stateParams.id;
StackService.stack(stackId) StackService.stack(stackId)
@ -77,9 +79,6 @@ function ($q, $scope, $state, $stateParams, $document, StackService, NodeService
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve tasks details'); Notifications.error('Failure', err, 'Unable to retrieve tasks details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="stacks" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="stacks" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Stacks</rd-header-content> <rd-header-content>Stacks</rd-header-content>
</rd-header> </rd-header>

View File

@ -46,19 +46,8 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
}; };
function deleteSelectedStacks() { function deleteSelectedStacks() {
$('#loadingViewSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadingViewSpinner').hide();
}
};
angular.forEach($scope.stacks, function (stack) { angular.forEach($scope.stacks, function (stack) {
if (stack.Checked) { if (stack.Checked) {
counter = counter + 1;
StackService.remove(stack) StackService.remove(stack)
.then(function success() { .then(function success() {
Notifications.success('Stack deleted', stack.Name); Notifications.success('Stack deleted', stack.Name);
@ -67,17 +56,12 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove stack ' + stack.Name); Notifications.error('Failure', err, 'Unable to remove stack ' + stack.Name);
})
.finally(function final() {
complete();
}); });
} }
}); });
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
StackService.stacks(true) StackService.stacks(true)
.then(function success(data) { .then(function success(data) {
var stacks = data; var stacks = data;
@ -93,9 +77,6 @@ function ($scope, Notifications, Pagination, StackService, ModalService) {
.catch(function error(err) { .catch(function error(err) {
$scope.stacks = []; $scope.stacks = [];
Notifications.error('Failure', err, 'Unable to retrieve stacks'); Notifications.error('Failure', err, 'Unable to retrieve stacks');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="swarm" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="swarm" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Swarm</rd-header-content> <rd-header-content>Swarm</rd-header-content>
</rd-header> </rd-header>

View File

@ -72,8 +72,6 @@ function ($q, $scope, SystemService, NodeService, Pagination, Notifications, Sta
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
if (StateManager.getState().application.authentication) { if (StateManager.getState().application.authentication) {
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true: false; var isAdmin = userDetails.role === 1 ? true: false;
@ -99,9 +97,6 @@ function ($q, $scope, SystemService, NodeService, Pagination, Notifications, Sta
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve cluster details'); Notifications.error('Failure', err, 'Unable to retrieve cluster details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="swarm.visualizer" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="swarm.visualizer" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="swarm">Swarm</a> &gt; <a ui-sref="swarm.visualizer">Cluster visualizer</a> <a ui-sref="swarm">Swarm</a> &gt; <a ui-sref="swarm.visualizer">Cluster visualizer</a>

View File

@ -47,7 +47,6 @@ function ($q, $scope, $document, NodeService, ServiceService, TaskService, Notif
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
$q.all({ $q.all({
nodes: NodeService.nodes(), nodes: NodeService.nodes(),
services: ServiceService.services(), services: ServiceService.services(),
@ -64,9 +63,6 @@ function ($q, $scope, $document, NodeService, ServiceService, TaskService, Notif
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to initialize cluster visualizer'); Notifications.error('Failure', err, 'Unable to initialize cluster visualizer');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Task details"> <rd-header-title title="Task details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content ng-if="task && service"> <rd-header-content ng-if="task && service">
<a ui-sref="services">Services</a> &gt; <a ui-sref="service({id: service.Id })">{{ service.Name }}</a> &gt; {{ task.Id }} <a ui-sref="services">Services</a> &gt; <a ui-sref="service({id: service.Id })">{{ service.Name }}</a> &gt; {{ task.Id }}
</rd-header-content> </rd-header-content>

View File

@ -3,7 +3,6 @@ angular.module('task', [])
function ($scope, $transition$, TaskService, Service, Notifications) { function ($scope, $transition$, TaskService, Service, Notifications) {
function initView() { function initView() {
$('#loadingViewSpinner').show();
TaskService.task($transition$.params().id) TaskService.task($transition$.params().id)
.then(function success(data) { .then(function success(data) {
var task = data; var task = data;
@ -16,9 +15,6 @@ function ($scope, $transition$, TaskService, Service, Notifications) {
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve task details'); Notifications.error('Failure', err, 'Unable to retrieve task details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="Team details"> <rd-header-title title="Team details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="teams">Teams</a> &gt; <a ui-sref="team({id: team.Id})">{{ team.Name }}</a> <a ui-sref="teams">Teams</a> &gt; <a ui-sref="team({id: team.Id})">{{ team.Name }}</a>
</rd-header-content> </rd-header-content>

View File

@ -44,7 +44,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}; };
$scope.promoteToLeader = function(user) { $scope.promoteToLeader = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 1) TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 1)
.then(function success(data) { .then(function success(data) {
$scope.leaderCount++; $scope.leaderCount++;
@ -53,14 +52,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user role'); Notifications.error('Failure', err, 'Unable to update user role');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.demoteToMember = function(user) { $scope.demoteToMember = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 2) TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 2)
.then(function success(data) { .then(function success(data) {
user.TeamRole = 'Member'; user.TeamRole = 'Member';
@ -69,14 +64,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user role'); Notifications.error('Failure', err, 'Unable to update user role');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.addAllUsers = function() { $scope.addAllUsers = function() {
$('#loadingViewSpinner').show();
var teamMembershipQueries = []; var teamMembershipQueries = [];
angular.forEach($scope.users, function (user) { angular.forEach($scope.users, function (user) {
teamMembershipQueries.push(TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2)); 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) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members'); Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.addUser = function(user) { $scope.addUser = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2) TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2)
.then(function success(data) { .then(function success(data) {
removeUserFromArray(user.Id, $scope.users); removeUserFromArray(user.Id, $scope.users);
@ -113,14 +100,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members'); Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.removeAllUsers = function() { $scope.removeAllUsers = function() {
$('#loadingViewSpinner').show();
var teamMembershipQueries = []; var teamMembershipQueries = [];
angular.forEach($scope.teamMembers, function (user) { angular.forEach($scope.teamMembers, function (user) {
teamMembershipQueries.push(TeamMembershipService.deleteMembership(user.MembershipId)); teamMembershipQueries.push(TeamMembershipService.deleteMembership(user.MembershipId));
@ -133,14 +116,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members'); Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.removeUser = function(user) { $scope.removeUser = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.deleteMembership(user.MembershipId) TeamMembershipService.deleteMembership(user.MembershipId)
.then(function success() { .then(function success() {
removeUserFromArray(user.Id, $scope.teamMembers); removeUserFromArray(user.Id, $scope.teamMembers);
@ -149,14 +128,10 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members'); Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
function deleteTeam() { function deleteTeam() {
$('#loadingViewSpinner').show();
TeamService.deleteTeam($scope.team.Id) TeamService.deleteTeam($scope.team.Id)
.then(function success(data) { .then(function success(data) {
Notifications.success('Team successfully deleted', $scope.team.Name); Notifications.success('Team successfully deleted', $scope.team.Name);
@ -164,9 +139,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove team'); 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() { function initView() {
$('#loadingViewSpinner').show();
$scope.isAdmin = Authentication.getUserDetails().role === 1 ? true: false; $scope.isAdmin = Authentication.getUserDetails().role === 1 ? true: false;
$q.all({ $q.all({
team: TeamService.team($transition$.params().id), team: TeamService.team($transition$.params().id),
@ -219,9 +190,6 @@ function ($q, $scope, $state, $transition$, TeamService, UserService, TeamMember
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve team details'); Notifications.error('Failure', err, 'Unable to retrieve team details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="teams" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="teams" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Teams management</rd-header-content> <rd-header-content>Teams management</rd-header-content>
</rd-header> </rd-header>
@ -50,8 +49,10 @@
<!-- !team-leaders --> <!-- !team-leaders -->
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!state.validName || formValues.Name === ''" ng-click="addTeam()"><i class="fa fa-plus" aria-hidden="true"></i> Add team</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !state.validName || formValues.Name === ''" ng-click="addTeam()" button-spinner="state.deploymentInProgress">
<i id="createTeamSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Create team</span>
<span ng-show="state.deploymentInProgress">Creating team...</span>
</button>
<span class="text-danger" ng-if="state.teamCreationError" style="margin: 5px;"> <span class="text-danger" ng-if="state.teamCreationError" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.teamCreationError }} <i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.teamCreationError }}
</span> </span>

View File

@ -5,7 +5,8 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
userGroupGroupCreationError: '', userGroupGroupCreationError: '',
selectedItemCount: 0, selectedItemCount: 0,
validName: false, validName: false,
pagination_count: Pagination.getPaginationCount('teams') pagination_count: Pagination.getPaginationCount('teams'),
deploymentInProgress: false
}; };
$scope.sortType = 'Name'; $scope.sortType = 'Name';
$scope.sortReverse = false; $scope.sortReverse = false;
@ -54,7 +55,7 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
}; };
$scope.addTeam = function() { $scope.addTeam = function() {
$('#createTeamSpinner').show(); $scope.state.deploymentInProgress = true;
$scope.state.teamCreationError = ''; $scope.state.teamCreationError = '';
var teamName = $scope.formValues.Name; var teamName = $scope.formValues.Name;
var leaderIds = []; var leaderIds = [];
@ -71,22 +72,13 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
Notifications.error('Failure', err, 'Unable to create team'); Notifications.error('Failure', err, 'Unable to create team');
}) })
.finally(function final() { .finally(function final() {
$('#createTeamSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function deleteSelectedTeams() { function deleteSelectedTeams() {
$('#loadingViewSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadingViewSpinner').hide();
}
};
angular.forEach($scope.teams, function (team) { angular.forEach($scope.teams, function (team) {
if (team.Checked) { if (team.Checked) {
counter = counter + 1;
TeamService.deleteTeam(team.Id) TeamService.deleteTeam(team.Id)
.then(function success(data) { .then(function success(data) {
var index = $scope.teams.indexOf(team); var index = $scope.teams.indexOf(team);
@ -95,9 +87,6 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove team'); Notifications.error('Failure', err, 'Unable to remove team');
})
.finally(function final() {
complete();
}); });
} }
}); });
@ -114,7 +103,6 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
}; };
function initView() { function initView() {
$('#loadingViewSpinner').show();
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true: false; var isAdmin = userDetails.role === 1 ? true: false;
$scope.isAdmin = isAdmin; $scope.isAdmin = isAdmin;
@ -130,9 +118,6 @@ function ($q, $scope, $state, TeamService, UserService, TeamMembershipService, M
$scope.teams = []; $scope.teams = [];
$scope.users = []; $scope.users = [];
Notifications.error('Failure', err, 'Unable to retrieve teams'); Notifications.error('Failure', err, 'Unable to retrieve teams');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="templates" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="templates" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>Templates</rd-header-content> <rd-header-content>Templates</rd-header-content>
</rd-header> </rd-header>
@ -60,10 +59,15 @@
<por-access-control-form form-data="formValues.AccessControlData" ng-if="applicationState.application.authentication"></por-access-control-form> <por-access-control-form form-data="formValues.AccessControlData" ng-if="applicationState.application.authentication"></por-access-control-form>
<!-- !access-control --> <!-- !access-control -->
<!-- actions --> <!-- actions -->
<div class="col-sm-12 form-section-title">
Actions
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.name" ng-click="createTemplate()">Create</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.name" ng-click="createTemplate()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Deploy the stack</span>
<span ng-show="state.deploymentInProgress">Deployment in progress...</span>
</button>
<span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span> <span class="text-danger" ng-if="state.formValidationError" style="margin-left: 5px;">{{ state.formValidationError }}</span>
</div> </div>
</div> </div>
@ -287,10 +291,15 @@
</div> </div>
<!-- !advanced-options --> <!-- !advanced-options -->
<!-- actions --> <!-- actions -->
<div class="col-sm-12 form-section-title">
Actions
</div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!formValues.network" ng-click="createTemplate()">Create</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !formValues.network" ng-click="createTemplate()" button-spinner="state.deploymentInProgress">
<i id="createResourceSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress">Deploy the container</span>
<span ng-show="state.deploymentInProgress">Deployment in progress...</span>
</button>
<span class="small text-muted" style="margin-left: 10px" ng-if="globalNetworkCount === 0 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM' && !state.formValidationError"> <span class="small text-muted" style="margin-left: 10px" ng-if="globalNetworkCount === 0 && applicationState.endpoint.mode.provider === 'DOCKER_SWARM' && !state.formValidationError">
When using Swarm, we recommend deploying containers in a shared network. Looks like you don't have any shared network, head over the <a ui-sref="networks">networks view</a> to create one. When using Swarm, we recommend deploying containers in a shared network. Looks like you don't have any shared network, head over the <a ui-sref="networks">networks view</a> to create one.
</span> </span>

View File

@ -7,6 +7,7 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
hideDescriptions: $transition$.params().hide_descriptions, hideDescriptions: $transition$.params().hide_descriptions,
formValidationError: '', formValidationError: '',
showDeploymentSelector: false, showDeploymentSelector: false,
deploymentInProgress: false,
filters: { filters: {
Categories: '!', Categories: '!',
Platform: '!', Platform: '!',
@ -85,7 +86,7 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
Notifications.error('Failure', err, err.msg); Notifications.error('Failure', err, err.msg);
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
} }
@ -113,26 +114,24 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
$state.go('stacks', {}, {reload: true}); $state.go('stacks', {}, {reload: true});
}) })
.finally(function final() { .finally(function final() {
$('#createResourceSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
} }
$scope.createTemplate = function() { $scope.createTemplate = function() {
$('#createResourceSpinner').show();
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var userId = userDetails.ID; var userId = userDetails.ID;
var accessControlData = $scope.formValues.AccessControlData; var accessControlData = $scope.formValues.AccessControlData;
var isAdmin = userDetails.role === 1 ? true : false; var isAdmin = userDetails.role === 1 ? true : false;
if (!validateForm(accessControlData, isAdmin)) { if (!validateForm(accessControlData, isAdmin)) {
$('#createResourceSpinner').hide();
return; return;
} }
var template = $scope.state.selectedTemplate; var template = $scope.state.selectedTemplate;
var templatesKey = $scope.templatesKey; var templatesKey = $scope.templatesKey;
$scope.state.deploymentInProgress = true;
if (template.Type === 'stack') { if (template.Type === 'stack') {
createStackFromTemplate(template, userId, accessControlData); createStackFromTemplate(template, userId, accessControlData);
} else { } else {
@ -234,9 +233,6 @@ function ($scope, $q, $state, $transition$, $anchorScroll, $filter, ContainerSer
.catch(function error(err) { .catch(function error(err) {
$scope.templates = []; $scope.templates = [];
Notifications.error('Failure', err, 'An error occured during apps initialization.'); Notifications.error('Failure', err, 'An error occured during apps initialization.');
})
.finally(function final(){
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="User details"> <rd-header-title title="User details"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content> <rd-header-content>
<a ui-sref="users">Users</a> &gt; <a ui-sref="user({id: user.Id})">{{ user.Username }}</a> <a ui-sref="users">Users</a> &gt; <a ui-sref="user({id: user.Id})">{{ user.Username }}</a>
</rd-header-content> </rd-header-content>

View File

@ -23,7 +23,6 @@ function ($q, $scope, $state, $transition$, UserService, ModalService, Notificat
}; };
$scope.updatePermissions = function() { $scope.updatePermissions = function() {
$('#loadingViewSpinner').show();
var role = $scope.formValues.Administrator ? 1 : 2; var role = $scope.formValues.Administrator ? 1 : 2;
UserService.updateUser($scope.user.Id, undefined, role) UserService.updateUser($scope.user.Id, undefined, role)
.then(function success(data) { .then(function success(data) {
@ -33,14 +32,10 @@ function ($q, $scope, $state, $transition$, UserService, ModalService, Notificat
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user permissions'); Notifications.error('Failure', err, 'Unable to update user permissions');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
$scope.updatePassword = function() { $scope.updatePassword = function() {
$('#loadingViewSpinner').show();
UserService.updateUser($scope.user.Id, $scope.formValues.newPassword, undefined) UserService.updateUser($scope.user.Id, $scope.formValues.newPassword, undefined)
.then(function success(data) { .then(function success(data) {
Notifications.success('Password successfully updated'); Notifications.success('Password successfully updated');
@ -48,14 +43,10 @@ function ($q, $scope, $state, $transition$, UserService, ModalService, Notificat
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user password'); Notifications.error('Failure', err, 'Unable to update user password');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
}; };
function deleteUser() { function deleteUser() {
$('#loadingViewSpinner').show();
UserService.deleteUser($scope.user.Id) UserService.deleteUser($scope.user.Id)
.then(function success(data) { .then(function success(data) {
Notifications.success('User successfully deleted', $scope.user.Username); Notifications.success('User successfully deleted', $scope.user.Username);
@ -63,14 +54,10 @@ function ($q, $scope, $state, $transition$, UserService, ModalService, Notificat
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove user'); Notifications.error('Failure', err, 'Unable to remove user');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }
function initView() { function initView() {
$('#loadingViewSpinner').show();
$q.all({ $q.all({
user: UserService.user($transition$.params().id), user: UserService.user($transition$.params().id),
settings: SettingsService.publicSettings() settings: SettingsService.publicSettings()
@ -83,9 +70,6 @@ function ($q, $scope, $state, $transition$, UserService, ModalService, Notificat
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve user information'); Notifications.error('Failure', err, 'Unable to retrieve user information');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -1,7 +1,5 @@
<rd-header> <rd-header>
<rd-header-title title="User settings"> <rd-header-title title="User settings"></rd-header-title>
<i id="loadingViewSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title>
<rd-header-content>User settings</rd-header-content> <rd-header-content>User settings</rd-header-content>
</rd-header> </rd-header>

View File

@ -34,9 +34,6 @@ function ($scope, $state, $sanitize, Authentication, UserService, Notifications,
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve application settings'); Notifications.error('Failure', err, 'Unable to retrieve application settings');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
}); });
} }

View File

@ -3,7 +3,6 @@
<a data-toggle="tooltip" title="Refresh" ui-sref="users" ui-sref-opts="{reload: true}"> <a data-toggle="tooltip" title="Refresh" ui-sref="users" ui-sref-opts="{reload: true}">
<i class="fa fa-refresh" aria-hidden="true"></i> <i class="fa fa-refresh" aria-hidden="true"></i>
</a> </a>
<i id="loadUsersSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px;"></i>
</rd-header-title> </rd-header-title>
<rd-header-content>User management</rd-header-content> <rd-header-content>User management</rd-header-content>
</rd-header> </rd-header>
@ -98,8 +97,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-12"> <div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!state.validUsername || formValues.Username === '' || (AuthenticationMethod === 1 && formValues.Password === '') || (AuthenticationMethod === 1 && formValues.Password !== formValues.ConfirmPassword)" ng-click="addUser()"><i class="fa fa-user-plus" aria-hidden="true"></i> Add user</button> <button type="button" class="btn btn-primary btn-sm" ng-disabled="state.deploymentInProgress || !state.validUsername || formValues.Username === '' || (AuthenticationMethod === 1 && formValues.Password === '') || (AuthenticationMethod === 1 && formValues.Password !== formValues.ConfirmPassword)" ng-click="addUser()" button-spinner="state.deploymentInProgress">
<i id="createUserSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i> <span ng-hide="state.deploymentInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Create user</span>
<span ng-show="state.deploymentInProgress">Creating user...</span>
</button>
<span class="text-danger" ng-if="state.userCreationError" style="margin: 5px;"> <span class="text-danger" ng-if="state.userCreationError" style="margin: 5px;">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.userCreationError }} <i class="fa fa-exclamation-circle" aria-hidden="true"></i> {{ state.userCreationError }}
</span> </span>

View File

@ -5,7 +5,8 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
userCreationError: '', userCreationError: '',
selectedItemCount: 0, selectedItemCount: 0,
validUsername: false, validUsername: false,
pagination_count: Pagination.getPaginationCount('users') pagination_count: Pagination.getPaginationCount('users'),
deploymentInProgress: false
}; };
$scope.sortType = 'RoleName'; $scope.sortType = 'RoleName';
$scope.sortReverse = false; $scope.sortReverse = false;
@ -57,7 +58,7 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
}; };
$scope.addUser = function() { $scope.addUser = function() {
$('#createUserSpinner').show(); $scope.state.deploymentInProgress = true;
$scope.state.userCreationError = ''; $scope.state.userCreationError = '';
var username = $sanitize($scope.formValues.Username); var username = $sanitize($scope.formValues.Username);
var password = $sanitize($scope.formValues.Password); var password = $sanitize($scope.formValues.Password);
@ -75,22 +76,13 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
Notifications.error('Failure', err, 'Unable to create user'); Notifications.error('Failure', err, 'Unable to create user');
}) })
.finally(function final() { .finally(function final() {
$('#createUserSpinner').hide(); $scope.state.deploymentInProgress = false;
}); });
}; };
function deleteSelectedUsers() { function deleteSelectedUsers() {
$('#loadUsersSpinner').show();
var counter = 0;
var complete = function () {
counter = counter - 1;
if (counter === 0) {
$('#loadUsersSpinner').hide();
}
};
angular.forEach($scope.users, function (user) { angular.forEach($scope.users, function (user) {
if (user.Checked) { if (user.Checked) {
counter = counter + 1;
UserService.deleteUser(user.Id) UserService.deleteUser(user.Id)
.then(function success(data) { .then(function success(data) {
var index = $scope.users.indexOf(user); var index = $scope.users.indexOf(user);
@ -99,9 +91,6 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
}) })
.catch(function error(err) { .catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove user'); Notifications.error('Failure', err, 'Unable to remove user');
})
.finally(function final() {
complete();
}); });
} }
}); });
@ -133,7 +122,6 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
} }
function initView() { function initView() {
$('#loadUsersSpinner').show();
var userDetails = Authentication.getUserDetails(); var userDetails = Authentication.getUserDetails();
var isAdmin = userDetails.role === 1 ? true: false; var isAdmin = userDetails.role === 1 ? true: false;
$scope.isAdmin = isAdmin; $scope.isAdmin = isAdmin;
@ -154,9 +142,6 @@ function ($q, $scope, $state, $sanitize, UserService, TeamService, TeamMembershi
Notifications.error('Failure', err, 'Unable to retrieve users and teams'); Notifications.error('Failure', err, 'Unable to retrieve users and teams');
$scope.users = []; $scope.users = [];
$scope.teams = []; $scope.teams = [];
})
.finally(function final() {
$('#loadUsersSpinner').hide();
}); });
} }

Some files were not shown because too many files have changed in this diff Show More