mirror of
https://github.com/ansible/awx.git
synced 2026-01-17 12:41:19 -03:30
Track inventory group expand/collapse in local storage. Support multiple inventory syncs running simultaneously. Moved socket connection for job_events to app root. Added on/off socket button so user can tell state of connection and reset/reconnect when needed. Applied AC-1211 fix.
This commit is contained in:
parent
b4d06796a3
commit
49c26aad10
@ -409,9 +409,11 @@ angular.module('Tower', [
|
||||
}
|
||||
])
|
||||
.run(['$cookieStore', '$rootScope', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'ViewLicense',
|
||||
'Timer', 'ClearScope', 'HideStream',
|
||||
'Timer', 'ClearScope', 'HideStream', 'Socket',
|
||||
function ($cookieStore, $rootScope, CheckLicense, $location, Authorization, LoadBasePaths, ViewLicense,
|
||||
Timer, ClearScope, HideStream) {
|
||||
Timer, ClearScope, HideStream, Socket) {
|
||||
|
||||
var base, sock;
|
||||
|
||||
LoadBasePaths();
|
||||
|
||||
@ -470,7 +472,7 @@ angular.module('Tower', [
|
||||
}
|
||||
|
||||
// If browser refresh, activate the correct tab
|
||||
var base = ($location.path().replace(/^\//, '').split('/')[0]);
|
||||
base = ($location.path().replace(/^\//, '').split('/')[0]);
|
||||
if (base === '') {
|
||||
base = 'home';
|
||||
$location.path('/home');
|
||||
@ -493,5 +495,38 @@ angular.module('Tower', [
|
||||
e.preventDefault();
|
||||
$('#' + tabs + ' #' + tab).tab('show');
|
||||
};
|
||||
|
||||
// Listen for job changes and issue callbacks to initiate
|
||||
// DOM updates
|
||||
function openSocket() {
|
||||
sock = Socket({ scope: $rootScope, endpoint: "jobs" });
|
||||
sock.init();
|
||||
setTimeout(function() {
|
||||
$rootScope.$apply(function() {
|
||||
sock.checkStatus();
|
||||
$rootScope.$emit('SocketErrorEncountered');
|
||||
});
|
||||
});
|
||||
sock.on("status_changed", function(data) {
|
||||
$rootScope.$emit('JobStatusChange', data);
|
||||
});
|
||||
}
|
||||
openSocket();
|
||||
|
||||
$rootScope.socketToggle = function() {
|
||||
switch($rootScope.socketStatus) {
|
||||
case 'ok':
|
||||
case 'connecting':
|
||||
sock = null;
|
||||
$rootScope.socketStatus = 'error';
|
||||
$rootScope.socketTip = 'Disconnected. Click to connect.';
|
||||
break;
|
||||
case 'error':
|
||||
sock = null;
|
||||
$rootScope.socketStatus = '';
|
||||
$rootScope.socketTip = '';
|
||||
setTimeout(openSocket, 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
|
||||
@ -471,11 +471,11 @@ InventoriesAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log
|
||||
|
||||
|
||||
|
||||
function InventoriesEdit($scope, $location, $routeParams, $compile, $log, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait,
|
||||
function InventoriesEdit($scope, $location, $routeParams, $compile, $log, $rootScope, GenerateList, ClearScope, InventoryGroups, InventoryHosts, BuildTree, Wait,
|
||||
GetSyncStatusMsg, InjectHosts, HostsReload, GroupsEdit, GroupsDelete, Breadcrumbs, LoadBreadCrumbs, Empty, Rest, ProcessErrors,
|
||||
InventoryUpdate, Alert, ToggleChildren, ViewUpdateStatus, GroupsCancelUpdate, Find, EditInventoryProperties, HostsEdit,
|
||||
HostsDelete, ToggleHostEnabled, CopyMoveGroup, CopyMoveHost, Stream, GetBasePath, ShowJobSummary, ApplyEllipsis, WatchInventoryWindowResize,
|
||||
HelpDialog, InventoryGroupsHelp, Store, ViewJob, Socket) {
|
||||
HelpDialog, InventoryGroupsHelp, Store, ViewJob) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -489,6 +489,40 @@ function InventoriesEdit($scope, $location, $routeParams, $compile, $log, Genera
|
||||
title: '{{ inventory_name }}'
|
||||
});
|
||||
|
||||
// Handle inventory sync status changes
|
||||
if ($rootScope.rmoveJobStatusChange) {
|
||||
$rootScope.removeJobStatusChange();
|
||||
}
|
||||
$rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange', function(e, data) {
|
||||
var group, stat;
|
||||
if ($scope.groups) {
|
||||
// Assuming we have a list of groups available
|
||||
group = Find({ list: $scope.groups, key: 'group_id', val: data.group_id });
|
||||
if (group) {
|
||||
// And we found the affected group
|
||||
$log.debug('Received event for group: ' + group.name);
|
||||
if (data.status === 'failed' || data.status === 'successful') {
|
||||
$log.debug('Update completed. Refreshing the tree.');
|
||||
$scope.refreshGroups(group.id, group.group_id);
|
||||
}
|
||||
else {
|
||||
$log.debug('Status changed to: ' + data.status);
|
||||
stat = GetSyncStatusMsg({
|
||||
status: data.status,
|
||||
has_inventory_sources: group.has_inventory_sources,
|
||||
source: group.source
|
||||
});
|
||||
$log.debug('Changing tooltip to: ' + stat.tooltip);
|
||||
group.status = data.status;
|
||||
group.status_class = stat['class'];
|
||||
group.status_tooltip = stat.tooltip;
|
||||
group.launch_tooltip = stat.launch_tip;
|
||||
group.launch_class = stat.launch_class;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// After the tree data loads for the first time, generate the groups and hosts lists
|
||||
if ($scope.removeGroupTreeLoaded) {
|
||||
$scope.removeGroupTreeLoaded();
|
||||
@ -643,38 +677,6 @@ function InventoriesEdit($scope, $location, $routeParams, $compile, $log, Genera
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.removeWatchUpdateStatus) {
|
||||
$scope.removeWatchUpdateStatus();
|
||||
}
|
||||
$scope.removeWatchUpdateStatus = $scope.$on('WatchUpdateStatus', function(e, job_id, group_id, tree_id) {
|
||||
var io = Socket({ scope: $scope, endpoint: "jobs" }),
|
||||
group = Find({ list: $scope.groups, key: 'id', val: tree_id }),
|
||||
stat;
|
||||
$log.debug('Watching for updates to job: ' + job_id + ' for group: ' + group_id + ' ' + group.name);
|
||||
io.init();
|
||||
io.on("status_changed", function(data) {
|
||||
Wait('stop');
|
||||
if (data.status === "failed" || data.status === "successful") {
|
||||
$log.debug('Update completed. Refreshing the tree.');
|
||||
$scope.refreshGroups(tree_id, group_id);
|
||||
}
|
||||
else {
|
||||
$log.debug('Status changed to: ' + data.status);
|
||||
stat = GetSyncStatusMsg({
|
||||
status: data.status,
|
||||
has_inventory_sources: group.has_inventory_sources,
|
||||
source: group.source
|
||||
});
|
||||
$log.debug('changing tooltip to: ' + stat.tooltip);
|
||||
group.status = data.status;
|
||||
group.status_class = stat['class'];
|
||||
group.status_tooltip = stat.tooltip;
|
||||
group.launch_tooltip = stat.launch_tip;
|
||||
group.launch_class = stat.launch_class;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.createGroup = function () {
|
||||
GroupsEdit({
|
||||
scope: $scope,
|
||||
@ -845,10 +847,10 @@ function InventoriesEdit($scope, $location, $routeParams, $compile, $log, Genera
|
||||
|
||||
}
|
||||
|
||||
InventoriesEdit.$inject = ['$scope', '$location', '$routeParams', '$compile', '$log', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts',
|
||||
InventoriesEdit.$inject = ['$scope', '$location', '$routeParams', '$compile', '$log', '$rootScope', 'GenerateList', 'ClearScope', 'InventoryGroups', 'InventoryHosts',
|
||||
'BuildTree', 'Wait', 'GetSyncStatusMsg', 'InjectHosts', 'HostsReload', 'GroupsEdit', 'GroupsDelete', 'Breadcrumbs',
|
||||
'LoadBreadCrumbs', 'Empty', 'Rest', 'ProcessErrors', 'InventoryUpdate', 'Alert', 'ToggleChildren', 'ViewUpdateStatus', 'GroupsCancelUpdate',
|
||||
'Find', 'EditInventoryProperties', 'HostsEdit', 'HostsDelete', 'ToggleHostEnabled', 'CopyMoveGroup', 'CopyMoveHost',
|
||||
'Stream', 'GetBasePath', 'ShowJobSummary', 'ApplyEllipsis', 'WatchInventoryWindowResize', 'HelpDialog', 'InventoryGroupsHelp', 'Store',
|
||||
'ViewJob', 'Socket'
|
||||
'ViewJob'
|
||||
];
|
||||
|
||||
@ -12,53 +12,98 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('ChildrenHelper', ['RestServices', 'Utilities'])
|
||||
.factory('ToggleChildren', [ function () {
|
||||
.factory('ToggleChildren', ['$location', 'Store', function ($location, Store) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
list = params.list,
|
||||
id = params.id,
|
||||
set = scope[list.name],
|
||||
i, clicked, found = false;
|
||||
clicked,
|
||||
//base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
path = $location.path(),
|
||||
local_child_store;
|
||||
|
||||
function expand(node) {
|
||||
var i;
|
||||
set[node].ngicon = 'fa fa-minus-square-o node-toggle';
|
||||
for (i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent === set[node].id) {
|
||||
set[i].show = true;
|
||||
function updateExpand(key, expand) {
|
||||
var found = false;
|
||||
local_child_store.every(function(child, i) {
|
||||
if (child.key === key) {
|
||||
local_child_store[i].expand = expand;
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!found) {
|
||||
local_child_store.push({ key: key, expand: expand });
|
||||
}
|
||||
}
|
||||
|
||||
function updateShow(key, show) {
|
||||
var found = false;
|
||||
local_child_store.every(function(child, i) {
|
||||
if (child.key === key) {
|
||||
local_child_store[i].show = show;
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!found) {
|
||||
local_child_store.push({ key: key, show: show });
|
||||
}
|
||||
}
|
||||
|
||||
function expand(node) {
|
||||
var i, has_children = false;
|
||||
for (i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent === set[node].id) {
|
||||
updateShow(set[i].key, true);
|
||||
set[i].show = true;
|
||||
}
|
||||
}
|
||||
set[node].ngicon = (has_children) ? 'fa fa-minus-square-o node-toggle' : 'fa fa-minus-square-o node-toggle';
|
||||
}
|
||||
|
||||
function collapse(node) {
|
||||
var i;
|
||||
set[node].ngicon = 'fa fa-plus-square-o node-toggle';
|
||||
var i, has_children = false;
|
||||
for (i = node + 1; i < set.length; i++) {
|
||||
if (set[i].parent === set[node].id) {
|
||||
set[i].show = false;
|
||||
has_children = true;
|
||||
updateShow(set[i].key, false);
|
||||
if (set[i].related.children) {
|
||||
collapse(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
set[node].ngicon = (has_children) ? 'fa fa-plus-square-o node-toggle' : 'fa fa-square-o node-toggle';
|
||||
}
|
||||
|
||||
local_child_store = Store(path + '_children');
|
||||
if (!local_child_store) {
|
||||
local_child_store = [];
|
||||
}
|
||||
|
||||
// Scan the array list and find the clicked element
|
||||
for (i = 0; i < set.length && found === false; i++) {
|
||||
if (set[i].id === id) {
|
||||
set.every(function(row, i) {
|
||||
if (row.id === id) {
|
||||
clicked = i;
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Expand or collapse children based on clicked element's icon
|
||||
if (/plus-square-o/.test(set[clicked].ngicon)) {
|
||||
// Expand: lookup and display children
|
||||
expand(clicked);
|
||||
updateExpand(set[clicked].key, true);
|
||||
} else if (/minus-square-o/.test(set[clicked].ngicon)) {
|
||||
collapse(clicked);
|
||||
updateExpand(set[clicked].key, false);
|
||||
}
|
||||
Store(path + '_children', local_child_store);
|
||||
};
|
||||
}
|
||||
]);
|
||||
@ -1064,6 +1064,8 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
if (!error) {
|
||||
// Update the parent view with any changes
|
||||
if (groups_reload) {
|
||||
$log.debug('calling UpdateGroup group_id: ' + group_id + ' name: ' + properties_scope.name + ' description: ' + properties_scope.description +
|
||||
'has_inventory_sources: ' + ((sources_scope.source && sources_scope.source.value) ? 'true' : 'false') + ' source: ' + sources_scope.source.value );
|
||||
UpdateGroup({
|
||||
scope: parent_scope,
|
||||
group_id: group_id,
|
||||
@ -1221,8 +1223,9 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
Rest.post(data)
|
||||
.success(function (data) {
|
||||
group_created = true;
|
||||
group_id = data.id;
|
||||
sources_scope.source_url = data.related.inventory_source;
|
||||
if (properties_scope.variables) {
|
||||
sources_scope.source_url = data.related.inventory_source;
|
||||
modal_scope.$emit('updateVariables', json_data, data.related.variable_data);
|
||||
}
|
||||
else {
|
||||
@ -1414,7 +1417,7 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
var group;
|
||||
if (groups && groups.length > 0) {
|
||||
group = groups.pop();
|
||||
Rest.setUrl(GetBasePath('group') + group.group_id + '/');
|
||||
Rest.setUrl(GetBasePath('groups') + group.group_id + '/');
|
||||
Rest.destroy()
|
||||
.success(function() {
|
||||
scope.$emit('DeleteNextGroup');
|
||||
|
||||
@ -56,6 +56,13 @@ angular.module('InventoryGroupsDefinition', [])
|
||||
awToolTip: "Refresh the page",
|
||||
ngClick: "refreshGroups()"
|
||||
},*/
|
||||
socket: {
|
||||
mode: 'all',
|
||||
iconClass: "{{ 'fa fa-power-off fa-lg socket-' + socketStatus }}",
|
||||
awToolTip: "{{ socketTip }}",
|
||||
dataTipWatch: "socketTip",
|
||||
ngClick: "socketToggle()",
|
||||
},
|
||||
stream: {
|
||||
ngClick: "showGroupActivity()",
|
||||
awToolTip: "View Activity Stream",
|
||||
|
||||
@ -1203,6 +1203,18 @@ input[type="checkbox"].checkbox-no-label {
|
||||
}
|
||||
/* end */
|
||||
|
||||
/* Socket icon */
|
||||
.socket-ok {
|
||||
color: @green;
|
||||
}
|
||||
.socket-error {
|
||||
color: @red;
|
||||
}
|
||||
.socket-connecting {
|
||||
color: @warning
|
||||
}
|
||||
/* end */
|
||||
|
||||
.field-success {
|
||||
color: #5bb75b;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-tz-extensions",
|
||||
"version": "0.3.9",
|
||||
"version": "0.3.10",
|
||||
"main": "js/angular-timezones.js",
|
||||
"ignore": [
|
||||
".bowerrc",
|
||||
@ -34,13 +34,14 @@
|
||||
"Chris Houseknecht"
|
||||
],
|
||||
"license": "MIT",
|
||||
"_release": "0.3.9",
|
||||
"_release": "0.3.10",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "0.3.9",
|
||||
"commit": "dded062e72274e2fc5379bb251c476d152ecc1a1"
|
||||
"tag": "0.3.10",
|
||||
"commit": "244ac659f0a15fe389f4cb1222ecafdc890e39ef"
|
||||
},
|
||||
"_source": "git://github.com/chouseknecht/angular-tz-extensions.git",
|
||||
"_target": "*",
|
||||
"_originalSource": "angular-tz-extensions"
|
||||
"_target": "~0.3.10",
|
||||
"_originalSource": "angular-tz-extensions",
|
||||
"_direct": true
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-tz-extensions",
|
||||
"version": "0.3.9",
|
||||
"version": "0.3.10",
|
||||
"main": "js/angular-timezones.js",
|
||||
"ignore": [
|
||||
".bowerrc",
|
||||
|
||||
@ -91,8 +91,8 @@
|
||||
name: name,
|
||||
abbreviation: reference.getTimezoneAbbreviation(),
|
||||
offset: reference.getTimezoneOffset(),
|
||||
region: name.split('/')[0],
|
||||
locality: name.split('/')[1].replace('_', ' ')
|
||||
region: ( (name) ? name.split('/')[0] : '' ),
|
||||
locality: ( (name) ? name.split('/')[1].replace('_', ' ') : '' )
|
||||
};
|
||||
|
||||
return result;
|
||||
@ -174,6 +174,7 @@
|
||||
}
|
||||
|
||||
name = jstz.determine().name();
|
||||
name = (name === null || name === '' || name === undefined) ? 'America/New_York' : name;
|
||||
now = new Date();
|
||||
return resolve(name, now);
|
||||
},
|
||||
|
||||
@ -1 +1 @@
|
||||
/*! angular-tz-extensions - v0.0.1 - 2014-03-03 */!function(a){var b=a.angular,c=a.timezoneJS,d=a.jstz,e=function(a){var b,c=new Date;for(b in a)c[b]=a[b];return c},f=b.module("Timezones",[]);f.config(function(){c.fromLocalString=function(a,b){var d,f,g=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(a),h=[1,4,5,6,7,10,11];for(d=0;f=h[d];++d)g[f]=+g[f]||0;return g[2]=(+g[2]||1)-1,g[3]=+g[3]||1,e(new c.Date(g[1],g[2],g[3],g[4],g[5],g[6],g[7],b))}}),f.constant("$timezones.definitions.location","/tz/data"),f.run(["$timezones.definitions.location",function(a){c.timezone.zoneFileBasePath=a,c.timezone.init({async:!1})}]),f.factory("$timezones",["$log","$http","$timezones.definitions.location",function(a,f,g){var h=function(a,d){var e,f;if("number"==typeof d&&(d=new Date(d)),!b.isDate(d))throw{name:"DateObjectExpected",message:'Expected a Date object; got "'+d+'".'};return d=new c.Date(d,a),e=d.getTimezone(),f={name:e,abbreviation:d.getTimezoneAbbreviation(),offset:d.getTimezoneOffset(),region:e.split("/")[0],locality:e.split("/")[1].replace("_"," ")}};return{align:function(a,d,f){if(!b.isDate(a))throw{name:"DateObjectExpected",message:'Expected a Date object; got "'+a+'".'};try{if(b.isObject(d)&&d.name)return e(new c.Date(a,d.name));if(b.isString(d))return e(new c.Date(a,d))}catch(g){if(!0===f)return a;throw new Error("The timezone argument must either be an Olson name (e.g., America/New_York), or a timezone object (produced by the resolve function) bearing an Olson name on the name property.")}},resolve:h,getLocal:function(){var a,b;if("undefined"==typeof d||"function"!=typeof d.determine)throw{name:"JSTZLibraryMissing",message:"The jsTimezoneDetect library, available at https://bitbucket.org/pellepim/jstimezonedetect, is required to detect the local timezone."};return a=d.determine().name(),b=new Date,h(a,b)},toUTC:function(a,c){var d,e,f=b.isDate(a)?a:new Date(a);return d=f.getUTCFullYear()+"-"+("00"+(f.getUTCMonth()+1)).substr(-2,2)+"-"+("00"+f.getUTCDate()).substr(-2,2)+"T"+("00"+f.getUTCHours()).substr(-2,2)+":"+("00"+f.getUTCMinutes()).substr(-2,2)+":"+("00"+f.getUTCSeconds()).substr(-2,2)+".000Z",e=this.align(new Date(d),c),new Date(e.getTime()+6e4*e.getTimezoneOffset())},getZoneList:function(b){var c,d=[];localStorage.zones?b.$emit("zonesReady"):f({method:"GET",url:g+"/zone.tab"}).success(function(a){var e,f,g=a.match(/[^\r\n]+/g);for(e=0;e<g.length;e++)/^#/.test(g[e])||(f=g[e].split(/\s+/),d.push(f[2]));for(c=d.sort(),d=[],e=0;e<c.length;e++)d.push({name:c[e]});localStorage.zones=JSON.stringify(d),b.$emit("zonesReady")}).error(function(){a.error("Failed to load "+g+"/zone.tab")})}}}]),f.filter("tzAlign",["$timezones",function(a){return function(c,d){if(!(b.isDate(c)||b.isNumber(c)||b.isString(c))||!b.isString(d)&&!b.isObject(d))return c;var e,f,g=c;if(b.isNumber(c)?g=new Date(c):b.isString(c)&&(f=parseInt(c),b.isNumber(f)||(f=Date.parse(c)),g=new Date(f)),!b.isDate(g)||isNaN(g.getTime()))return c;try{e=a.align(g,d,!0)}catch(h){return c}return e&&e.getTime&&!isNaN(e.getTime())?e:c}}])}(this);
|
||||
/*! angular-tz-extensions - v0.3.10 - 2014-04-23 */!function(a){var b=a.angular,c=a.timezoneJS,d=a.jstz,e=function(a){var b,c=new Date;for(b in a)c[b]=a[b];return c},f=b.module("Timezones",[]);f.config(function(){c.fromLocalString=function(a,b){var d,f,g=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(a),h=[1,4,5,6,7,10,11];for(d=0;f=h[d];++d)g[f]=+g[f]||0;return g[2]=(+g[2]||1)-1,g[3]=+g[3]||1,e(new c.Date(g[1],g[2],g[3],g[4],g[5],g[6],g[7],b))}}),f.constant("$timezones.definitions.location","/tz/data"),f.run(["$timezones.definitions.location",function(a){c.timezone.zoneFileBasePath=a,c.timezone.init({async:!1})}]),f.factory("$timezones",["$log","$http","$timezones.definitions.location",function(a,f,g){var h=function(a,d){var e,f;if("number"==typeof d&&(d=new Date(d)),!b.isDate(d))throw{name:"DateObjectExpected",message:'Expected a Date object; got "'+d+'".'};return d=new c.Date(d,a),e=d.getTimezone(),f={name:e,abbreviation:d.getTimezoneAbbreviation(),offset:d.getTimezoneOffset(),region:e?e.split("/")[0]:"",locality:e?e.split("/")[1].replace("_"," "):""}};return{align:function(a,d,f){if(!b.isDate(a))throw{name:"DateObjectExpected",message:'Expected a Date object; got "'+a+'".'};try{if(b.isObject(d)&&d.name)return e(new c.Date(a,d.name));if(b.isString(d))return e(new c.Date(a,d))}catch(g){if(!0===f)return a;throw new Error("The timezone argument must either be an Olson name (e.g., America/New_York), or a timezone object (produced by the resolve function) bearing an Olson name on the name property.")}},resolve:h,getLocal:function(){var a,b;if("undefined"==typeof d||"function"!=typeof d.determine)throw{name:"JSTZLibraryMissing",message:"The jsTimezoneDetect library, available at https://bitbucket.org/pellepim/jstimezonedetect, is required to detect the local timezone."};return a=d.determine().name(),a=null===a||""===a||void 0===a?"America/New_York":a,b=new Date,h(a,b)},toUTC:function(a,c){var d,e,f=b.isDate(a)?a:new Date(a);return d=f.getUTCFullYear()+"-"+("00"+(f.getUTCMonth()+1)).substr(-2,2)+"-"+("00"+f.getUTCDate()).substr(-2,2)+"T"+("00"+f.getUTCHours()).substr(-2,2)+":"+("00"+f.getUTCMinutes()).substr(-2,2)+":"+("00"+f.getUTCSeconds()).substr(-2,2)+".000Z",e=this.align(new Date(d),c),new Date(e.getTime()+6e4*e.getTimezoneOffset())},getZoneList:function(b){var c,d=[];localStorage.zones?b.$emit("zonesReady"):f({method:"GET",url:g+"/zone.tab"}).success(function(a){var e,f,g=a.match(/[^\r\n]+/g);for(e=0;e<g.length;e++)/^#/.test(g[e])||(f=g[e].split(/\s+/),d.push(f[2]));for(c=d.sort(),d=[],e=0;e<c.length;e++)d.push({name:c[e]});localStorage.zones=JSON.stringify(d),b.$emit("zonesReady")}).error(function(){a.error("Failed to load "+g+"/zone.tab")})}}}]),f.filter("tzAlign",["$timezones",function(a){return function(c,d){if(!(b.isDate(c)||b.isNumber(c)||b.isString(c))||!b.isString(d)&&!b.isObject(d))return c;var e,f,g=c;if(b.isNumber(c)?g=new Date(c):b.isString(c)&&(f=parseInt(c),b.isNumber(f)||(f=Date.parse(c)),g=new Date(f)),!b.isDate(g)||isNaN(g.getTime()))return c;try{e=a.align(g,d,!0)}catch(h){return c}return e&&e.getTime&&!isNaN(e.getTime())?e:c}}])}(this);
|
||||
@ -33,8 +33,8 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
}
|
||||
])
|
||||
|
||||
.factory('BuildTree', ['Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg',
|
||||
function (Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg) {
|
||||
.factory('BuildTree', ['$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'SortNodes', 'Wait', 'GetSyncStatusMsg', 'GetHostsStatusMsg', 'Store',
|
||||
function ($location, Rest, GetBasePath, ProcessErrors, SortNodes, Wait, GetSyncStatusMsg, GetHostsStatusMsg, Store) {
|
||||
return function (params) {
|
||||
|
||||
var inventory_id = params.inventory_id,
|
||||
@ -43,7 +43,9 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
emit = params.emit,
|
||||
new_group_id = params.new_group_id,
|
||||
groups = [],
|
||||
id = 1;
|
||||
id = 1,
|
||||
local_child_store,
|
||||
path = $location.path();
|
||||
|
||||
function buildAllHosts(tree_data) {
|
||||
// Start our tree object with All Hosts
|
||||
@ -74,10 +76,35 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
groups.push(all_hosts);
|
||||
}
|
||||
|
||||
function getExpandState(key) {
|
||||
var result = true;
|
||||
local_child_store.every(function(child) {
|
||||
if (child.key === key) {
|
||||
result = child.expand;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getShowState(key) {
|
||||
var result = true;
|
||||
local_child_store.every(function(child) {
|
||||
if (child.key === key) {
|
||||
result = (child.show !== undefined) ? child.show : true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildGroups(tree_data, parent, level) {
|
||||
|
||||
var children, stat, hosts_status, group,
|
||||
sorted = SortNodes(tree_data);
|
||||
sorted = SortNodes(tree_data),
|
||||
expand, show;
|
||||
|
||||
sorted.forEach( function(row, i) {
|
||||
id++;
|
||||
@ -100,6 +127,9 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
children.push(sorted[i].children[j].id);
|
||||
});
|
||||
|
||||
expand = (sorted[i].children.length > 0) ? getExpandState(sorted[i].id) : false;
|
||||
show = getShowState(sorted[i].id);
|
||||
|
||||
group = {
|
||||
name: sorted[i].name,
|
||||
has_active_failures: sorted[i].has_active_failures,
|
||||
@ -112,10 +142,11 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
has_inventory_sources: sorted[i].has_inventory_sources,
|
||||
id: id,
|
||||
source: sorted[i].summary_fields.inventory_source.source,
|
||||
key: sorted[i].id,
|
||||
group_id: sorted[i].id,
|
||||
event_level: level,
|
||||
children: children,
|
||||
ngicon: (sorted[i].children.length > 0) ? 'fa fa-minus-square-o node-toggle' : 'fa fa-square-o node-no-toggle',
|
||||
show: show,
|
||||
related: sorted[i].related,
|
||||
status: sorted[i].summary_fields.inventory_source.status,
|
||||
status_class: stat['class'],
|
||||
@ -127,16 +158,37 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
hosts_status_class: hosts_status['class'],
|
||||
inventory_id: inventory_id,
|
||||
selected_class: '',
|
||||
show: true,
|
||||
isDraggable: true,
|
||||
isDroppable: true
|
||||
};
|
||||
groups.push(group);
|
||||
if (sorted[i].children.length > 0) {
|
||||
if (expand) {
|
||||
group.ngicon = 'fa fa-minus-square-o node-toggle';
|
||||
}
|
||||
else {
|
||||
group.ngicon = 'fa fa-plus-square-o node-toggle';
|
||||
}
|
||||
}
|
||||
else {
|
||||
group.ngicon = 'fa fa-square-o node-no-toggle';
|
||||
}
|
||||
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_group_id = group.group_id;
|
||||
}
|
||||
groups.push(group);
|
||||
if (sorted[i].children.length > 0) {
|
||||
buildGroups(sorted[i].children, id, level + 1);
|
||||
}
|
||||
@ -185,7 +237,10 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
local_child_store = Store(path + '_children');
|
||||
if (!local_child_store) {
|
||||
local_child_store = [];
|
||||
}
|
||||
loadTreeData();
|
||||
};
|
||||
}
|
||||
@ -222,8 +277,8 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
|
||||
// Update date sync status links/icons
|
||||
stat = GetSyncStatusMsg({
|
||||
status: scope.groups[i].status,
|
||||
has_inventory_sources: scope.groups[i].has_inventory_sources,
|
||||
source: scope.groups[i].source
|
||||
has_inventory_sources: properties.has_inventory_sources,
|
||||
source: properties.source
|
||||
});
|
||||
scope.groups[i].status_class = stat['class'];
|
||||
scope.groups[i].status_tooltip = stat.tooltip;
|
||||
|
||||
@ -29,9 +29,10 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
$rootScope.sessionTimer.expireSession();
|
||||
$location.url('/login');
|
||||
}
|
||||
else {
|
||||
Alert("Socket Error", "Attempt to refresh page failed with: " + reason, "alert-danger");
|
||||
// should we do something more here?
|
||||
else if (scope.socketStatus === 'error') {
|
||||
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.",
|
||||
"alert-danger");
|
||||
}
|
||||
});
|
||||
|
||||
@ -49,53 +50,75 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
self.socket = io.connect(url, { headers:
|
||||
{
|
||||
'Authorization': 'Token ' + token,
|
||||
"X-Auth-Token": 'Token ' + token
|
||||
'X-Auth-Token': 'Token ' + token
|
||||
},
|
||||
'connect timeout': 3000,
|
||||
'try multiple transports': false,
|
||||
'max reconneciton attemps': 3,
|
||||
'reconnection limit': 3000,
|
||||
|
||||
});
|
||||
self.socket.on('connection', function() {
|
||||
$log.debug('Socket connecting...');
|
||||
self.scope.socket_status = 'connecting';
|
||||
self.scope.$apply(function () {
|
||||
self.scope.socketStatus = 'connecting';
|
||||
self.scope.socketTip = 'Connecting. Click to cancel.';
|
||||
});
|
||||
});
|
||||
self.socket.on('connect', function() {
|
||||
$log.debug('Socket connection established');
|
||||
self.scope.socket_status = 'ok';
|
||||
self.scope.$apply(function () {
|
||||
self.scope.socketStatus = 'ok';
|
||||
self.scope.socketTip = 'Connected. Click to close.';
|
||||
});
|
||||
});
|
||||
self.socket.on('connect_failed', function(reason) {
|
||||
var r = reason || 'connection refused by host';
|
||||
$log.error('Socket connection failed: ' + r);
|
||||
self.scope.socket_status = 'error';
|
||||
self.scope.socket_reason = r;
|
||||
self.scope.$emit('SocketErrorEncountered', 'Connection failed: ' + r);
|
||||
self.scope.$apply(function () {
|
||||
self.scope.socketStatus = 'error';
|
||||
self.scope.socketTip = 'Connection failed. Click to retry.';
|
||||
self.scope.$emit('SocketErrorEncountered');
|
||||
});
|
||||
|
||||
});
|
||||
self.socket.on('diconnect', function() {
|
||||
$log.debug('Socket disconnected');
|
||||
self.scope.socket_status = 'disconnected';
|
||||
self.scope.$apply(function() {
|
||||
self.socketStatus = 'error';
|
||||
self.socketTip = 'Disconnected. Click to connect.';
|
||||
self.scope.$emit('SocketErrorEncountered');
|
||||
});
|
||||
});
|
||||
self.socket.on('error', function(reason) {
|
||||
var r = reason || 'connection refused by host';
|
||||
$log.error('Socket error encountered: ' + r);
|
||||
self.scope.socket_status = 'error';
|
||||
self.scope.socket_reason = r;
|
||||
self.scope.$emit('SocketErrorEncountered', r);
|
||||
$log.debug('Socket error: ' + r);
|
||||
self.scope.$apply(function() {
|
||||
self.scope.socketStatus = 'error';
|
||||
self.scope.socketTip = 'Connection error encountered. Click to retry.';
|
||||
self.scope.$emit('SocketErrorEncountered');
|
||||
});
|
||||
});
|
||||
self.socket.on('reconnecting', function() {
|
||||
$log.debug('Socket attempting reconnect...');
|
||||
self.scope.socket_status = 'connecting';
|
||||
self.scope.$apply(function() {
|
||||
self.scope.socketStatus = 'connecting';
|
||||
self.scope.socketTip = 'Connecting. Click to cancel.';
|
||||
});
|
||||
});
|
||||
self.socket.on('reconnect', function() {
|
||||
$log.debug('Socket reconnected');
|
||||
self.scope.socket_status = 'ok';
|
||||
self.scope.$apply(function() {
|
||||
self.scope.socketStatus = 'ok';
|
||||
self.scope.socketTip = 'Connected. Click to close.';
|
||||
});
|
||||
});
|
||||
self.socket.on('reconnect_failed', function(reason) {
|
||||
$log.error('Socket reconnect failed: ' + reason);
|
||||
self.scope.socket_status = 'error';
|
||||
self.scope.socket_reason = reason;
|
||||
self.scope.$emit('SocketErrorEncountered', 'Connection failed: ' + reason);
|
||||
self.scope.$apply(function() {
|
||||
self.scope.socketStatus = 'error';
|
||||
self.scope.socketTip = 'Connection failed. Click to retry.';
|
||||
self.scope.$emit('SocketErrorEncountered');
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
@ -103,6 +126,26 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
self.scope.$emit('SocketErrorEncountered', 'Session expired');
|
||||
}
|
||||
},
|
||||
checkStatus: function() {
|
||||
// Check connection status
|
||||
var self = this;
|
||||
if (self.socket.socket.connected) {
|
||||
$log.debug('Socket connected');
|
||||
self.scope.socketStatus = 'ok';
|
||||
self.scope.socketTip = 'Connected. Click to close.';
|
||||
}
|
||||
else if (self.socket.socket.connecting || self.socket.socket.reconnecting) {
|
||||
$log.debug('Socket connecting...');
|
||||
self.scope.socketStatus = 'connecting';
|
||||
self.scope.socketTip = 'Connecting. Click to cancel.';
|
||||
}
|
||||
else {
|
||||
$log.debug('Socket error: connection refused');
|
||||
self.scope.socketStatus = 'error';
|
||||
self.scope.socketTip = 'Connection failed. Click to retry';
|
||||
}
|
||||
return self.scope.socketStatus;
|
||||
},
|
||||
on: function (eventName, callback) {
|
||||
var self = this;
|
||||
self.socket.on(eventName, function () {
|
||||
|
||||
@ -117,6 +117,9 @@ angular.module('GeneratorHelpers', [])
|
||||
case 'stream':
|
||||
icon = 'fa-clock-o';
|
||||
break;
|
||||
case 'socket':
|
||||
icon = 'fa-power-off';
|
||||
break;
|
||||
case 'refresh':
|
||||
icon = 'fa-refresh';
|
||||
break;
|
||||
@ -191,6 +194,7 @@ angular.module('GeneratorHelpers', [])
|
||||
html += (btn.ngHide) ? Attr(btn, 'ngHide') : "";
|
||||
html += (btn.awToolTip) ? Attr(btn, 'awToolTip') : "";
|
||||
html += (btn.awToolTip && btn.dataPlacement === undefined) ? "data-placement=\"top\" " : "";
|
||||
html += (btn.dataTipWatch) ? "data-tip-watch=\"" + btn.dataTipWatch + "\" " : "";
|
||||
html += (btn.awPopOver) ? "aw-pop-over=\"" +
|
||||
btn.awPopOver.replace(/[\'\"]/g, '"') + "\" " : "";
|
||||
html += (btn.dataPlacement) ? Attr(btn, 'dataPlacement') : "";
|
||||
@ -204,10 +208,15 @@ angular.module('GeneratorHelpers', [])
|
||||
html += " >";
|
||||
html += (btn.img) ? "<img src=\"" + $basePath + "img/" + btn.img + "\" style=\"width: 12px; height: 12px;\" >" : "";
|
||||
|
||||
html += SelectIcon({
|
||||
action: action,
|
||||
size: btn.iconSize
|
||||
});
|
||||
if (btn.iconClass) {
|
||||
html += "<i class=\"" + btn.iconClass + "\"></i>";
|
||||
}
|
||||
else {
|
||||
html += SelectIcon({
|
||||
action: action,
|
||||
size: btn.iconSize
|
||||
});
|
||||
}
|
||||
|
||||
html += (btn.label) ? " " + btn.label : "";
|
||||
html += "</button> ";
|
||||
|
||||
@ -395,7 +395,8 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
|
||||
html += (fAction.dataTitle) ? Attr(fAction, 'dataTitle') : "";
|
||||
for (itm in fAction) {
|
||||
if (itm !== 'ngHref' && itm !== 'href' && itm !== 'label' && itm !== 'icon' && itm !== 'class' &&
|
||||
itm !== 'iconClass' && itm !== "dataPlacement" && itm !== "awPopOver" && itm !== "dataTitle") {
|
||||
itm !== 'iconClass' && itm !== "dataPlacement" && itm !== "awPopOver" &&
|
||||
itm !== "dataTitle") {
|
||||
html += Attr(fAction, itm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="groupsCount == 0 && hostsCount == 0">
|
||||
<div class=\"alert alert-info">Delete group <em>{{ group_name }}</em>?</div>
|
||||
<div class="alert alert-info">Delete group <em>{{ group_name }}</em>?</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -21,7 +21,8 @@
|
||||
"less.js": "~1.6.3",
|
||||
"select2": "~3.4.5",
|
||||
"sizzle": "1.10.16",
|
||||
"d3js": "*"
|
||||
"d3js": "*",
|
||||
"angular-tz-extensions": "~0.3.10"
|
||||
},
|
||||
"resolutions": {
|
||||
"angular": "1.2.15-build.2398+sha.4bab3d8"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user