Inventory refactor: add job status summary fly-out on host status. Click on a status and a second dialog appears for the specific job. Dialog can be resized and moved- built using jquery and styled to match TB dialog. Fixed home/groups and home/hosts pages to appear more inventory edit page. Home/groups page now allows you to start and inventory sync as well. Fixed tool-tip consistency. Click page forward/back now employs the spinner and should stop overclicking, which was resulting in page numbers < 0.

This commit is contained in:
chris Houseknecht
2014-01-22 04:53:18 -05:00
parent 2213268096
commit 7269c7bd06
62 changed files with 15517 additions and 177 deletions

View File

@@ -51,9 +51,85 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
}
}])
.factory('SetStatus', ['SetEnabledMsg', 'Empty', function(SetEnabledMsg, Empty) {
return function(params) {
var scope = params.scope;
var host = params.host;
var html, title;
function setMsg(host) {
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';
}
else {
host.badgeToolTip = "Most recent job successful. Click to view jobs.";
host.active_failures = 'success';
}
if (host.summary_fields.recent_jobs.length > 0) {
// build html table of job status info
var jobs = host.summary_fields.recent_jobs.sort(
function(a,b) {
// reverse numerical order
return -1 * (a - b);
});
title = "Recent Jobs";
html = "<table class=\"table table-condensed\">\n";
html += "<thead>\n";
html += "<tr>\n";
html += "<th>ID</td>\n";
html += "<th>Status</td>\n";
html += "<th>Name</td>\n";
html += "</tr>\n";
html += "</thead>\n";
html += "<tbody>\n";
for (var j=0; j < jobs.length; j++) {
var job = jobs[j];
html += "<tr>\n";
html += "<td><a href=\"/#/jobs/" + job.id + "\">" + job.id + "</a></td>\n";
html += "<td><a ng-click=\"showJobSummary(" + job.id + ")\"><i class=\"fa icon-job-" + job.status + "\"></i> " + job.status + "</a></td>\n";
html += "<td>" + job.name + "</td>\n";
html += "</tr>\n";
}
html += "</tbody>\n";
html += "</table>\n";
}
else {
title = 'No job data';
html = '<p>No recent job data available for this host.</p>';
}
}
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.job_status_html = html;
host.job_status_title = title;
}
if (!Empty(host)) {
// update single host
setMsg(host);
SetEnabledMsg(host);
}
else {
// update all hosts
for (var i=0; i < scope.hosts.length; i++) {
setMsg(scope.hosts[i]);
SetEnabledMsg(scope.hosts[i]);
}
}
}
}])
.factory('HostsReload', [ '$routeParams', 'Empty', 'InventoryHosts', 'GetBasePath', 'SearchInit', 'PaginateInit', 'Wait', 'SetHostStatus',
function($routeParams, Empty, InventoryHosts, GetBasePath, SearchInit, PaginateInit, Wait, SetHostStatus) {
.factory('HostsReload', [ '$routeParams', 'Empty', 'InventoryHosts', 'GetBasePath', 'SearchInit', 'PaginateInit', 'Wait',
'SetHostStatus', 'SetStatus',
function($routeParams, Empty, InventoryHosts, GetBasePath, SearchInit, PaginateInit, Wait, SetHostStatus, SetStatus) {
return function(params) {
var scope = params.scope;
@@ -74,9 +150,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
for (var i=0; i < scope.hosts.length; i++) {
//Set tooltip for host enabled flag
scope.hosts[i].enabled_flag = scope.hosts[i].enabled;
//SetEnabledMsg(scope.hosts[i]);
SetHostStatus(scope.hosts[i]);
//SetHostStatus(scope.hosts[i]);
}
SetStatus({ scope: scope });
Wait('stop');
scope.$emit('HostReloadComplete');
});
@@ -347,9 +423,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
.factory('HostsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm',
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetEnabledMsg',
'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetStatus',
function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors,
GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetEnabledMsg) {
GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus) {
return function(params) {
var parent_scope = params.scope;
@@ -371,7 +447,6 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
scope.parseType = 'yaml';
ParseTypeChange(scope);
$('#form-modal .btn-none').removeClass('btn-none').addClass('btn-success');
if (scope.hostLoadedRemove) {
scope.hostLoadedRemove();
@@ -441,7 +516,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
host.name = scope.name;
host.enabled = scope.enabled;
host.enabled_flag = scope.enabled;
SetEnabledMsg(host);
SetStatus({ scope: parent_scope, host: host });
// Close modal
Wait('stop');
$('#form-modal').modal('hide');

View File

@@ -423,7 +423,9 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
Wait('stop');
Alert('Update Started', 'Your request to start the inventory sync process was submitted. Monitor progress ' +
'by clicking the <i class="fa fa-refresh fa-lg"></i> button.', 'alert-info');
scope.removeHostReloadComplete();
if (scope.removeHostReloadComplete) {
scope.removeHostReloadComplete();
}
});
if (scope.removeUpdateSubmitted) {
@@ -431,10 +433,14 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
}
scope.removeUpdateSubmitted = scope.$on('UpdateSubmitted', function(e, action) {
if (action == 'started') {
// Cancel the update process
scope.selected_tree_id = tree_id;
scope.selected_group_id = group_id;
scope.refreshGroups();
if (scope.refreshGroups) {
scope.selected_tree_id = tree_id;
scope.selected_group_id = group_id;
scope.refreshGroups();
}
else {
scope.$emit('HostReloadComplete');
}
}
});

View File

@@ -7,7 +7,8 @@
*
*/
angular.module('JobsHelper', [ ])
angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinition'])
.factory('JobStatusToolTip', [ function() {
return function(status) {
var toolTip;
@@ -37,4 +38,97 @@ angular.module('JobsHelper', [ ])
}
return toolTip;
}
}]);
}])
.factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary',
function(Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary) {
return function(params) {
// Display status info in a modal dialog- called from inventory edit page
var job_id = params.job_id;
var generator = GenerateForm;
var form = JobSummary;
// Using jquery dialog for its expandable property
var html = "<div id=\"status-modal-dialog\" title=\"Job " + job_id + "\"><div id=\"form-container\" style=\"width: 100%;\"></div></div>\n";
$('#inventory-modal-container').empty().append(html);
var scope = generator.inject(form, { mode: 'edit', id: 'form-container', breadCrumbs: false, related: false });
// Set modal dimensions based on viewport width
var ww = $(document).width();
var wh = $('body').height();
var x, y, maxrows;
if (ww > 1199) {
// desktop
x = 675;
y = (750 > wh) ? wh - 20 : 750;
maxrows = 20;
}
else if (ww <= 1199 && ww >= 768) {
x = 550;
y = (620 > wh) ? wh - 15 : 620;
maxrows = 15;
}
else {
x = (ww - 20);
y = (500 > wh) ? wh : 500;
maxrows = 10;
}
// Create the modal
$('#status-modal-dialog').dialog({
buttons: { "OK": function() { $( this ).dialog( "close" ); } },
modal: true,
width: x,
height: y,
autoOpen: false,
create: function (e, ui) {
// fix the close button
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({ 'class': 'close' }).text('x');
// fix the OK button
$('.ui-dialog[aria-describedby="status-modal-dialog"]').find('.ui-dialog-buttonset button:first')
.attr({ 'class': 'btn btn-primary' });
},
resizeStop: function(e, ui) {
// for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100%
var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]');
var content = dialog.find('#status-modal-dialog');
content.width( dialog.width() - 28 );
},
close: function(e, ui) {
// Destroy on close
$('#status-modal-dialog').dialog('destroy');
$('#inventory-modal-container').empty();
}
});
function calcRows (content) {
var n = content.match(/\n/g);
var rows = (n) ? n.length : 1;
return (rows > maxrows) ? 20 : rows;
}
Wait('start');
var url = GetBasePath('jobs') + job_id + '/';
Rest.setUrl(url);
Rest.get()
.success( function(data, status, headers, config) {
scope.id = data.id;
scope.name = data.name;
scope.status = data.status;
scope.result_stdout = data.result_stdout;
scope.result_traceback = data.result_traceback;
scope['stdout_rows'] = calcRows(scope['result_stdout']);
scope['traceback_rows'] = calcRows(scope['result_traceback']);
var cDate = new Date(data.created);
scope.created = FormatDate(cDate);
Wait('stop');
$('#status-modal-dialog').dialog('open');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Attempt to load job failed. GET returned status: ' + status });
});
}
}]);

View File

@@ -14,8 +14,8 @@
*
*/
angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies'])
.factory('PaginateInit', [ 'Refresh', '$cookieStore', function(Refresh, $cookieStore) {
angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies', 'Utilities'])
.factory('PaginateInit', [ 'Refresh', '$cookieStore', 'Wait', function(Refresh, $cookieStore, Wait) {
return function(params) {
var scope = params.scope;
@@ -51,6 +51,7 @@ angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies'])
scope.nextSet = function(set, iterator) {
if (scope[iterator + 'NextUrl']) {
scope[iterator + 'Page']++;
Wait('start');
Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'NextUrl'] });
}
};
@@ -58,6 +59,7 @@ angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies'])
scope.prevSet = function(set, iterator) {
if (scope[iterator + 'PrevUrl']) {
scope[iterator + 'Page']--;
Wait('start');
Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'PrevUrl'] });
}
};
@@ -70,11 +72,10 @@ angular.module('PaginateHelper', ['RefreshHelper', 'ngCookies'])
scope[iterator + 'Page'] = 0;
var new_url = url.replace(/\?page_size\=\d+/,'');
console.log('new_url: ' + new_url);
var connect = (/\/$/.test(new_url)) ? '?' : '&';
new_url += (scope[iterator + 'SearchParams']) ? connect + scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + 'PageSize' ] :
connect + 'page_size=' + scope[iterator + 'PageSize' ];
console.log('new_url: ' + new_url);
Wait('start');
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
}
}

View File

@@ -41,7 +41,6 @@ angular.module('RefreshRelatedHelper', ['RestServices', 'Utilities'])
}
})
.error ( function(data, status, headers, config) {
Wait('stop');
//scope[iterator + 'SearchSpin'] = true;
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to retrieve ' + set + '. GET returned status: ' + status });

View File

@@ -41,7 +41,6 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities'])
scope.$emit('PostRefresh');
})
.error ( function(data, status, headers, config) {
Wait('stop');
//scope[iterator + 'SearchSpin'] = false;
scope[iterator + 'HoldInput'] = false;
ProcessErrors(scope, data, status, null,