Started fixing/finishing input group delete. Started moving socket status to header.

This commit is contained in:
Chris Houseknecht
2014-04-25 11:55:49 +00:00
parent 557b92ef05
commit 65859fa446
9 changed files with 82 additions and 67 deletions

View File

@@ -408,12 +408,12 @@ angular.module('Tower', [
}); });
} }
]) ])
.run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'ViewLicense', .run(['$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'ViewLicense',
'Timer', 'ClearScope', 'HideStream', 'Socket', 'Timer', 'ClearScope', 'HideStream', 'Socket',
function ($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense, function ($compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense,
Timer, ClearScope, HideStream, Socket) { Timer, ClearScope, HideStream, Socket) {
var base, sock; var base, e, html, sock;
LoadBasePaths(); LoadBasePaths();
@@ -496,6 +496,12 @@ angular.module('Tower', [
$('#' + tabs + ' #' + tab).tab('show'); $('#' + tabs + ' #' + tab).tab('show');
}; };
html = "<a href=\"\" aw-pop-over=\"{{ socketTip }}\" aw-pop-over-watch=\"socketTip\" data-placement=\"bottom\" data-trigger=\"hover\" " +
"data-popover-title=\"Live Updates\" data-container=\"body\" style=\"font-size: 10px;\"><i class=\"fa icon-socket-{{ socketStatus }}\"></i></a>";
e = angular.element(document.getElementById('socket-beacon'));
e.empty().append(html);
$compile(e)($rootScope);
// Listen for job changes and issue callbacks to initiate // Listen for job changes and issue callbacks to initiate
// DOM updates // DOM updates
function openSocket() { function openSocket() {
@@ -505,6 +511,7 @@ angular.module('Tower', [
$rootScope.$apply(function() { $rootScope.$apply(function() {
sock.checkStatus(); sock.checkStatus();
$rootScope.$emit('SocketErrorEncountered'); $rootScope.$emit('SocketErrorEncountered');
$log.debug('socket status: ' + $rootScope.socketStatus);
}); });
}); });
sock.on("status_changed", function(data) { sock.on("status_changed", function(data) {

View File

@@ -1299,7 +1299,7 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
"class": "btn btn-default", "class": "btn btn-default",
"id": "group-delete-cancel-button" "id": "group-delete-cancel-button"
},{ },{
label: "Continue", label: "Delete",
onClick: function() { onClick: function() {
scope.performDelete(); scope.performDelete();
}, },

View File

@@ -76,18 +76,19 @@ angular.module('ProjectsListDefinition', [])
awToolTip: 'Click for help', awToolTip: 'Click for help',
awTipPlacement: 'top' awTipPlacement: 'top'
},*/ },*/
/*refresh: { refresh: {
mode: 'all', mode: 'all',
awToolTip: "Refresh the page", awToolTip: "Refresh the page",
ngClick: "refresh()" ngClick: "refresh()",
},*/ ngShow: "socketStatus == 'error'"
socket: { },
/*socket: {
mode: 'all', mode: 'all',
iconClass: "{{ 'fa fa-power-off fa-lg socket-' + socketStatus }}", iconClass: "{{ 'fa fa-power-off fa-lg socket-' + socketStatus }}",
awToolTip: "{{ socketTip }}", awToolTip: "{{ socketTip }}",
dataTipWatch: "socketTip", dataTipWatch: "socketTip",
ngClick: "socketToggle()", ngClick: "socketToggle()",
}, },*/
stream: { stream: {
ngClick: "showActivity()", ngClick: "showActivity()",
awToolTip: "View Activity Stream", awToolTip: "View Activity Stream",

View File

@@ -1066,6 +1066,19 @@ input[type="checkbox"].checkbox-no-label {
content: "\f04b"; content: "\f04b";
} }
.icon-socket-ok:before {
content: "\f111";
color: @green;
}
.icon-socket-error:before {
content: "\f111";
color: @red;
}
.icon-socket-connecting:before {
content: "\f042";
color: @warning;
}
.badge { .badge {
padding: 2px 3px 3px 4px; padding: 2px 3px 3px 4px;
font-size: 10px; font-size: 10px;
@@ -1203,18 +1216,6 @@ input[type="checkbox"].checkbox-no-label {
} }
/* end */ /* end */
/* Socket icon */
.socket-ok {
color: @green;
}
.socket-error {
color: @red;
}
.socket-connecting {
color: @warning
}
/* end */
.field-success { .field-success {
color: #5bb75b; color: #5bb75b;
} }

View File

@@ -89,7 +89,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
} }
function getShowState(key) { function getShowState(key) {
var result = true; var result = null;
local_child_store.every(function(child) { local_child_store.every(function(child) {
if (child.key === key) { if (child.key === key) {
result = (child.show !== undefined) ? child.show : true; result = (child.show !== undefined) ? child.show : true;
@@ -129,6 +129,20 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
expand = (sorted[i].children.length > 0) ? getExpandState(sorted[i].id) : false; expand = (sorted[i].children.length > 0) ? getExpandState(sorted[i].id) : false;
show = getShowState(sorted[i].id); show = getShowState(sorted[i].id);
if (show === null) {
// this is a node we haven't seen before, so check the parent expand/collapse state
// If parent is not expanded, then child should be hidden.
show = true;
if (parent > 0) {
groups.every(function(g) {
if (g.id === parent) {
show = getExpandState(g.key);
return false;
}
return true;
});
}
}
group = { group = {
name: sorted[i].name, name: sorted[i].name,
@@ -173,18 +187,6 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
group.ngicon = 'fa fa-square-o node-no-toggle'; group.ngicon = 'fa fa-square-o node-no-toggle';
} }
if (new_group_id && group.group_id === new_group_id) { if (new_group_id && group.group_id === new_group_id) {
// For new group
// Find parent's expand state and set the show property accordingly.
// If parent is not expanded, then child should be hidden.
if (parent > 0) {
scope.groups.every(function(g) {
if (g.id === group.parent) {
group.show = getExpandState(g.key);
return false;
}
return true;
});
}
scope.selected_tree_id = id; scope.selected_tree_id = id;
scope.selected_group_id = group.group_id; scope.selected_group_id = group.group_id;
} }

View File

@@ -12,7 +12,7 @@
angular.module('SocketIO', ['AuthService', 'Utilities']) angular.module('SocketIO', ['AuthService', 'Utilities'])
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Alert', function ($rootScope, $location, $log, Authorization, Alert) { .factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', function ($rootScope, $location, $log, Authorization) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
host = $location.host(), host = $location.host(),
@@ -23,17 +23,23 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
if (scope.removeSocketErrorEncountered) { if (scope.removeSocketErrorEncountered) {
scope.removeSocketErrorEncountered(); scope.removeSocketErrorEncountered();
} }
scope.removeSocketErrorEncountered = scope.$on('SocketErrorEncountered', function(e, reason) { scope.removeSocketErrorEncountered = scope.$on('socketStatusChange', function() {
if (reason === 'Session expired') { switch(scope.socketStatus) {
// encountered expired token, ask user to log in again case 'error':
$rootScope.sessionTimer.expireSession(); scope.socketTip = "There was an error connecting to the websocket server. Click for troubleshooting help.";
$location.url('/login'); break;
case 'connecting':
scope.socketTip = "Attempting to connect to the websocket server. Click for troubleshooting help.";
break;
case "ok":
scope.socketTip = "Connected to the websocket server. Pages containing job status information for playbook runs, SCM updates and inventory " +
"sync processes will automatically update in real-time.";
} }
else if (scope.socketStatus === 'error') { /*else if (scope.socketStatus === 'error') {
Alert("Connection Error", "Error encountered while attempting to connect to the websocket server. Confirm the server " + Alert("Connection Error", "Error encountered while attempting to connect to the websocket server. Confirm the server " +
"is up. Use the <i class=\"fa fa-power-off\"></i> button found on the Inventories, Projects and Jobs pages to reconnect.", "is up. Use the <i class=\"fa fa-power-off\"></i> button found on the Inventories, Projects and Jobs pages to reconnect.",
"alert-danger"); "alert-danger");
} }*/
}); });
return { return {
@@ -61,14 +67,14 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
$log.debug('Socket connecting...'); $log.debug('Socket connecting...');
self.scope.$apply(function () { self.scope.$apply(function () {
self.scope.socketStatus = 'connecting'; self.scope.socketStatus = 'connecting';
self.scope.socketTip = 'Connecting. Click to cancel.'; self.scope.$emit('socketStatusChange');
}); });
}); });
self.socket.on('connect', function() { self.socket.on('connect', function() {
$log.debug('Socket connection established'); $log.debug('Socket connection established');
self.scope.$apply(function () { self.scope.$apply(function () {
self.scope.socketStatus = 'ok'; self.scope.socketStatus = 'ok';
self.scope.socketTip = 'Connected. Click to close.'; self.scope.$emit('socketStatusChange');
}); });
}); });
self.socket.on('connect_failed', function(reason) { self.socket.on('connect_failed', function(reason) {
@@ -76,8 +82,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
$log.error('Socket connection failed: ' + r); $log.error('Socket connection failed: ' + r);
self.scope.$apply(function () { self.scope.$apply(function () {
self.scope.socketStatus = 'error'; self.scope.socketStatus = 'error';
self.scope.socketTip = 'Connection failed. Click to retry.'; self.scope.$emit('socketStatusChange');
self.scope.$emit('SocketErrorEncountered');
}); });
}); });
@@ -85,8 +90,7 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
$log.debug('Socket disconnected'); $log.debug('Socket disconnected');
self.scope.$apply(function() { self.scope.$apply(function() {
self.socketStatus = 'error'; self.socketStatus = 'error';
self.socketTip = 'Disconnected. Click to connect.'; self.scope.$emit('socketStatusChange');
self.scope.$emit('SocketErrorEncountered');
}); });
}); });
self.socket.on('error', function(reason) { self.socket.on('error', function(reason) {
@@ -94,36 +98,35 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
$log.debug('Socket error: ' + r); $log.debug('Socket error: ' + r);
self.scope.$apply(function() { self.scope.$apply(function() {
self.scope.socketStatus = 'error'; self.scope.socketStatus = 'error';
self.scope.socketTip = 'Connection error encountered. Click to retry.'; self.scope.$emit('socketStatusChange');
self.scope.$emit('SocketErrorEncountered');
}); });
}); });
self.socket.on('reconnecting', function() { self.socket.on('reconnecting', function() {
$log.debug('Socket attempting reconnect...'); $log.debug('Socket attempting reconnect...');
self.scope.$apply(function() { self.scope.$apply(function() {
self.scope.socketStatus = 'connecting'; self.scope.socketStatus = 'connecting';
self.scope.socketTip = 'Connecting. Click to cancel.'; self.scope.$emit('socketStatusChange');
}); });
}); });
self.socket.on('reconnect', function() { self.socket.on('reconnect', function() {
$log.debug('Socket reconnected'); $log.debug('Socket reconnected');
self.scope.$apply(function() { self.scope.$apply(function() {
self.scope.socketStatus = 'ok'; self.scope.socketStatus = 'ok';
self.scope.socketTip = 'Connected. Click to close.'; self.scope.$emit('socketStatusChange');
}); });
}); });
self.socket.on('reconnect_failed', function(reason) { self.socket.on('reconnect_failed', function(reason) {
$log.error('Socket reconnect failed: ' + reason); $log.error('Socket reconnect failed: ' + reason);
self.scope.$apply(function() { self.scope.$apply(function() {
self.scope.socketStatus = 'error'; self.scope.socketStatus = 'error';
self.scope.socketTip = 'Connection failed. Click to retry.'; self.scope.$emit('socketStatusChange');
self.scope.$emit('SocketErrorEncountered'); });
});
}); });
} }
else { else {
// Encountered expired token // encountered expired token, redirect to login page
self.scope.$emit('SocketErrorEncountered', 'Session expired'); $rootScope.sessionTimer.expireSession();
$location.url('/login');
} }
}, },
checkStatus: function() { checkStatus: function() {

View File

@@ -285,7 +285,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job
.directive('awPopOver', ['$compile', function($compile) { .directive('awPopOver', ['$compile', function($compile) {
return function(scope, element, attrs) { return function(scope, element, attrs) {
var placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left', var placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left',
title = (attrs.title !== undefined && attrs.title !== null) ? attrs.title : 'Help', title = (attrs.title) ? attrs.title : (attrs.popoverTitle) ? attrs.popoverTitle : 'Help',
container = (attrs.container !== undefined) ? attrs.container : false, container = (attrs.container !== undefined) ? attrs.container : false,
trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manual'; trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manual';
if (attrs.awPopOverWatch) { if (attrs.awPopOverWatch) {

View File

@@ -54,42 +54,42 @@
<div ng-show="groupsCount > 0 || hostsCount > 0"> <div ng-show="groupsCount > 0 || hostsCount > 0">
<div class="alert alert-info"> <div class="alert alert-info">
<p>Deleting group <em>{{ group_name }}</em>. <p>Deleting group <em>{{ group_name }}</em>.
<span ng-show="groupsCount > 0 && hostsCount > 0"> This group has {{ groupsCount }} child groups and {{ hostsCount }} child hosts. </span> <span ng-show="groupsCount > 0 && hostsCount > 0"> This group contains {{ groupsCount }} groups and {{ hostsCount }} hosts. </span>
<span ng-show="groupsCount == 0 && hostsCount > 0"> This group has {{ hostsCount }} child hosts. </span> <span ng-show="groupsCount == 0 && hostsCount > 0"> This group contains {{ hostsCount }} hosts. </span>
<span ng-show="groupsCopunt > 0 && hostsCount == 0"> This group has {{ groupsCount }} child groups. </span> <span ng-show="groupsCopunt > 0 && hostsCount == 0"> This group contains {{ groupsCount }} groups. </span>
Delete or preserve the group's children?</p> Delete or preserve the group's children?</p>
<div style="width: 50%; margin: 15px auto;"> <div style="width: 50%; margin: 15px auto;">
<div class="radio" ng-show="groupsCount > 0 && hostsCount > 0"> <div class="radio" ng-show="groupsCount > 0 && hostsCount > 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option1" value="preserve-all"> Preserve child groups and hosts <input type="radio" ng-model="deleteOption" name="delete_option1" value="preserve-all"> Preserve groups and hosts
</label> </label>
</div> </div>
<div class="radio" ng-show="groupsCount > 0 && hostsCount > 0"> <div class="radio" ng-show="groupsCount > 0 && hostsCount > 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option1" value="delete-all"> Delete child groups and hosts <input type="radio" ng-model="deleteOption" name="delete_option1" value="delete-all"> Delete groups and hosts
</label> </label>
</div> </div>
<div class="radio" ng-show="groupsCount > 0 && hostsCount == 0"> <div class="radio" ng-show="groupsCount > 0 && hostsCount == 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option2" value="preserve-all"> Preserve child groups <input type="radio" ng-model="deleteOption" name="delete_option2" value="preserve-all"> Preserve groups
</label> </label>
</div> </div>
<div class="radio" ng-show="groupsCount > 0 && hostsCount == 0"> <div class="radio" ng-show="groupsCount > 0 && hostsCount == 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option2" value="delete-all"> Delete child groups <input type="radio" ng-model="deleteOption" name="delete_option2" value="delete-all"> Delete groups
</label> </label>
</div> </div>
<div class="radio" ng-show="groupsCount == 0 && hostsCount > 0"> <div class="radio" ng-show="groupsCount == 0 && hostsCount > 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option3" value="preserve-all"> Preserve child hosts <input type="radio" ng-model="deleteOption" name="delete_option3" value="preserve-all"> Preserve hosts
</label> </label>
</div> </div>
<div class="radio" ng-show="groupsCount == 0 && hostsCount > 0"> <div class="radio" ng-show="groupsCount == 0 && hostsCount > 0">
<label> <label>
<input type="radio" ng-model="deleteOption" name="delete_option3" value="delete-all"> Delete child hosts <input type="radio" ng-model="deleteOption" name="delete_option3" value="delete-all"> Delete hosts
</label> </label>
</div> </div>

View File

@@ -179,6 +179,7 @@
</div> </div>
<div class="collapse navbar-collapse navbar-responsive-collapse"> <div class="collapse navbar-collapse navbar-responsive-collapse">
<ul class="nav navbar-nav pull-right"> <ul class="nav navbar-nav pull-right">
<li id="socket-beacon"></li>
<li ng-show="current_user.username != null && current_user.username != undefined"> <li ng-show="current_user.username != null && current_user.username != undefined">
<a id="main_view_user" href="" ng-click="viewCurrentUser()" ng-bind="'Hello! ' + current_user.username"></a></li> <a id="main_view_user" href="" ng-click="viewCurrentUser()" ng-bind="'Hello! ' + current_user.username"></a></li>
<li ng-show="userLoggedIn == true"><a id="main_view_license" href="" ng-click="viewLicense()">View License</a></li> <li ng-show="userLoggedIn == true"><a id="main_view_license" href="" ng-click="viewLicense()">View License</a></li>