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,330 +1,334 @@
<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>
<rd-widget-body classes="padding"> <rd-widget-body classes="padding">
<div class="btn-group" role="group" aria-label="..."> <div class="btn-group" role="group" aria-label="...">
<button class="btn btn-success" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button> <button class="btn btn-success" ng-click="start()" ng-disabled="container.State.Running"><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button>
<button class="btn btn-danger" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button> <button class="btn btn-danger" ng-click="stop()" ng-disabled="!container.State.Running"><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button>
<button class="btn btn-danger" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button> <button class="btn btn-danger" ng-click="kill()" ng-disabled="!container.State.Running"><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button>
<button class="btn btn-primary" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Restart</button> <button class="btn btn-primary" ng-click="restart()" ng-disabled="!container.State.Running"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Restart</button>
<button class="btn btn-primary" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button> <button class="btn btn-primary" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button>
<button class="btn btn-primary" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button> <button class="btn btn-primary" ng-click="unpause()" ng-disabled="!container.State.Paused"><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button>
<button class="btn btn-danger" ng-click="confirmRemove()"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button> <button class="btn btn-danger" ng-click="confirmRemove()"><i class="fa fa-trash space-right" aria-hidden="true"></i>Remove</button>
<button class="btn btn-danger" ng-click="recreate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Recreate</button> <button class="btn btn-danger" ng-click="recreate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-refresh space-right" aria-hidden="true"></i>Recreate</button>
<button class="btn btn-primary" ng-click="duplicate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-files-o space-right" aria-hidden="true"></i>Duplicate/Edit</button> <button class="btn btn-primary" ng-click="duplicate()" ng-if="!container.Config.Labels['com.docker.swarm.service.id']"><i class="fa fa-files-o space-right" aria-hidden="true"></i>Duplicate/Edit</button>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title="Container status"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>ID</td>
<td>{{ container.Id }}</td>
</tr>
<tr>
<td>Name</td>
<td ng-if="!container.edit">
{{ container.Name|trimcontainername }}
<a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
</td>
<td ng-if="container.edit">
<form ng-submit="renameContainer()">
<input type="text" class="containerNameInput" ng-model="container.newContainerName">
<a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
<a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
</form>
</td>
</tr>
<tr ng-if="container.NetworkSettings.IPAddress">
<td>IP address</td>
<td>{{ container.NetworkSettings.IPAddress }}</td>
</tr>
<tr>
<td>Status</td>
<td>
<i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
<i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
{{ container.State|getstatetext }} since {{ activityTime }}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
</td>
</tr>
<tr>
<td>Created</td>
<td>{{ container.Created|getisodate }}</td>
</tr>
<tr ng-if="container.State.Running">
<td>Start time</td>
<td>{{ container.State.StartedAt|getisodate }}</td>
</tr>
<tr ng-if="!container.State.Running && container.State.Status !== 'created'">
<td>Finished</td>
<td>{{ container.State.FinishedAt|getisodate }}</td>
</tr>
<tr>
<td colspan="2">
<div class="btn-group" role="group" aria-label="...">
<a class="btn btn-outline-secondary" type="button" ui-sref="stats({id: container.Id})"><i class="fa fa-area-chart space-right" aria-hidden="true"></i>Stats</a>
<a class="btn btn-outline-secondary" type="button" ui-sref="containerlogs({id: container.Id})"><i class="fa fa-exclamation-circle space-right" aria-hidden="true"></i>Logs</a>
<a class="btn btn-outline-secondary" type="button" ui-sref="console({id: container.Id})"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
<a class="btn btn-outline-secondary" type="button" ui-sref="inspect({id: container.Id})"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
</div>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<!-- access-control-panel -->
<por-access-control-panel
ng-if="container && applicationState.application.authentication"
resource-id="container.Id"
resource-control="container.ResourceControl"
resource-type="'container'">
</por-access-control-panel>
<!-- !access-control-panel -->
<div ng-if="container.State.Health" class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title="Container health"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Status</td>
<td>
<i ng-class="{'healthy': 'fa fa-heartbeat space-right green-icon', 'unhealthy': 'fa fa-heartbeat space-right red-icon', 'starting': 'fa fa-heartbeat space-right orange-icon'}[container.State.Health.Status]"></i>
{{ container.State.Health.Status }}
</td>
</tr>
<tr>
<td>Failure count</td>
<td>{{ container.State.Health.FailingStreak }}</td>
</tr>
<tr>
<td>Last output</td>
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-clone" title="Create image"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<!-- tag-description -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">
You can create an image from this container, this allows you to backup important data or save
helpful configurations. You'll be able to spin up another container based on this image afterward.
</span>
</div>
</div> </div>
<!-- !tag-description --> </rd-widget-body>
<!-- image-and-registry --> </rd-widget>
<div class="form-group"> </div>
<por-image-registry image="config.Image" registry="config.Registry"></por-image-registry>
</div>
<!-- !image-and-registry -->
<!-- tag-note -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
</div>
</div>
<!-- !tag-note -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button>
<i id="createImageSpinner" class="fa fa-cog fa-spin" style="margin-left: 5px; display: none;"></i>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</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 status"></rd-widget-header>
<rd-widget-body classes="no-padding"> <rd-widget-body classes="no-padding">
<table class="table"> <table class="table">
<tbody> <tbody>
<tr> <tr>
<td>Image</td> <td>ID</td>
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td> <td>{{ container.Id }}</td>
</tr> </tr>
<tr ng-if="portBindings.length > 0"> <tr>
<td>Port configuration</td> <td>Name</td>
<td> <td ng-if="!container.edit">
<div ng-repeat="portMapping in portBindings"> {{ container.Name|trimcontainername }}
{{ portMapping.container }} <i class="fa fa-long-arrow-right"></i> {{ portMapping.host }} <a href="" data-toggle="tooltip" title="Edit container name" ng-click="container.edit = true;"><i class="fa fa-edit"></i></a>
</div> </td>
</td> <td ng-if="container.edit">
</tr> <form ng-submit="renameContainer()">
<tr> <input type="text" class="containerNameInput" ng-model="container.newContainerName">
<td>CMD</td> <a href="" ng-click="container.edit = false;"><i class="fa fa-times"></i></a>
<td><code>{{ container.Config.Cmd|command }}</code></td> <a href="" ng-click="renameContainer()"><i class="fa fa-check-square-o"></i></a>
</tr> </form>
<tr> </td>
<td>ENV</td> </tr>
<td> <tr ng-if="container.NetworkSettings.IPAddress">
<table class="table table-bordered table-condensed"> <td>IP address</td>
<tr ng-repeat="var in container.Config.Env track by $index"> <td>{{ container.NetworkSettings.IPAddress }}</td>
<td>{{ var|key: '=' }}</td> </tr>
<td>{{ var|value: '=' }}</td> <tr>
</tr> <td>Status</td>
</table> <td>
</td> <i class="fa fa-heartbeat space-right green-icon" ng-if="container.State.Running"></i>
</tr> <i class="fa fa-heartbeat space-right red-icon" ng-if="!container.State.Running && container.State.Status !== 'created'"></i>
<tr ng-if="!(container.Config.Labels | emptyobject)"> {{ container.State|getstatetext }} since {{ activityTime }}<span ng-if="!container.State.Running && container.State.Status !== 'created'"> with exit code {{ container.State.ExitCode }}</span>
<td>Labels</td> </td>
<td> </tr>
<table class="table table-bordered table-condensed"> <tr>
<tr ng-repeat="(k, v) in container.Config.Labels"> <td>Created</td>
<td>{{ k }}</td> <td>{{ container.Created|getisodate }}</td>
<td>{{ v }}</td> </tr>
</tr> <tr ng-if="container.State.Running">
</table> <td>Start time</td>
</td> <td>{{ container.State.StartedAt|getisodate }}</td>
</tr> </tr>
<tr ng-if="container.HostConfig.RestartPolicy.Name !== 'no'"> <tr ng-if="!container.State.Running && container.State.Status !== 'created'">
<td>Restart policies</td> <td>Finished</td>
<td> <td>{{ container.State.FinishedAt|getisodate }}</td>
<table class="table table-bordered table-condensed"> </tr>
<tr> <tr>
<td class="col-md-3">Name</td> <td colspan="2">
<td>{{ container.HostConfig.RestartPolicy.Name }}</td> <div class="btn-group" role="group" aria-label="...">
</tr> <a class="btn btn-outline-secondary" type="button" ui-sref="stats({id: container.Id})"><i class="fa fa-area-chart space-right" aria-hidden="true"></i>Stats</a>
<tr> <a class="btn btn-outline-secondary" type="button" ui-sref="containerlogs({id: container.Id})"><i class="fa fa-exclamation-circle space-right" aria-hidden="true"></i>Logs</a>
<td class="col-md-3">MaximumRetryCount</td> <a class="btn btn-outline-secondary" type="button" ui-sref="console({id: container.Id})"><i class="fa fa-terminal space-right" aria-hidden="true"></i>Console</a>
<td> <a class="btn btn-outline-secondary" type="button" ui-sref="inspect({id: container.Id})"><i class="fa fa-info-circle space-right" aria-hidden="true"></i>Inspect</a>
{{ container.HostConfig.RestartPolicy.MaximumRetryCount }} </div>
</td> </td>
</tr> </tr>
</table> </tbody>
</td> </table>
</tr> </rd-widget-body>
</tbody> </rd-widget>
</table> </div>
</rd-widget-body>
</rd-widget>
</div> </div>
</div>
<div class="row" ng-if="container.Mounts.length > 0"> <!-- access-control-panel -->
<div class="col-lg-12 col-md-12 col-xs-12"> <por-access-control-panel
<rd-widget> ng-if="container && applicationState.application.authentication"
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header> resource-id="container.Id"
<rd-widget-body classes="no-padding"> resource-control="container.ResourceControl"
<table class="table"> resource-type="'container'">
<thead> </por-access-control-panel>
<tr> <!-- !access-control-panel -->
<th>Host/volume</th>
<th>Path in container</th> <div ng-if="container.State.Health" class="row">
</tr> <div class="col-lg-12 col-md-12 col-xs-12">
</thead> <rd-widget>
<tbody> <rd-widget-header icon="fa-server" title="Container health"></rd-widget-header>
<tr ng-repeat="vol in container.Mounts"> <rd-widget-body classes="no-padding">
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td> <table class="table">
<td ng-if="vol.Type === 'volume'"><a ui-sref="volume({id: vol.Name})">{{ vol.Name }}</a></td> <tbody>
<td>{{ vol.Destination }}</td> <tr>
</tr> <td>Status</td>
</tbody> <td>
</table> <i ng-class="{'healthy': 'fa fa-heartbeat space-right green-icon', 'unhealthy': 'fa fa-heartbeat space-right red-icon', 'starting': 'fa fa-heartbeat space-right orange-icon'}[container.State.Health.Status]"></i>
</rd-widget-body> {{ container.State.Health.Status }}
</rd-widget> </td>
</tr>
<tr>
<td>Failure count</td>
<td>{{ container.State.Health.FailingStreak }}</td>
</tr>
<tr>
<td>Last output</td>
<td>{{ container.State.Health.Log[container.State.Health.Log.length - 1].Output }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div> </div>
</div>
<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-clone" title="Create image"></rd-widget-header>
<div class="pull-right"> <rd-widget-body>
Items per page: <form class="form-horizontal">
<select ng-model="state.pagination_count" ng-change="changePaginationCount()"> <!-- tag-description -->
<option value="0">All</option> <div class="form-group">
<option value="10">10</option> <div class="col-sm-12">
<option value="25">25</option> <span class="small text-muted">
<option value="50">50</option> You can create an image from this container, this allows you to backup important data or save
<option value="100">100</option> helpful configurations. You'll be able to spin up another container based on this image afterward.
</select> </span>
</div> </div>
</rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<thead>
<th>Network Name</th>
<th>IP Address</th>
<th>Gateway</th>
<th>MacAddress</th>
<th>Actions</th>
</thead>
<tbody>
<tr dir-paginate="(key, value) in container.NetworkSettings.Networks | itemsPerPage: state.pagination_count">
<td><a ui-sref="network({id: value.NetworkID})">{{ key }}</a></td>
<td>{{ value.IPAddress || '-' }}</td>
<td>{{ value.Gateway || '-' }}</td>
<td>{{ value.MacAddress || '-' }}</td>
<td>
<button type="button" class="btn btn-xs btn-danger" ng-click="containerLeaveNetwork(container, value.NetworkID)"><i class="fa fa-trash space-right" aria-hidden="true"></i>Leave Network</button>
</td>
</tr>
<tr ng-if="(container.NetworkSettings.Networks | emptyobject)">
<td colspan="5" class="text-center text-muted">No networks connected.</td>
</tr>
</tbody>
</table>
<div class="pagination-controls">
<dir-pagination-controls></dir-pagination-controls>
</div>
<hr />
<form class="form-horizontal">
<!-- network-input -->
<div class="row">
<label for="container_network" class="col-sm-3 col-lg-2 control-label text-left">Join a Network</label>
<div class="col-sm-5 col-lg-4">
<select class="form-control" ng-model="selectedNetwork" id="container_network">
<option selected disabled hidden value="">Select a network</option>
<option ng-repeat="net in availableNetworks" ng-value="net.Id">{{ net.Name }}</option>
</select>
</div> </div>
<div class="col-sm-1"> <!-- !tag-description -->
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!selectedNetwork" ng-click="containerJoinNetwork(container, selectedNetwork)">Join Network</button> <!-- image-and-registry -->
<div class="form-group">
<por-image-registry image="config.Image" registry="config.Registry"></por-image-registry>
</div> </div>
<!-- !image-and-registry -->
<!-- tag-note -->
<div class="form-group">
<div class="col-sm-12">
<span class="small text-muted">Note: if you don't specify the tag in the image name, <span class="label label-default">latest</span> will be used.</span>
</div>
</div>
<!-- !tag-note -->
<div class="form-group">
<div class="col-sm-12">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="!config.Image" ng-click="commit()">Create</button>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-server" title="Container details"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Image</td>
<td><a ui-sref="image({id: container.Image})">{{ container.Image }}</a></td>
</tr>
<tr ng-if="portBindings.length > 0">
<td>Port configuration</td>
<td>
<div ng-repeat="portMapping in portBindings">
{{ portMapping.container }} <i class="fa fa-long-arrow-right"></i> {{ portMapping.host }}
</div>
</td>
</tr>
<tr>
<td>CMD</td>
<td><code>{{ container.Config.Cmd|command }}</code></td>
</tr>
<tr>
<td>ENV</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="var in container.Config.Env track by $index">
<td>{{ var|key: '=' }}</td>
<td>{{ var|value: '=' }}</td>
</tr>
</table>
</td>
</tr>
<tr ng-if="!(container.Config.Labels | emptyobject)">
<td>Labels</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="(k, v) in container.Config.Labels">
<td>{{ k }}</td>
<td>{{ v }}</td>
</tr>
</table>
</td>
</tr>
<tr ng-if="container.HostConfig.RestartPolicy.Name !== 'no'">
<td>Restart policies</td>
<td>
<table class="table table-bordered table-condensed">
<tr>
<td class="col-md-3">Name</td>
<td>{{ container.HostConfig.RestartPolicy.Name }}</td>
</tr>
<tr>
<td class="col-md-3">MaximumRetryCount</td>
<td>
{{ container.HostConfig.RestartPolicy.MaximumRetryCount }}
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row" ng-if="container.Mounts.length > 0">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-cubes" title="Volumes"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<thead>
<tr>
<th>Host/volume</th>
<th>Path in container</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="vol in container.Mounts">
<td ng-if="vol.Type === 'bind'">{{ vol.Source }}</td>
<td ng-if="vol.Type === 'volume'"><a ui-sref="volume({id: vol.Name})">{{ vol.Name }}</a></td>
<td>{{ vol.Destination }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-sitemap" title="Connected networks">
<div class="pull-right">
Items per page:
<select ng-model="state.pagination_count" ng-change="changePaginationCount()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div> </div>
</form> </rd-widget-header>
</rd-widget-body> <rd-widget-body classes="no-padding">
</rd-widget> <table class="table">
<thead>
<th>Network Name</th>
<th>IP Address</th>
<th>Gateway</th>
<th>MacAddress</th>
<th>Actions</th>
</thead>
<tbody>
<tr dir-paginate="(key, value) in container.NetworkSettings.Networks | itemsPerPage: state.pagination_count">
<td><a ui-sref="network({id: value.NetworkID})">{{ key }}</a></td>
<td>{{ value.IPAddress || '-' }}</td>
<td>{{ value.Gateway || '-' }}</td>
<td>{{ value.MacAddress || '-' }}</td>
<td>
<button type="button" class="btn btn-xs btn-danger" ng-disabled="state.leaveNetworkInProgress" button-spinner="state.leaveNetworkInProgress" ng-click="containerLeaveNetwork(container, value.NetworkID)">
<span ng-hide="state.leaveNetworkInProgress"><i class="fa fa-trash space-right" aria-hidden="true"></i> Leave network</span>
<span ng-show="state.leaveNetworkInProgress">Leaving network...</span>
</button>
</td>
</tr>
<tr ng-if="(container.NetworkSettings.Networks | emptyobject)">
<td colspan="5" class="text-center text-muted">No networks connected.</td>
</tr>
</tbody>
</table>
<div class="pagination-controls">
<dir-pagination-controls></dir-pagination-controls>
</div>
<hr />
<form class="form-horizontal">
<!-- network-input -->
<div class="row">
<label for="container_network" class="col-sm-3 col-lg-2 control-label text-left">Join a Network</label>
<div class="col-sm-5 col-lg-4">
<select class="form-control" ng-model="selectedNetwork" id="container_network">
<option selected disabled hidden value="">Select a network</option>
<option ng-repeat="net in availableNetworks" ng-value="net.Id">{{ net.Name }}</option>
</select>
</div>
<div class="col-sm-1">
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.joinNetworkInProgress || !selectedNetwork" ng-click="containerJoinNetwork(container, selectedNetwork)" button-spinner="state.joinNetworkInProgress">
<span ng-hide="state.joinNetworkInProgress">Join network</span>
<span ng-show="state.joinNetworkInProgress">Joining network...</span>
</button>
</div>
</div>
</form>
</rd-widget-body>
</rd-widget>
</div>
</div> </div>
</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

@ -1,9 +1,8 @@
angular.module('engine', []) angular.module('engine', [])
.controller('EngineController', ['$q', '$scope', 'SystemService', 'Notifications', .controller('EngineController', ['$q', '$scope', 'SystemService', 'Notifications',
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