Inventory page, group status now working.

This commit is contained in:
Chris Houseknecht 2014-04-04 03:34:18 -04:00
parent 748e82cc8a
commit 5a6bbfee8e
9 changed files with 184 additions and 85 deletions

View File

@ -10,9 +10,9 @@
'use strict';
function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, InventoryList, GenerateList,
function InventoriesList($scope, $rootScope, $location, $log, $routeParams, $compile, $filter, Rest, Alert, InventoryList, GenerateList,
LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, Wait, Stream,
EditInventoryProperties, Find) {
EditInventoryProperties, Find, Empty, LogViewer) {
//ClearScope();
@ -22,7 +22,7 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
paths = $location.path().replace(/^\//, '').split('/'),
mode = (paths[0] === 'inventories') ? 'edit' : 'select';
view.inject(InventoryList, { mode: mode, $scope: $scope });
view.inject(InventoryList, { mode: mode, scope: $scope });
$rootScope.flashMessage = null;
SearchInit({
@ -82,30 +82,6 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
LoadBreadCrumbs();
if ($scope.removeBuildPopover) {
$scope.removeBuildPopover();
}
$scope.removeBuildPopover = $scope.$on('BuildPopover', function(e, data) {
var inventory, html = '';
if (data.count) {
inventory = Find({ list: $scope.inventories, key: 'id', val: data.results[0].inventory });
html += "<table class=\"table table-condensed flyout\" style=\"width: 100%\">" +
"<thead>" +
"<tr><th>Group</th><th>Source</th><th>Last Run</th><th>Status</th></tr>" +
"</thead>" +
"<tbody>";
data.results.forEach(function(row) {
html += "<tr><td>" + row.summary_fields.group.name + "</td>" +
"<td>" + row.source + "</td>" +
"<td>" + row.last_update + "</td>" +
"<td><i class=\"fa icon-job-" + row.status + "</i></td></tr>";
});
html += "</tbody></table>\n";
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
inventory.syncPopOver = "bob was here!"; //html;
}
});
if ($scope.removePostRefresh) {
$scope.removePostRefresh();
}
@ -141,14 +117,6 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
$scope.inventories[idx].hostsStatus = 'successful';
$scope.inventories[idx].hostsTip = 'No hosts with failures. Click for details.';
}
if (inventory.has_inventory_sources) {
Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
Rest.get()
.success( function(data) {
$scope.$emit('BuildPopover', data);
});
}
});
});
@ -160,6 +128,92 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
$scope.search(list.iterator);
});
if ($scope.removeGroupSummaryReady) {
$scope.removeGroupSummaryReady();
}
$scope.removeGroupSummaryReady = $scope.$on('GroupSummaryReady', function(e, event, inventory, data) {
var j, elem, html, title, row;
function ellipsis(a) {
if (a.length > 20) {
return a.substr(0,20) + '...';
}
return a;
}
if (data.count) {
html = "<table class=\"table table-condensed flyout\" style=\"width: 100%\">\n";
html += "<thead>\n";
html += "<tr>\n";
html += "<th>Status</th>\n";
html += "<th>Group</th>\n";
html += "<th>Last Sync</th>\n";
html += "</tr>\n";
html += "</thead>\n";
html += "<tbody>\n";
for (j=0; j < data.results.length; j++) {
row = data.results[j];
html += "<tr>";
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\" aw-tool-tip=\"Click to view details\" aw-tip-placement=\"top\"><i class=\"fa icon-job-" + row.status + "\"></i></a></td>";
html += "<td><a href=\"\" ng-click=\"viewJob('" + row.related.last_update + "')\" aw-tool-tip=\"Click to view details\" aw-tip-placement=\"top\">" + ellipsis(row.summary_fields.group.name) + "</a></td>";
html += "<td>" + $filter('date')(row.last_updated,'MM/dd HH:mm:ss') + "</td>";
html += "</tr>\n";
}
html += "</tbody>\n";
html += "</table>\n";
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
title = "Sync Status";
elem = $(event.target).parent();
try {
elem.tooltip('hide');
elem.popover('destroy');
}
catch(err) {
//ignore
}
elem.attr({ "aw-pop-over": html, "data-title": title, "data-placement": "right" });
Wait('stop');
$compile(elem)($scope);
elem.on('shown.bs.popover', function() {
$('.popover').each(function() {
$compile($(this))($scope); //make nested directives work!
});
$('.popover-content, .popover-title').click(function() {
elem.popover('hide');
});
});
elem.popover('show');
}
});
$scope.showGroupSummary = function(event, id) {
var inventory;
if (!Empty(id)) {
inventory = Find({ list: $scope.inventories, key: 'id', val: id });
if (inventory.syncStatus !== 'na') {
Wait('start');
Rest.setUrl(inventory.related.inventory_sources + '?or__source=ec2&or__source=rax&order_by=-last_job_run&page_size=5');
Rest.get()
.success(function(data) {
$scope.$emit('GroupSummaryReady', event, inventory, data);
})
.error(function(data, status) {
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + inventory.related.inventory_sources + ' failed. GET returned status: ' + status
});
});
}
}
};
$scope.viewJob = function(url) {
LogViewer({
scope: $scope,
url: url
});
};
$scope.showActivity = function () {
Stream({ scope: $scope });
};
@ -190,7 +244,6 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
$scope.search(list.iterator);
})
.error(function (data, status) {
Wait('stop');
ProcessErrors( $scope, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status
});
@ -199,7 +252,7 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
Prompt({
hdr: 'Delete',
body: '<div class=\"alert alert-info\">Are you sure you want to delete ' + name + '?</div>',
body: '<div class=\"alert alert-info\">Delete inventory ' + name + '?</div>',
action: action
});
};
@ -223,9 +276,9 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
};
}
InventoriesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'InventoryList', 'GenerateList',
InventoriesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', '$compile', '$filter', 'Rest', 'Alert', 'InventoryList', 'GenerateList',
'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', 'ProcessErrors',
'GetBasePath', 'Wait', 'Stream', 'EditInventoryProperties', 'Find'
'GetBasePath', 'Wait', 'Stream', 'EditInventoryProperties', 'Find', 'Empty', 'LogViewer'
];
@ -340,7 +393,7 @@ function InventoriesEdit($scope, $location, $routeParams, $compile, GenerateList
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) {
HelpDialog, InventoryGroupsHelp, Store, ViewJob) {
ClearScope();
@ -665,6 +718,10 @@ function InventoriesEdit($scope, $location, $routeParams, $compile, GenerateList
HelpDialog(opts);
};
$scope.viewJob = function(id) {
ViewJob({ scope: $scope, id: id });
};
//Load tree data for the first time
BuildTree({
scope: $scope,
@ -678,5 +735,6 @@ InventoriesEdit.$inject = ['$scope', '$location', '$routeParams', '$compile', 'G
'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'
'Stream', 'GetBasePath', 'ShowJobSummary', 'ApplyEllipsis', 'WatchInventoryWindowResize', 'HelpDialog', 'InventoryGroupsHelp', 'Store',
'ViewJob'
];

View File

@ -414,7 +414,13 @@ ToggleSchedule, DeleteSchedule, GetBasePath, SchedulesListInit) {
schedule_scope.search(list.iterator);
});
schedule_scope.toggleSchedule = function(id) {
schedule_scope.toggleSchedule = function(event, id) {
try {
$(event.target).tooltip('hide');
}
catch(e) {
// ignore
}
ToggleSchedule({
scope: schedule_scope,
id: id,

View File

@ -14,7 +14,7 @@
angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'HostListDefinition',
'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'HostsHelper',
'InventoryHelper', 'RelatedSearchHelper', 'InventoryFormDefinition', 'SelectionHelper',
'HostGroupsFormDefinition', 'VariablesHelper', 'ModalDialog'
'HostGroupsFormDefinition', 'VariablesHelper', 'ModalDialog', 'LogViewerHelper'
])
.factory('SetEnabledMsg', [ function() {
@ -68,17 +68,24 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
}
return a;
}
function noRecentJobs() {
title = 'No job data';
html = "<p>No recent job data available for this host.</p>\n" +
"<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
}
function setMsg(host) {
var j, job, jobs;
if (host.has_active_failures === true || (host.has_active_failures === false && host.last_job !== null)) {
if (host.has_active_failures === true) {
host.badgeToolTip = 'Most recent job failed. Click to view jobs.';
host.active_failures = 'failed';
host.active_failures = 'error';
}
else {
host.badgeToolTip = "Most recent job successful. Click to view jobs.";
host.active_failures = 'success';
host.active_failures = 'successful';
}
if (host.summary_fields.recent_jobs.length > 0) {
// build html table of job status info
@ -101,7 +108,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
for (j=0; j < jobs.length; j++) {
job = jobs[j];
html += "<tr>\n";
html += "<td><a href=\"/#/jobs/" + job.id + "\">" + job.id + "</a></td>\n";
html += "<td><a href=\"\" ng-click=\"viewJob(" + job.id + ")\">" + job.id + "</a></td>\n";
html += "<td class=\"text-center\"><a ng-click=\"showJobSummary(" + job.id + ")\" " +
"aw-tool-tip=\"" + job.status.charAt(0).toUpperCase() + job.status.slice(1) +
". Click for details\" data-placement=\"top\"><i class=\"fa icon-job-" +
@ -116,15 +123,13 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
}
else {
title = 'No job data';
html = '<p>No recent job data available for this host.</p>';
html += "<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>\n";
noRecentJobs();
}
}
else if (host.has_active_failures === false && host.last_job === null) {
host.has_active_failures = 'none';
host.badgeToolTip = "No job data available.";
host.active_failures = 'n/a';
host.active_failures = 'none';
noRecentJobs();
}
host.job_status_html = html;
host.job_status_title = title;
@ -145,7 +150,18 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
};
}])
.factory('ViewJob', ['LogViewer', 'GetBasePath', function(LogViewer, GetBasePath) {
return function(params) {
var scope = params.scope,
id = params.id;
LogViewer({
scope: scope,
url: GetBasePath('jobs') + id + '/'
});
};
}])
.factory('HostsReload', [ '$routeParams', 'Empty', 'InventoryHosts', 'GetBasePath', 'SearchInit', 'PaginateInit', 'Wait',
'SetHostStatus', 'SetStatus', 'ApplyEllipsis',
function($routeParams, Empty, InventoryHosts, GetBasePath, SearchInit, PaginateInit, Wait, SetHostStatus, SetStatus,
@ -252,9 +268,8 @@ function(GetBasePath, Rest, Wait, ProcessErrors, Alert, Find, SetEnabledMsg) {
});
}
else {
Alert('Action Not Allowed', 'This host is part of a cloud inventory. It can only be disabled in the cloud.' +
' After disabling it, run an inventory sync to see the new status reflected here.',
'alert-info');
Alert('Action Not Allowed', 'This host is managed by an external cloud source. Disable it at the external source, ' +
'and then run an inventory sync to update Tower with the new status.', 'alert-info');
}
};
}])

View File

@ -33,6 +33,25 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
scope.removeJobReady = scope.$on('JobReady', function(e, data) {
var key, resizeText, elem;
$('#status-form-container').empty();
$('#options-form-container').empty();
$('#stdout-form-container').empty();
$('#traceback-form-container').empty();
$('#variables-container').empty();
$('#source-container').empty();
$('#logview-tabs li:eq(1)').hide();
$('#logview-tabs li:eq(2)').hide();
$('#logview-tabs li:eq(4)').hide();
$('#logview-tabs li:eq(5)').hide();
// Make sure subsequenct scope references don't bubble up to the parent
for (key in LogViewerStatusForm.fields) {
scope[key] = '';
}
for (key in LogViewerOptionsForm.fields) {
scope[key] = '';
}
for (key in data) {
scope[key] = data[key];
}
@ -47,10 +66,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
val: data.result_stdout
});
}
else {
$('#logview-tabs li:eq(1)').hide();
}
if (data.result_traceback) {
$('#logview-tabs li:eq(2)').show();
AddPreFormattedText({
@ -58,10 +74,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
val: data.result_traceback
});
}
else {
$('#logview-tabs li:eq(2)').hide();
}
/*if (data.job_env) {
EnvTable({
id: 'env-form-container',
@ -77,10 +90,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
val: ParseVariableString(data.extra_vars)
});
}
else {
$('#logview-tabs li:eq(4)').hide();
}
if (data.source_vars) {
$('#logview-tabs li:eq(5)').show();
AddTextarea({
@ -89,10 +99,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
val: ParseVariableString(data.source_vars)
});
}
else {
$('#logview-tabs li:eq(5)').hide();
}
if (!Empty(scope.source)) {
if (scope.removeChoicesReady) {
scope.removeChoicesReady();
@ -179,6 +186,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator',
onResizeStop: resizeText,
onOpen: function() {
$('#logview-tabs a:first').tab('show');
$('#dialog-ok-button').focus();
resizeText();
}
});

View File

@ -342,12 +342,12 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe
Rest.setUrl(url);
Rest.get()
.success(function(data) {
scope.$emit('ScheduleFound', data);
})
.error(function(data,status){
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to retrieve schedule ' + id + ' GET returned: ' + status });
});
scope.$emit('ScheduleFound', data);
})
.error(function(data,status){
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
msg: 'Failed to retrieve schedule ' + id + ' GET returned: ' + status });
});
};
}])
@ -390,7 +390,12 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe
scope.$emit(callback, id);
})
.error(function (data, status) {
$('#prompt-modal').modal('hide');
try {
$('#prompt-modal').modal('hide');
}
catch(e) {
// ignore
}
ProcessErrors(scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url +
' failed. DELETE returned: ' + status });
});

View File

@ -32,14 +32,12 @@ angular.module('InventoriesListDefinition', [])
icon: "{{ 'icon-cloud-' + inventory.syncStatus }}",
awToolTip: "{{ inventory.syncTip }}",
awTipPlacement: "top",
awPopOver: "{{ inventory.syncPopOver }}",
dataPlacement: "right"
ngClick: "showGroupSummary($event, inventory.id)"
},{
icon: "{{ 'icon-job-' + inventory.hostsStatus }}",
awToolTip: "{{ inventory.hostsTip }}",
awTipPlacement: "top",
awPopOver: "{{ inventory.hostsPopOver }}",
dataPlacement: "right"
ngClick: "showHostSummary($event, inventory.id)"
}]
},
name: {
@ -106,7 +104,7 @@ angular.module('InventoriesListDefinition', [])
},
"delete": {
label: 'Delete',
ngClick: "deleteInventory(inventory.id, inventory.names)",
ngClick: "deleteInventory(inventory.id, inventory.name)",
awToolTip: 'Delete inventory',
dataPlacement: 'top'
}

View File

@ -63,7 +63,7 @@ angular.module('InventoryHostsDefinition', [])
awToolTip: "{{ host.badgeToolTip }}",
awTipPlacement: 'top',
dataPlacement: 'left',
iconClass: "{{ 'fa icon-failures-' + host.has_active_failures }}",
iconClass: "{{ 'fa icon-job-' + host.active_failures }}",
id: 'active-failutes-action'
},
edit: {

View File

@ -137,6 +137,14 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper'])
}
},
open: function () {
$('.tooltip').each(function () {
// Remove any lingering tooltip <div> elements
$(this).remove();
});
$('.popover').each(function () {
// remove lingering popover <div> elements
$(this).remove();
});
if (onOpen) {
onOpen();
}

View File

@ -1,3 +1,4 @@
<div class="tab-pane" id="inventories">
<div ng-cloak id="htmlTemplate"></div>
<div ng-include="'/static/partials/logviewer.html'"></div>
</div>