AC-414 Making red/green bubbles consistent throughout the application. Changes made to Inventory and jobs pages. Tooltip text now dynamic. Improved deep linking, especially on status fields.

This commit is contained in:
chouseknecht 2013-10-07 03:19:30 -04:00
parent 6bf8f9cd98
commit b28fe1254e
25 changed files with 628 additions and 210 deletions

View File

@ -70,7 +70,8 @@ angular.module('ansible', [
'LicenseFormDefinition',
'License',
'HostGroupsFormDefinition',
'ObjectCountWidget'
'ObjectCountWidget',
'JobsHelper'
])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.

View File

@ -43,15 +43,15 @@ function InventoryHosts ($scope, $rootScope, $compile, $location, $log, $routePa
LoadSearchTree({ scope: scope, inventory_id: scope['inventory_id'] });
// Add the selected flag to the hosts set.
if (scope.relatedHostsRemove) {
scope.relatedHostsRemove();
}
scope.relatedHostsRemove = scope.$on('relatedhosts', function() {
scope.toggleAllFlag = false;
for (var i=0; i < scope.hosts.length; i++) {
scope.hosts[i].selected = 0;
}
});
//if (scope.relatedHostsRemove) {
// scope.relatedHostsRemove();
//}
//scope.relatedHostsRemove = scope.$on('relatedhosts', function() {
// scope.toggleAllFlag = false;
// for (var i=0; i < scope.hosts.length; i++) {
// scope.hosts[i].selected = 0;
// }
// });
scope.filterHosts = function() {
HostsReload({ scope: scope, inventory_id: scope['inventory_id'], group_id: scope['group_id'] });

View File

@ -30,65 +30,79 @@ function InventoriesList ($scope, $rootScope, $location, $log, $routeParams, Res
scope.search(list.iterator);
LoadBreadCrumbs();
if (scope.projectsPostRefresh) {
scope.projectsPostRefresh();
}
scope.projectsPostRefresh = scope.$on('PostRefresh', function() {
for (var i=0; i < scope.inventories.length; i++) {
if (scope.inventories[i].hosts_with_active_failures > 0) {
scope.inventories[i].active_failures_params = "/?has_active_failures=true";
}
//if (scope.inventories[i].hosts_with_active_failures < 99) {
// scope.inventories[i].hosts_with_active_failures = ('00' + scope.inventories[i].hosts_with_active_failures).substr(-2);
//}
}
});
scope.addInventory = function() {
$location.path($location.path() + '/add');
}
$location.path($location.path() + '/add');
}
scope.editInventory = function(id) {
$location.path($location.path() + '/' + id);
}
$location.path($location.path() + '/' + id);
}
scope.deleteInventory = function(id, name) {
var action = function() {
var url = defaultUrl + id + '/';
$('#prompt-modal').modal('hide');
Wait('start');
Rest.setUrl(url);
Rest.destroy()
.success( function(data, status, headers, config) {
scope.search(list.iterator);
Wait('stop');
})
.error( function(data, status, headers, config) {
Wait('stop');
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
});
};
var action = function() {
var url = defaultUrl + id + '/';
$('#prompt-modal').modal('hide');
Wait('start');
Rest.setUrl(url);
Rest.destroy()
.success( function(data, status, headers, config) {
scope.search(list.iterator);
Wait('stop');
})
.error( function(data, status, headers, config) {
Wait('stop');
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
});
};
Prompt({ hdr: 'Delete',
body: 'Are you sure you want to delete ' + name + '?',
action: action
});
}
Prompt({ hdr: 'Delete',
body: 'Are you sure you want to delete ' + name + '?',
action: action
});
}
scope.lookupOrganization = function(organization_id) {
Rest.setUrl(GetBasePath('organizations') + organization_id + '/');
Rest.get()
.success( function(data, status, headers, config) {
return data.name;
});
}
scope.lookupOrganization = function(organization_id) {
Rest.setUrl(GetBasePath('organizations') + organization_id + '/');
Rest.get()
.success( function(data, status, headers, config) {
return data.name;
});
}
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
scope.viewJobs = function(id) {
$location.url('/jobs/?inventory__int=' + id);
}
// Failed jobs link. Go to the jobs tabs, find all jobs for the inventory and sort by status
scope.viewJobs = function(id) {
$location.url('/jobs/?inventory__int=' + id);
}
scope.viewFailedJobs = function(id) {
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
}
scope.viewFailedJobs = function(id) {
$location.url('/jobs/?inventory__int=' + id + '&status=failed');
}
scope.editHosts = function(id) {
$location.url('/inventories/' + id + '/hosts');
}
scope.editHosts = function(id) {
$location.url('/inventories/' + id + '/hosts');
}
scope.editGroups = function(id) {
$location.url('/inventories/' + id + '/groups');
}
scope.editGroups = function(id) {
$location.url('/inventories/' + id + '/groups');
}
}
InventoriesList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'InventoryList', 'GenerateList',

View File

@ -131,12 +131,39 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
set[i]['spaces'] = set[i].event_level * 24;
if (scope.jobevents[i].failed) {
scope.jobevents[i].status = 'error';
if (i == set.length - 1) {
scope.jobevents[i].statusBadgeToolTip = "A failure occurred durring one or more playbook tasks.";
}
else if (set[i].event_level < 3) {
scope.jobevents[i].statusBadgeToolTip = "A failure occurred within the children of this event.";
}
else {
scope.jobevents[i].statusBadgeToolTip = "A failure occurred. Click to view details";
}
}
else if (scope.jobevents[i].changed) {
scope.jobevents[i].status = 'changed';
if (i == set.length - 1) {
scope.jobevents[i].statusBadgeToolTip = "A change was completed durring one or more playbook tasks.";
}
else if (set[i].event_level < 3) {
scope.jobevents[i].statusBadgeToolTip = "A change was completed by one or more children of this event.";
}
else {
scope.jobevents[i].statusBadgeToolTip = "A change was completed. Click to view details";
}
}
else {
scope.jobevents[i].status = 'success';
if (i == set.length - 1) {
scope.jobevents[i].statusBadgeToolTip = "All playbook tasks completed successfully.";
}
else if (set[i].event_level < 3) {
scope.jobevents[i].statusBadgeToolTip = "All the children of this event completed successfully.";
}
else {
scope.jobevents[i].statusBadgeToolTip = "No errors occurred. Click to view details";
}
}
cDate = new Date(set[i].created);
set[i].created = FormatDate(cDate);
@ -147,6 +174,8 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
Rest.get()
.success( function(data, status, headers, config) {
scope.job_status = data.status;
scope.job_name = data.summary_fields.job_template.name;
LoadBreadCrumbs({ path: '/jobs/' + scope.job_id, title: scope.job_name });
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
if ($rootScope.timer) {
clearInterval($rootScope.timer);
@ -181,8 +210,6 @@ function JobEventsList ($scope, $rootScope, $location, $log, $routeParams, Rest,
children: children
});
}
LoadBreadCrumbs();
scope.viewJobEvent = function(id) {
EventView({ event_id: id });

View File

@ -12,13 +12,14 @@
function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobHostList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, GetBasePath, Refresh)
ClearScope, ProcessErrors, GetBasePath, Refresh, JobStatusToolTip)
{
ClearScope('htmlTemplate');
var list = JobHostList;
var base = $location.path().replace(/^\//,'').split('/')[0];
var defaultUrl = GetBasePath(base) + $routeParams.id + '/job_host_summaries/';
var inventory_id;
// When viewing all summaries for a particular host, show job ID, otherwise row ID.
if (base == 'hosts') {
list.index = false;
@ -42,46 +43,71 @@ function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams,
scope.host_id = null;
}
if (scope.RemoveSetHostLink) {
scope.RemoveSetHostLink();
}
scope.RemoveSetHostLink = scope.$on('setHostLink', function(e, inventory_id) {
for (var i=0; i < scope.jobhosts.length; i++) {
scope.jobhosts[i].hostLinkTo = '/#/inventories/' + inventory_id + '/hosts/?name=' +
escape(scope.jobhosts[i].summary_fields.host.name);
}
});
// After a refresh, populate any needed summary field values on each row
if (scope.PostRefreshRemove) {
scope.PostRefreshRemove();
}
scope.PostRefershRemove = scope.$on('PostRefresh', function() {
scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
// Set status, tooltips, badget icons, etc.
for( var i=0; i < scope.jobhosts.length; i++) {
scope.jobhosts[i].host_name = scope.jobhosts[i].summary_fields.host.name;
scope.jobhosts[i].status = (scope.jobhosts[i].failed) ? 'error' : 'success';
scope.jobhosts[i].status = (scope.jobhosts[i].failed) ? 'failed' : 'success';
scope.jobhosts[i].statusBadgeToolTip = JobStatusToolTip(scope.jobhosts[i].status) +
" Click to view details.";
scope.jobhosts[i].statusLinkTo = '/#/jobs/' + scope.jobhosts[i].job + '/job_events/?host=' +
escape(scope.jobhosts[i].summary_fields.host.name);
}
if (scope.job_id !== null && scope.job_id !== undefined && scope.job_id !== '') {
// need job_status so we can show/hide refresh button
Rest.setUrl(GetBasePath('jobs') + scope.job_id);
Rest.get()
.success( function(data, status, headers, config) {
scope.job_status = data.status;
scope.$emit('setHostLink', data.inventory);
if (!(data.status == 'pending' || data.status == 'waiting' || data.status == 'running')) {
if ($rootScope.timer) {
clearInterval($rootScope.timer);
}
}
})
.error( function(data, status, headers, config) {
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
{ hdr: 'Error!', msg: 'Failed to get job status for job: ' + scope.job_id + '. GET status: ' + status });
});
}
if (base == 'hosts' && $routeParams['host_name']) {
// Make the host name appear in breadcrumbs
LoadBreadCrumbs({ path: '/hosts/' + scope['host_id'], title: $routeParams['host_name'] });
}
else {
LoadBreadCrumbs();
}
});
SearchInit({ scope: scope, set: 'jobhosts', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
// Called from Inventories tab, host failed events link:
if ($routeParams.host) {
if ($routeParams['host_name']) {
scope[list.iterator + 'SearchField'] = 'host';
scope[list.iterator + 'SearchValue'] = $routeParams.host;
scope[list.iterator + 'SearchValue'] = $routeParams['host_name'];
scope[list.iterator + 'SearchFieldLabel'] = list.fields['host'].label;
}
scope.search(list.iterator);
LoadBreadCrumbs();
scope.showEvents = function(host_name, last_job) {
// When click on !Failed Events link, redirect to latest job/job_events for the host
@ -113,5 +139,5 @@ function JobHostSummaryList ($scope, $rootScope, $location, $log, $routeParams,
JobHostSummaryList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobHostList',
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
'ProcessErrors', 'GetBasePath', 'Refresh'
'ProcessErrors', 'GetBasePath', 'Refresh', 'JobStatusToolTip'
];

View File

@ -27,6 +27,14 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
SearchInit({ scope: scope, set: 'job_templates', list: list, url: defaultUrl });
PaginateInit({ scope: scope, list: list, url: defaultUrl });
// Called from Inventories tab, host failed events link:
if ($routeParams['name']) {
scope[list.iterator + 'SearchField'] = 'name';
scope[list.iterator + 'SearchValue'] = $routeParams['name'];
scope[list.iterator + 'SearchFieldLabel'] = list.fields['name'].label;
}
scope.search(list.iterator);
LoadBreadCrumbs();

View File

@ -12,7 +12,8 @@
function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList,
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh)
ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh,
JobStatusToolTip)
{
ClearScope('htmlTemplate');
var list = JobList;
@ -41,6 +42,13 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest,
scope[list.name][i].created = FormatDate(cDate);
}
}
for (var i=0; i < scope.jobs.length; i++) {
scope.jobs[i].statusBadgeToolTip = JobStatusToolTip(scope.jobs[i].status) +
" Click to view status details.";
scope.jobs[i].statusLinkTo = '/#/jobs/' + scope.jobs[i].id;
}
});
@ -157,14 +165,14 @@ function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest,
JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh'
'ProcessErrors','GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip'
];
function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm,
GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit,
RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList,
ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate)
ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@ -334,7 +342,9 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
}
}
}
scope.statusToolTip = JobStatusToolTip(data.status);
$('form[name="jobs_form"] input[type="text"], form[name="jobs_form"] jobs_form textarea').attr('readonly','readonly');
$('form[name="jobs_form"] select').prop('disabled', 'disabled');
$('form[name="jobs_form"] .lookup-btn').prop('disabled', 'disabled');
@ -503,5 +513,6 @@ function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams,
JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm',
'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit',
'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList',
'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'FormatDate'
'ProjectList', 'LookUpInit', 'PromptPasswords', 'GetBasePath', 'md5Setup', 'FormatDate',
'JobStatusToolTip'
];

View File

@ -18,13 +18,29 @@ angular.module('InventoryHostsFormDefinition', [])
fields: {
name: {
key: true,
label: 'Host Name',
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')",
label: 'Name',
ngClick: "editHost(\{\{ host.id \}\}, '\{\{ host.name \}\}')"
//columnClass: 'col-lg-3'
},
active_failures: {
label: 'Current<br>Job Status?',
ngHref: "\{\{ host.activeFailuresLink \}\}",
awToolTip: "\{\{ host.badgeToolTip \}\}",
dataPlacement: 'bottom',
badgeNgHref: '\{\{ host.activeFailuresLink \}\}',
badgeIcon: "\{\{ 'icon-failures-' + host.has_active_failures \}\}",
badgeToolTip: 'Indicates if host has active failures',
badgePlacement: 'left',
badgeToolTip: "\{\{ host.badgeToolTip \}\}",
badgeTipPlacement: 'bottom',
columnClass: 'col-lg-3'
searchable: false,
nosort: true
},
has_active_failures: {
label: 'Current job failed?',
searchSingleValue: true,
searchType: 'boolean',
searchValue: 'true',
searchOnly: true
},
groups: {
label: 'Groups',
@ -32,7 +48,7 @@ angular.module('InventoryHostsFormDefinition', [])
sourceModel: 'groups',
sourceField: 'name',
nosort: true
}
},
},
actions: {

View File

@ -270,7 +270,7 @@ angular.module('JobFormDefinition', [])
status: {
label: 'Job Status',
type: 'custom',
control: '<div class="job-detail-status job-\{\{ status \}\}"><i class="icon-circle"></i> \{\{ status \}\}</div>',
control: '<div class=\"job-detail-status\"><i class=\"icon-job-\{\{ status \}\}\"></i> \{\{ status \}\}</div>',
readonly: true
},
created: {

View File

@ -27,7 +27,7 @@ angular.module('EventsHelper', ['RestServices', 'Utilities', 'JobEventDataDefini
fields: {
status: {
labelClass: 'job-\{\{ status \}\}',
icon: 'icon-circle',
icon: 'icon-job-\{\{ status \}\}',
type: 'custom',
section: 'Event',
control: '<div class=\"job-event-status job-\{\{ status \}\}\">\{\{ status \}\}</div>'

View File

@ -147,26 +147,35 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
for (var i=0; i < scope.groups.length; i++) {
var last_update = (scope.groups[i].last_updated == null) ? '' : FormatDate(new Date(scope.groups[i].last_updated));
var source = 'Manual';
var stat;
var stat_class;
var stat, stat_class, status_tip;
stat = scope.groups[i].status;
stat_class = stat;
switch (scope.groups[i].status) {
case 'never updated':
stat = 'never';
stat_class = 'never';
status_tip = 'Inventory update has not been performed. Click Update button to start it now.';
break;
case 'none':
stat = 'n/a';
stat_class = 'na';
status_tip = 'Not configured for inventory update.';
break;
case 'failed':
status_tip = 'Inventory update completed with errors. Click to view process output.';
break;
case 'successful':
status_tip = 'Inventory update completed with no errors. Click to view process output.';
break;
case 'updating':
status_tip = 'Inventory update process running now.';
break;
default:
stat = scope.groups[i].status;
stat_class = stat;
}
switch (scope.groups[i].source) {
case 'file':
source = 'File';
source = 'Local Script';
break;
case 'ec2':
source = 'Amazon EC2';
@ -175,10 +184,21 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
source = 'Rackspace';
break;
}
if (scope.groups[i].summary_fields.group.hosts_with_active_failures > 0) {
scope.groups[i].active_failures_params = "/?has_active_failures=true";
}
else {
scope.groups[i].active_failures_params = '';
}
scope.groups[i].hosts_with_active_failures = scope.groups[i].summary_fields.group.hosts_with_active_failures;
scope.groups[i].has_active_failures = scope.groups[i].summary_fields.group.has_active_failures;
scope.groups[i].status = stat;
scope.groups[i].source = source;
scope.groups[i].last_updated = last_update;
scope.groups[i].status_class = stat_class;
scope.groups[i].status_badge_class = stat_class;
scope.groups[i].status_badge_tooltip = status_tip;
}
});
@ -688,6 +708,36 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
});
}
}
// Start the update process
scope.updateGroup = function() {
if (scope[source] == "" || scope.groups[i].source == null) {
Alert('Missing Configuration', 'The group is not configured for updates. You must provide Source settings before running the update ' +
'process.');
}
else if (scope[status] == 'updating') {
Alert('Update in Progress', 'The inventory update process is currently running for this group <em>' +
scope.groups[i].summary_fields.group.name + '</em>. Under the Groupmonitor the status.', 'alert-info');
}
else {
if (scope['source'] == 'Amazon EC2') {
scope['sourceUsernameLabel'] = 'Access Key ID';
scope['sourcePasswordLabel'] = 'Secret Access Key';
scope['sourcePasswordConfirmLabel'] = 'Confirm Secret Access Key';
}
else {
scope['sourceUsernameLabel'] = 'Username';
scope['sourcePasswordLabel'] = 'Password';
scope['sourcePasswordConfirmLabel'] = 'Confirm Password';
}
InventoryUpdate({
scope: scope,
group_id: id,
url: scope.groups[i].related.update,
group_name: scope.groups[i].summary_fields.group.name,
group_source: scope.groups[i].source
});
}
}
// Cancel
scope.formReset = function() {
@ -697,6 +747,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
}
scope.parseType = 'yaml';
}
}
}])

View File

@ -408,8 +408,8 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
}])
.factory('HostsReload', ['SearchInit', 'PaginateInit', 'InventoryHostsForm', 'GetBasePath', 'Wait',
function(SearchInit, PaginateInit, InventoryHostsForm, GetBasePath, Wait) {
.factory('HostsReload', ['$routeParams', 'SearchInit', 'PaginateInit', 'InventoryHostsForm', 'GetBasePath', 'Wait',
function($routeParams, SearchInit, PaginateInit, InventoryHostsForm, GetBasePath, Wait) {
return function(params) {
// Rerfresh the Hosts view on right side of page
@ -424,15 +424,13 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
var url = (group_id !== null && group_id !== undefined) ? GetBasePath('groups') + group_id + '/all_hosts/' :
GetBasePath('inventory') + params.inventory_id + '/hosts/';
if (scope.hostFailureFilter) {
url += '?has_active_failures=true';
}
// Set the groups value in each element of hosts array
if (scope.removePostRefresh) {
scope.removePostRefresh();
}
scope.removePostRefresh = scope.$on('PostRefresh', function() {
// Add a list of groups to each host
var groups, descr, found, list;
for (var i=0; i < scope.hosts.length; i++) {
groups = scope.hosts[i].summary_fields.groups;
@ -444,14 +442,54 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
}
scope.hosts[i].groups = scope.hosts[i].groups.replace(/\, $/,'');
}
// Add the value displayed in Job Status column
for (var i=0; i < scope.hosts.length; i++) {
scope.hosts[i].activeFailuresLink = '/#/hosts/' + scope.hosts[i].id + '/job_host_summaries/?inventory=' + scope['inventory_id'] +
'&host_name=' + escape(scope.hosts[i].name);
if (scope.hosts[i].has_active_failures == true) {
scope.hosts[i].badgeToolTip = 'Most recent job failed. Click to view jobs.';
scope.hosts[i].active_failures = 'failed';
}
else if (scope.hosts[i].has_active_failures == false && scope.hosts[i].last_job == null) {
scope.hosts[i].has_active_failures = 'none';
scope.hosts[i].badgeToolTip = "No job data available.";
scope.hosts[i].active_failures = 'n/a';
}
else if (scope.hosts[i].has_active_failures == false && scope.hosts[i].last_job !== null) {
scope.hosts[i].badgeToolTip = "Most recent job successful. Click to view jobs.";
scope.hosts[i].active_failures = 'success';
}
}
if (postAction) {
postAction();
}
});
});
SearchInit({ scope: scope, set: 'hosts', list: InventoryHostsForm, url: url });
PaginateInit({ scope: scope, list: InventoryHostsForm, url: url });
scope.search('host');
if ($routeParams['has_active_failures']) {
//scope.resetSearch(InventoryHostsForm.iterator);
scope[InventoryHostsForm.iterator + 'InputDisable'] = true;
scope[InventoryHostsForm.iterator + 'SearchValue'] = $routeParams['has_active_failures'];
scope[InventoryHostsForm.iterator + 'SearchField'] = 'has_active_failures';
scope[InventoryHostsForm.iterator + 'SearchFieldLabel'] = InventoryHostsForm.fields['has_active_failures'].label;
scope[InventoryHostsForm.iterator + 'SearchSelectValue'] = ($routeParams['has_active_failures'] == 'true') ? { value: 1 } : { value: 0 };
}
if ($routeParams['name']) {
console.log('here!');
scope[InventoryHostsForm.iterator + 'InputDisable'] = false;
scope[InventoryHostsForm.iterator + 'SearchValue'] = $routeParams['name'];
scope[InventoryHostsForm.iterator + 'SearchField'] = 'name';
scope[InventoryHostsForm.iterator + 'SearchFieldLabel'] = InventoryHostsForm.fields['name'].label;
scope[InventoryHostsForm.iterator + 'SearchSelectValue'] = null;
}
scope.search(InventoryHostsForm.iterator);
if (!params.scope.$$phase) {
params.scope.$digest();
@ -467,6 +505,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
var scope = params.scope;
var inventory_id = params.inventory_id;
var html = '';
var toolTip = 'Hosts have failed jobs?';
function buildHTML(tree_data) {
var sorted = SortNodes(tree_data);
@ -480,7 +519,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
"data-group-id=\"" + sorted[i].id + "\" " +
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
"<i class=\"field-badge icon-failures-" + sorted[i].has_active_failures + "\" " +
"aw-tool-tip=\"Indicates if group contains hosts with active failures\" data-placement=\"bottom\"></i> " +
"aw-tool-tip=\"" + toolTip + "\" data-placement=\"bottom\"></i> " +
"<a href=\"\" class=\"activate\">" + sorted[i].name + "</a> ";
if (sorted[i].children.length > 0) {
buildHTML(sorted[i].children);
@ -651,7 +690,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'H
"data-name=\"" + data.name + "\" " +
"><a href=\"\" class=\"expand\"><i class=\"icon-caret-down\"></i></a> " +
"<i class=\"field-badge icon-failures-" + data.has_active_failures + "\"" +
"aw-tool-tip=\"Indicates if group contains hosts with active failures\" data-placement=\"bottom\"></i> " +
"aw-tool-tip=\"" + toolTip + "\" data-placement=\"bottom\"></i> " +
"<a href=\"\" class=\"activate active\">" + data.name + "</a>";
scope.$emit('buildAllGroups', data.name, data.related.tree, data.related.groups);
scope.$emit('refreshHost', null, 'All Hosts');

View File

@ -0,0 +1,40 @@
/*********************************************
* Copyright (c) 2013 AnsibleWorks, Inc.
*
* JobsHelper
*
* Routines shared by job related controllers
*
*/
angular.module('JobsHelper', [ ])
.factory('JobStatusToolTip', [ function() {
return function(status) {
var toolTip;
switch (status) {
case 'successful':
case 'success':
toolTip = 'There were no failed tasks.';
break;
case 'failed':
toolTip = 'Some tasks encountered errors.';
break;
case 'canceled':
toolTip = 'Stopped by user request.';
break;
case 'new':
toolTip = 'In queue, waiting on task manager.';
break;
case 'waiting':
toolTip = 'SCM Update or Inventory Update is executing.';
break;
case 'pending':
toolTip = 'Not in queue, waiting on task manager.';
break;
case 'running':
toolTip = 'Playbook tasks executing.';
break;
}
return toolTip;
}
}]);

View File

@ -166,7 +166,6 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
$(tree_id).bind('move_node.jstree', function(e, data) {
// When user drags-n-drops a node, update the API
Wait('start');
var node, target, url, parent, inv_id, variables;
@ -273,12 +272,11 @@ angular.module('InventoryHelper', [ 'RestServices', 'Utilities', 'OrganizationLi
}
});
// When user clicks on a group
$(tree_id).bind("select_node.jstree", function(e, data){
scope.$emit('NodeSelect', data.inst.get_json()[0]);
});
// When user clicks on a group
$(tree_id).bind("select_node.jstree", function(e, data){
scope.$emit('NodeSelect', data.inst.get_json()[0]);
});
Wait('start');
LoadTreeData(params);

View File

@ -83,19 +83,57 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
scope[iterator + 'SelectShow'] = false;
scope[iterator + 'HideSearchType'] = false;
scope[iterator + 'InputHide'] = false;
scope[iterator + 'InputDisable'] = false;
scope[iterator + 'SearchType'] = 'icontains';
if (list.fields[fld].searchType && list.fields[fld].searchType == 'gtzero') {
scope[iterator + "InputHide"] = true;
}
if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean'
else if (list.fields[fld].searchSingleValue){
// Query a specific attribute for one specific value
// searchSingleValue: true
// searchType: 'boolean|int|etc.'
// searchValue: < value to match for boolean use 'true'|'false' >
scope[iterator + "SearchType"] = list.fields[fld].searchType;
scope[iterator + 'InputDisable'] = true;
scope[iterator + "SearchValue"] = list.fields[fld].searchValue;
// For boolean type, SearchValue must be an object
if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'true') {
scope[iterator + "SearchSelectValue"] = { value: 1 };
}
else if (list.fields[fld].searchType == 'boolean' && list.fields[fld].searchValue == 'false') {
scope[iterator + "SearchSelectValue"] = { value: 0 };
}
else if (list.fields[fld].searchType == 'boolean') {
scope[iterator + "SearchSelectValue"] = { value: list.fields[fld].searchValue };
}
}
else if (list.fields[fld].searchType && (list.fields[fld].searchType == 'boolean'
|| list.fields[fld].searchType == 'select')) {
scope[iterator + 'SelectShow'] = true;
scope[iterator + 'SearchSelectOpts'] = list.fields[fld].searchOptions;
}
if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
else if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
scope[iterator + 'HideSearchType'] = true;
}
scope.search(iterator);
}
scope.resetSearch = function(iterator) {
// Respdond to click of reset button
scope[iterator + "SearchValue"] = '';
scope[iterator + "SearchSelectValue"] = '';
scope[iterator + 'SelectShow'] = false;
scope[iterator + 'HideSearchType'] = false;
scope[iterator + 'InputHide'] = false;
scope[iterator + 'InputDisable'] = false;
for (fld in list.fields) {
if (list.fields[fld].searchable == undefined || list.fields[fld].searchable == true) {
scope[iterator + 'SearchFieldLabel'] = list.fields[fld].label;
scope[iterator + 'SearchField'] = fld;
break;
}
}
scope.search(iterator);
}

View File

@ -21,21 +21,37 @@ angular.module('InventoriesListDefinition', [])
fields: {
name: {
key: true,
label: 'Name',
badgeIcon: "\{\{ 'icon-failures-' + inventory.has_active_failures \}\}",
badgePlacement: 'left',
badgeToolTip: 'Indicates if inventory contains hosts with active failures',
badgeTipPlacement: 'bottom'
label: 'Name'
},
description: {
label: 'Description'
label: 'Description',
link: true
},
hosts_with_active_failures: {
label: 'Hosts with<br>Failed Job?',
ngHref: '/#/inventories/{{ inventory.id }}/hosts{{ inventory.active_failures_params }}',
type: 'badgeCount',
"class": "{{ 'failures-' + inventory.has_active_failures }}",
//badgeIcon: "\{\{ 'icon-failures-' + inventory.has_active_failures \}\}",
//badgePlacement: 'left',
awToolTip: '# of hosts with failed jobs. Click to view hosts.',
dataPlacement: 'bottom',
searchable: false
},
organization: {
label: 'Organization',
ngBind: 'inventory.summary_fields.organization.name',
linkTo: '/organizations/{{ inventory.organization }}',
sourceModel: 'organization',
sourceField: 'name',
excludeModal: true
},
has_active_failures: {
label: 'Hosts with failed jobs?',
searchSingleValue: true,
searchType: 'boolean',
searchValue: 'true',
searchOnly: true
}
},

View File

@ -25,27 +25,35 @@ angular.module('InventorySummaryDefinition', [])
noLink: true,
ngBind: "group.summary_fields.group.name",
sourceModel: 'group',
sourceField: 'name',
badges: [
{ //Active Failures
icon: "\{\{ 'icon-failures-' + group.summary_fields.group.has_active_failures \}\}",
toolTip: 'Indicates if inventory contains hosts with active failures',
toolTipPlacement: 'bottom'
},
{ //Cloud Status
icon: "\{\{ 'icon-cloud-' + group.status_class \}\}",
toolTip: 'Indicates status of inventory update process',
toolTipPlacement: 'bottom'
}]
sourceField: 'name'
},
failures: {
label: 'Active<br>Failures',
ngBind: "group.summary_fields.group.hosts_with_active_failures",
sourceModel: 'group',
sourceField: 'hosts_with_active_failures',
searchField: 'group__has_active_failures',
searchType: 'boolean',
searchOptions: [{ name: "yes", value: 1 }, { name: "no", value: 0 }]
hosts_with_active_failures: {
label: 'Hosts with<br>Job Failures?',
ngHref: '/#/inventories/{{ inventory_id }}/hosts{{ group.active_failures_params }}',
type: 'badgeCount',
"class": "{{ 'failures-' + group.has_active_failures }}",
awToolTip: '# of hosts with job failures. Click to view hosts.',
dataPlacement: 'bottom',
searchable: false,
nosort: true
},
status: {
label: 'Update<br>Status',
searchType: 'select',
badgeIcon: 'icon-cloud',
badgeToolTip: "\{\{ group.status_badge_tooltip \}\}",
badgePlacement: 'left',
badgeClass: "\{\{ 'icon-cloud-' + group.status_badge_class \}\}",
searchOptions: [
{ name: "failed", value: "failed" },
{ name: "never", value: "never updated" },
{ name: "n/a", value: "none" },
{ name: "successful", value: "successful" },
{ name: "updating", value: "updating" }]
},
last_updated: {
label: 'Last<br>Updated',
searchable: false
},
source: {
label: 'Source',
@ -56,25 +64,20 @@ angular.module('InventorySummaryDefinition', [])
{ name: "Manual", value: "" },
{ name: "Rackspace", value: "rackspace" }]
},
last_updated: {
label: 'Last<br>Updated',
searchable: false
},
status: {
label: 'Update<br>Status',
searchType: 'select',
searchOptions: [
{ name: "failed", value: "failed" },
{ name: "never", value: "never updated" },
{ name: "n/a", value: "none" },
{ name: "successful", value: "successful" },
{ name: "updating", value: "updating" }]
has_active_failures: {
label: 'Hosts have job failures?',
searchSingleValue: true,
searchType: 'boolean',
searchValue: 'true',
searchOnly: true,
sourceModel: 'group',
sourceField: 'has_active_failures'
}
},
actions: {
refresh: {
awRefresh: true,
awRefresh: false,
mode: 'all'
},
help: {

View File

@ -48,14 +48,20 @@ angular.module('JobEventsListDefinition', [])
},
status: {
label: 'Status',
icon: 'icon-circle',
showValue: true,
"class": 'job-\{\{ jobevent.status \}\}',
searchField: 'failed',
searchType: 'boolean',
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }],
nosort: true,
searchable: false
searchable: false,
ngClick: "viewJobEvent(\{\{ jobevent.id \}\})",
awToolTip: "\{\{ jobevent.statusBadgeToolTip \}\}",
dataPlacement: 'top',
badgeIcon: 'icon-job-\{\{ jobevent.status \}\}',
badgePlacement: 'left',
badgeToolTip: "\{\{ jobevent.statusBadgeToolTip \}\}",
badgeTipPlacement: 'top',
badgeNgClick: "viewJobEvent(\{\{ jobevent.id \}\})"
},
event_display: {
label: 'Event',

View File

@ -38,7 +38,7 @@ angular.module('JobHostDefinition', [])
},
fields: {
id: {
job: {
label: 'Job ID',
ngClick: "showJob(\{\{ jobhost.job \}\})",
columnShow: 'host_id !== null',
@ -51,12 +51,18 @@ angular.module('JobHostDefinition', [])
sourceModel: 'host',
sourceField: 'name',
ngBind: 'jobhost.host_name',
ngClick:"showEvents('\{\{ jobhost.summary_fields.host.name \}\}','\{\{ jobhost.related.job \}\}')"
ngHref: "\{\{ jobhost.hostLinkTo \}\}"
},
status: {
label: 'Status',
icon: 'icon-circle',
"class": 'job-\{\{ jobhost.status \}\}',
badgeNgHref: "\{\{ jobhost.statusLinkTo \}\}",
badgeIcon: 'icon-job-\{\{ jobhost.status \}\}',
badgePlacement: 'left',
badgeToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}",
badgeTipPlacement: 'top',
ngHref: "\{\{ jobhost.statusLinkTo \}\}",
awToolTip: "\{\{ jobhost.statusBadgeToolTip \}\}",
dataPlacement: 'top',
searchField: 'failed',
searchType: 'boolean',
searchOptions: [{ name: "success", value: 0 }, { name: "error", value: 1 }]

View File

@ -37,15 +37,15 @@ angular.module('JobsListDefinition', [])
job_template: {
label: 'Job Template',
ngBind: 'job.summary_fields.job_template.name',
link: true,
ngHref: "\{\{ '/#/job_templates/?name=' + job.summary_fields.job_template.name \}\}",
sourceModel: 'job_template',
sourceField: 'name'
},
status: {
label: 'Status',
icon: 'icon-circle',
"class": 'job-\{\{ job.status \}\}',
searchType: 'select',
linkTo: "\{\{ job.statusLinkTo \}\}",
searchOptions: [
{ name: "new", value: "new" },
{ name: "waiting", value: "waiting" },
@ -54,7 +54,14 @@ angular.module('JobsListDefinition', [])
{ name: "successful", value: "successful" },
{ name: "error", value: "error" },
{ name: "failed", value: "failed" },
{ name: "canceled", value: "canceled" } ]
{ name: "canceled", value: "canceled" } ],
badgeIcon: 'icon-job-\{\{ job.status \}\}',
badgePlacement: 'left',
badgeToolTip: "\{\{ job.statusBadgeToolTip \}\}",
badgeTipPlacement: 'top',
badgeNgHref: "\{\{ job.statusLinkTo \}\}",
awToolTip: "\{\{ job.statusBadgeToolTip \}\}",
dataPlacement: 'top'
}
},

View File

@ -9,11 +9,12 @@
@black: #171717;
@warning: #FF9900;
@red: #FF0000;
@red: #da4f49;;
@green: #5bb75b;
@blue: #1778c3; /* logo blue */
@blue-link: #0088cc;
@grey: #A9A9A9;
@green: #5bb75b;
html {
background-color: @black;
@ -32,6 +33,7 @@ body {
.no-bullets { list-style: none; }
.capitalize { text-transform: capitalize; }
.grey-txt { color: @grey; }
.text-center { text-align: center !important; }
.success-badge {
color: #ffffff;
@ -92,10 +94,6 @@ body {
z-index: 1050;
}
.text-center {
text-align: center !important;
}
hr {
border-color: #e3e3e3;
}
@ -607,8 +605,6 @@ select.field-mini-height {
/* Jobs pages */
.job-error,
.job-failed,
.license-expired,
.license-invalid,
.icon-failures-true,
@ -633,33 +629,87 @@ select.field-mini-height {
padding-top: 5px;
}
.job-new,
input[type="text"].job-new,
.job-canceled,
input[type="text"].job-canceled {
color: #778899;
}
.job-pending,
.job-running,
.job-success,
.job-successful,
.job-waiting,
.icon-failures-false,
.license-valid,
input[type="text"].job-success,
input[type="text"].job-successful {
color: #5bb75b;
color: @green;
}
.icon-job-pending:before,
.icon-job-running:before,
.icon-job-success:before,
.icon-job-successful:before,
.icon-job-waiting:before,
.icon-job-new:before,
.icon-job-canceled:before,
.icon-job-changed:before {
content: "\f111";
}
.icon-job-error:before,
.icon-job-failed:before {
content: "\f06a";
}
.icon-job-pending,
.icon-job-running,
.icon-job-success,
.icon-job-successful,
.icon-job-waiting,
.icon-job-new {
color: @green;
}
.icon-job-canceled {
color: @grey;
}
.icon-job-changed {
color: @warning;
}
.icon-job-error,
.icon-job-failed {
color: @red;
}
.icon-failures-none {
color: @grey;
}
.icon-failures-true:before {
content: "\f06a";
}
.icon-failures-none:before,
.icon-failures-false:before {
content: "\f111";
}
.badge {
padding: 3px 4px;
font-size: 11px;
font-weight: normal;
line-height: 1;
}
/* Inventory job status badge */
.failures-true {
background-color: @red;
color: #fff;
}
.failures-false {
background-color: @green;
color: #fff;
}
/* Cloud inventory status. i.e. inventory_source.status values */
@ -671,7 +721,7 @@ select.field-mini-height {
content: "\f0c2";
}
.icon-cloud-na {
color: #e3e3e3;
color: #888;
}
.icon-cloud-never {
color: #888;
@ -684,7 +734,6 @@ select.field-mini-height {
color: @red;
}
.field-success {
color: #5bb75b;
}
@ -702,11 +751,10 @@ select.field-mini-height {
}
.field-badge {
font-size: 12px;
font-size: 14px;
}
.job-changed,
.license-warning,
.license-warning
.license-demo {
color: @warning;
}

View File

@ -1272,7 +1272,7 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<div class=\"hosts-well well\">\n";
html += SearchWidget({ iterator: form.iterator, template: form, mini: true, size: 'col-md-6 col-lg-6'});
html += SearchWidget({ iterator: form.iterator, template: form, mini: true, size: 'col-md-5 col-lg-5'});
html += "<div class=\"col-md-5 col-lg-5\">\n"
html += "<div class=\"pull-right\">\n";
@ -1309,26 +1309,28 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "<tr>\n";
for (var fld in form.fields) {
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ";
html += (!form.fields[fld].nosort) ? "ng-click=\"sort('"+ fld + "')\"" : "";
html += ">";
html += (form['fields'][fld].label && form['fields'][fld].type !== 'DropDown') ? form['fields'][fld].label : '';
if (form.fields[fld].nosort == undefined || form.fields[fld].nosort == false) {
html += " <i class=\"";
if (form.fields[fld].key) {
if (form.fields[fld].desc) {
html += "icon-sort-down";
}
else {
html += "icon-sort-up";
}
}
else {
html += "icon-sort";
}
html += "\"></i>";
if (form.fields[fld].searchOnly == undefined || form.fields[fld].searchOnly == false) {
html += "<th class=\"list-header\" id=\"" + fld + "-header\" ";
html += (!form.fields[fld].nosort) ? "ng-click=\"sort('"+ fld + "')\"" : "";
html += ">";
html += (form['fields'][fld].label && form['fields'][fld].type !== 'DropDown') ? form['fields'][fld].label : '';
if (form.fields[fld].nosort == undefined || form.fields[fld].nosort == false) {
html += " <i class=\"";
if (form.fields[fld].key) {
if (form.fields[fld].desc) {
html += "icon-sort-down";
}
else {
html += "icon-sort-up";
}
}
else {
html += "icon-sort";
}
html += "\"></i>";
}
html += "</th>\n";
}
html += "</th>\n";
}
html += "<th></th>\n";
@ -1349,11 +1351,11 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
rfield = form.fields[fld];
if (fld == 'groups' ) {
// generate group form control/button widget
html += "<td>";
html += "<td class=\"col-lg-5 col-md-4 col-sm-3\">";
html += "<div class=\"input-group input-group-sm\">\n";
html += "<span class=\"input-group-btn\">\n";
html += "<button class=\"btn btn-default\" type=\"button\" id=\"edit_groups_btn\" ng-click=\"editHostGroups({{ host.id }})\" " +
"aw-tool-tip=\"Change group associations for this host\" data-placement=\"top\" >" +
"aw-tool-tip=\"Edit group associations\" data-placement=\"top\" >" +
"<i class=\"icon-sitemap\"></i></button>\n";
html += "</span>\n";
html += "<input type=\"text\" id=\"host_groups\" ng-model=\"host.groups\" class=\"form-control\" disabled=\"disabled\" >\n";
@ -1361,7 +1363,9 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "</td>\n";
}
else {
html += Column({ list: form, fld: fld, options: options, base: null });
if (form.fields[fld].searchOnly == undefined || form.fields[fld].searchOnly == false) {
html += Column({ list: form, fld: fld, options: options, base: null });
}
}
}
@ -1404,12 +1408,14 @@ angular.module('FormGenerator', ['GeneratorHelpers', 'ngCookies'])
html += "</table>\n";
html += "</div>\n"; // close list
/*
html += "<div class=\"row host-failure-filter\">\n";
html += "<div class=\"col-lg-12\">\n";
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"hostFailureFilter\" ng-change=\"filterHosts()\" > Only show hosts with failed jobs" +
"</label>\n";
html += "</div>\n";
html += "</div>\n";
*/
html += "</div>\n"; // close well

View File

@ -186,7 +186,13 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
var name = field['label'].replace(/ /g,'_');
html = (params.td == undefined || params.td !== false) ? "<td>\n" : "";
if (params.td == undefined || params.td !== false) {
html = "<td class=\"" + fld + "-column\">\n";
}
else {
html = '';
}
/*
html += "<div class=\"btn-group\">\n";
html += "<button type=\"button\" ";
@ -218,19 +224,49 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
html += (field.options[i].ngHide) ? "ng-hide=\"" + field.options[i].ngHide + "\" " : "";
html += "href=\"\">" + field.options[i].label + "</a></li>\n";
}
html += "</ul>\n";
html += "</div>\n";
html += (params.td == undefined || params.td !== false) ? "</td>\n" : "";
return html;
}
}])
.factory('BadgeCount', [ function() {
return function(params) {
// Adds a badge count with optional tooltip
var list = params['list'];
var fld = params['fld'];
var field = list.fields[fld];
var options = params['options'];
var base = params['base'];
var html = "<td class=\"" + fld + "-column"
html += (field.columnClass) ? " " + field.columnClass : "";
html += "\">\n";
html += "<a ng-href=\"" + field.ngHref + "\" aw-tool-tip=\"" + field.awToolTip + "\"";
html += (field.dataPlacement) ? " data-placement=\"" + field.dataPlacement + "\"" : "";
html += ">";
html += "<span class=\"badge";
html += (field['class']) ? " " + field['class'] : "";
html += "\">";
html += "\{\{ " + list.iterator + '.' + fld + " \}\}";
html += "</span>";
html += (field.badgeLabel) ? " " + field.badgeLabel : "";
html += "</a>\n";
html += "</td>\n";
return html;
}
}])
.factory('Badge', [ function() {
return function(field) {
// Adds an icon(s) with optional tooltip
var html = '';
if (field.badges) {
@ -254,7 +290,10 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
else {
if (field.badgeToolTip) {
html += "<a href=\"\" aw-tool-tip=\"" + field.badgeToolTip + "\"";
html += "<a ";
html += (field.badgeNgHref) ? "ng-href=\"" + field.badgeNgHref + "\" " : "href=\"\"";
html += (field.ngClick) ? "ng-click=\"" + field.ngClick + "\" " : "";
html += " aw-tool-tip=\"" + field.badgeToolTip + "\"";
html += (field.badgeTipPlacement) ? " data-placement=\"" + field.badgeTipPlacement + "\"" : "";
html += (field.badgeShow) ? " ng-show=\"" + field.badgeShow + "\"" : "";
html += ">";
@ -275,7 +314,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
}])
.factory('Column', ['Attr', 'Icon', 'DropDown', 'Badge', function(Attr, Icon, DropDown, Badge) {
.factory('Column', ['Attr', 'Icon', 'DropDown', 'Badge', 'BadgeCount', function(Attr, Icon, DropDown, Badge, BadgeCount) {
return function(params) {
var list = params['list'];
var fld = params['fld'];
@ -288,6 +327,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
if (field.type !== undefined && field.type == 'DropDown') {
html = DropDown(params);
}
else if (field.type == 'badgeCount') {
html = BadgeCount(params);
}
else {
html += "<td class=\"" + fld + "-column";
html += (field['class']) ? " " + field['class'] : "";
@ -314,17 +356,21 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
// Start the Link
if ( (field.key || field.link || field.linkTo || field.ngClick ) &&
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref) &&
options['mode'] != 'lookup' && options['mode'] != 'select' && !field.noLink ) {
var cap=false;
if (field.linkTo) {
html += "<a href=\"#" + field.linkTo + "\" ";
html += "<a href=\"" + field.linkTo + "\" ";
cap = true;
}
else if (field.ngClick) {
html += "<a href=\"\"" + Attr(field, 'ngClick') + " ";
cap = true;
}
else if (field.ngHref) {
html += "<a ng-href=\"" + field.ngHref + "\" ";
cap = true;
}
else if (field.link || (field.key && (field.link === undefined || field.link))) {
html += "<a href=\"#/" + base + "/{{" + list.iterator + ".id }}\" ";
cap = true;
@ -368,7 +414,7 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
}
// close the link
if ( (field.key || field.link || field.linkTo || field.ngClick )
if ( (field.key || field.link || field.linkTo || field.ngClick || field.ngHref )
&& options.mode != 'lookup' && options.mode != 'select' && !field.noLink ) {
html += "</a>";
}
@ -458,7 +504,6 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
//html += "</a>\n";
html += "<ul class=\"dropdown-menu\" id=\"" + iterator + "SearchDropdown\">\n";
for ( var fld in form.fields) {
if (form.fields[fld].searchable == undefined || form.fields[fld].searchable == true) {
html += "<li><a href=\"\" ng-click=\"setSearchField('" + iterator + "','";
@ -475,8 +520,9 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
html += "<input id=\"search_value_input\" type=\"text\" ng-hide=\"" + iterator + "SelectShow || " + iterator + "InputHide\" class=\"form-control ";
html += "\" ng-model=\"" + iterator + "SearchValue\" ng-change=\"search('" + iterator +
"')\" placeholder=\"Search\" type=\"text\" >\n";
"')\" placeholder=\"Search\" type=\"text\" ng-disabled=\"" + iterator + "InputDisable\">\n";
/*
html += "<div class=\"input-group-btn dropdown\">\n";
html += "<button type=\"button\" ";
html += "id=\"search_option_ddown\" ";
@ -490,7 +536,17 @@ angular.module('GeneratorHelpers', ['GeneratorHelpers'])
html += "<li><a href=\"\" ng-click=\"setSearchType('" + iterator + "','icontains','Contains')\">Contains</a></li>\n";
html += "</ul>\n";
html += "</div><!-- input-group-btn -->\n";
*/
// Reset button
html += "<div class=\"input-group-btn\">\n";
html += "<button type=\"button\" class=\"btn btn-default btn-small\" ng-click=\"resetSearch('" + iterator + "')\" " +
"aw-tool-tip=\"Reset filter\" data-placement=\"top\" " +
"><i class=\"icon-undo\"></i></button>\n";
html += "</div><!-- input-group-btn -->\n";
html += "</div><!-- input-group -->\n";
html += "</div><!-- col-lg-x -->\n";
html += "<div class=\"col-lg-1 col-md-1 col-sm-1 col-xs-1\"><i class=\"icon-spinner icon-spin icon-large\" ng-show=\"" + iterator +
"SearchSpin == true\"></i></div>\n";

View File

@ -224,10 +224,10 @@ angular.module('ListGenerator', ['GeneratorHelpers'])
}
}
if (list.name == 'inventories' && options.mode !== 'select') {
/*if (list.name == 'inventories' && options.mode !== 'select') {
html += "<label class=\"checkbox-inline pull-right\"><input type=\"checkbox\" ng-model=\"inventoryFailureFilter\" " +
"ng-change=\"search('inventory')\" id=\"failed_jobs_chbox\"> Show only inventories with failed jobs</label>\n";
}
}*/
//select instructions
if (options.mode == 'select' && list.selectInstructions) {

View File

@ -106,6 +106,7 @@
<script src="{{ STATIC_URL }}js/helpers/Selection.js"></script>
<script src="{{ STATIC_URL }}js/helpers/Projects.js"></script>
<script src="{{ STATIC_URL }}js/helpers/Users.js"></script>
<script src="{{ STATIC_URL }}js/helpers/Jobs.js"></script>
<script src="{{ STATIC_URL }}js/widgets/ObjectCount.js"></script>
<script src="{{ STATIC_URL }}lib/less/less-1.4.1.min.js"></script>