Latest jobs page changes. Integrated log viewer. Added support to log viewer for variables (extra vars and source vars). Most things on jobs pages are working, execept for scheduled jobs bit.

This commit is contained in:
Chris Houseknecht
2014-03-31 03:25:41 -04:00
parent e1d3da731e
commit 1e0af7b82e
25 changed files with 362 additions and 230 deletions

View File

@@ -113,18 +113,18 @@ angular.module('ansible', [
controller: 'JobsListController' controller: 'JobsListController'
}). }).
when('/jobs/:id', { /* when('/jobs/:id', {
templateUrl: urlPrefix + 'partials/jobs.html', templateUrl: urlPrefix + 'partials/jobs.html',
controller: 'JobsEdit' controller: 'JobsEdit'
}). }). */
when('/jobs/:id/job_events', { when('/jobs/:id/job_events', {
templateUrl: urlPrefix + 'partials/jobs.html', templateUrl: urlPrefix + 'partials/job_events.html',
controller: 'JobEventsList' controller: 'JobEventsList'
}). }).
when('/jobs/:id/job_host_summaries', { when('/jobs/:id/job_host_summaries', {
templateUrl: urlPrefix + 'partials/jobs.html', templateUrl: urlPrefix + 'partials/job_host_summaries.html',
controller: 'JobHostSummaryList' controller: 'JobHostSummaryList'
}). }).

View File

@@ -189,7 +189,7 @@ function InventoriesList($scope, $rootScope, $location, $log, $routeParams, Rest
Prompt({ Prompt({
hdr: 'Delete', hdr: 'Delete',
body: 'Are you sure you want to delete ' + name + '?', body: '<div class=\"alert alert-info\">Are you sure you want to delete ' + name + '?</div>',
action: action action: action
}); });
}; };

View File

@@ -11,14 +11,14 @@
'use strict'; 'use strict';
function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBreadCrumbs, LoadScope, RunningJobsList, CompletedJobsList, QueuedJobsList, function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBreadCrumbs, LoadScope, RunningJobsList, CompletedJobsList, QueuedJobsList,
ScheduledJobsList, GetChoices, GetBasePath, Wait, DeleteJob, Find, DeleteSchedule, ToggleSchedule, RelaunchInventory, RelaunchPlaybook, RelaunchSCM, ScheduledJobsList, GetChoices, GetBasePath, Wait, Find, JobsControllerInit, DeleteSchedule, ToggleSchedule,
LoadDialogPartial, ScheduledJobEdit) { LoadDialogPartial, ScheduledJobEdit) {
ClearScope(); ClearScope();
var e, var e,
completed_scope, running_scope, queued_scope, scheduled_scope, completed_scope, running_scope, queued_scope, scheduled_scope,
choicesCount = 0, listsCount = 0, relaunch, getTypeId; choicesCount = 0;
LoadBreadCrumbs(); LoadBreadCrumbs();
@@ -27,47 +27,7 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
e.html(Breadcrumbs({ list: { editTitle: 'Jobs' } , mode: 'edit' })); e.html(Breadcrumbs({ list: { editTitle: 'Jobs' } , mode: 'edit' }));
$compile(e)($scope); $compile(e)($scope);
relaunch = function(params) {
var scope = params.scope,
id = params.id,
type = params.type,
name = params.name;
if (type === 'inventory_sync') {
RelaunchInventory({ scope: scope, id: id});
}
else if (type === 'playbook_run') {
RelaunchPlaybook({ scope: scope, id: id, name: name });
}
else if (type === 'scm_sync') {
RelaunchSCM({ });
}
};
getTypeId = function(job) {
var type_id;
if (job.type === 'inventory_sync') {
type_id = job.inventory_source;
}
else if (job.type === 'scm_sync') {
type_id = job.poject;
}
else if (job.type === 'playbook_run') {
type_id = job.id;
}
return type_id;
};
// After all the lists are loaded
if ($scope.removeListLoaded) {
$scope.removeListLoaded();
}
$scope.removeListLoaded = $scope.$on('listLoaded', function() {
listsCount++;
if (listsCount === 3) {
Wait('stop');
}
});
// After all choices are ready, load up the lists and populate the page // After all choices are ready, load up the lists and populate the page
if ($scope.removeBuildJobsList) { if ($scope.removeBuildJobsList) {
$scope.removeBuildJobsList(); $scope.removeBuildJobsList();
@@ -113,18 +73,6 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
scheduled_scope.search(ScheduledJobsList.iterator); scheduled_scope.search(ScheduledJobsList.iterator);
}); });
completed_scope.deleteJob = function(id) {
DeleteJob({ scope: completed_scope, id: id });
};
queued_scope.deleteJob = function(id) {
DeleteJob({ scope: queued_scope, id: id });
};
running_scope.deleteJob = function(id) {
DeleteJob({ scope: running_scope, id: id });
};
scheduled_scope.toggleSchedule = function(id) { scheduled_scope.toggleSchedule = function(id) {
ToggleSchedule({ ToggleSchedule({
scope: scheduled_scope, scope: scheduled_scope,
@@ -144,25 +92,6 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
scheduled_scope.editSchedule = function(id) { scheduled_scope.editSchedule = function(id) {
ScheduledJobEdit({ scope: scheduled_scope, id: id }); ScheduledJobEdit({ scope: scheduled_scope, id: id });
}; };
completed_scope.relaunch = function(id) {
var job = Find({ list: completed_scope.completed_jobs, key: 'id', val: id }),
type_id = getTypeId(job);
relaunch({ scope: completed_scope, id: type_id, type: job.type, name: job.name });
};
running_scope.relaunch = function(id) {
var job = Find({ list: running_scope.running_jobs, key: 'id', val: id }),
type_id = getTypeId(job);
relaunch({ scope: running_scope, id: type_id, type: job.type, name: job.name });
};
queued_scope.relaunch = function(id) {
var job = Find({ list: queued_scope.queued_jobs, key: 'id', val: id }),
type_id = getTypeId(job);
relaunch({ scope: queued_scope, id: type_id, type: job.type, name: job.name });
};
}); });
if ($scope.removeChoicesReady) { if ($scope.removeChoicesReady) {
@@ -198,11 +127,17 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea
element_id: 'schedule-dialog-target', element_id: 'schedule-dialog-target',
callback: 'choicesReady' callback: 'choicesReady'
}); });
$scope.refreshJobs = function() {
queued_scope.search('queued_job');
running_scope.search('running_job');
completed_scope.search('completed_job');
};
} }
JobsListController.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'LoadScope', 'RunningJobsList', 'CompletedJobsList', JobsListController.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'LoadScope', 'RunningJobsList', 'CompletedJobsList',
'QueuedJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', 'DeleteJob', 'Find', 'DeleteSchedule', 'ToggleSchedule', 'RelaunchInventory', 'QueuedJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', 'Find', 'JobsControllerInit',
'RelaunchPlaybook', 'RelaunchSCM', 'LoadDialogPartial', 'ScheduledJobEdit']; 'DeleteSchedule', 'ToggleSchedule', 'LoadDialogPartial', 'ScheduledJobEdit'];
function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest, function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest,
Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList,

View File

@@ -37,8 +37,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G
scope.$emit('sourceTypeOptionsReady'); scope.$emit('sourceTypeOptionsReady');
}) })
.error(function (data, status) { .error(function (data, status) {
ProcessErrors(scope, data, status, null, { ProcessErrors(scope, data, status, null, { hdr: 'Error!',
hdr: 'Error!',
msg: 'Failed to retrieve options for inventory_sources.source. OPTIONS status: ' + status msg: 'Failed to retrieve options for inventory_sources.source. OPTIONS status: ' + status
}); });
}); });
@@ -651,7 +650,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
if (ww > 1199) { if (ww > 1199) {
// desktop // desktop
x = 675; x = 675;
y = (780 > wh) ? wh - 15 : 780; y = (800 > wh) ? wh - 15 : 800;
maxrows = 18; maxrows = 18;
} else if (ww <= 1199 && ww >= 768) { } else if (ww <= 1199 && ww >= 768) {
x = 550; x = 550;
@@ -740,8 +739,8 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
if (sources_scope.codeMirror) { if (sources_scope.codeMirror) {
sources_scope.codeMirror.destroy(); sources_scope.codeMirror.destroy();
} }
$('#group-modal-dialog').dialog('destroy');
$('#group-modal-dialog').hide(); $('#group-modal-dialog').hide();
$('#group-modal-dialog').dialog('destroy');
$('#properties-tab').empty(); $('#properties-tab').empty();
$('#sources-tab').empty(); $('#sources-tab').empty();
$('#schedules-list').empty(); $('#schedules-list').empty();
@@ -983,9 +982,12 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
if (modal_scope.searchCleanUp) { if (modal_scope.searchCleanUp) {
modal_scope.searchCleanup(); modal_scope.searchCleanup();
} }
try {
$('#group-modal-dialog').dialog('close'); $('#group-modal-dialog').dialog('close');
}
catch(e) {
// ignore
}
// Change the selected group // Change the selected group
if (groups_reload && parent_scope.selected_tree_id !== tree_id) { if (groups_reload && parent_scope.selected_tree_id !== tree_id) {
parent_scope.showHosts(tree_id, group_id, false); parent_scope.showHosts(tree_id, group_id, false);
@@ -1058,7 +1060,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
overwrite: sources_scope.overwrite, overwrite: sources_scope.overwrite,
overwrite_vars: sources_scope.overwrite_vars, overwrite_vars: sources_scope.overwrite_vars,
update_on_launch: sources_scope.update_on_launch, update_on_launch: sources_scope.update_on_launch,
update_cache_timeout: sources_scope.update_cache_timeout update_cache_timeout: (sources_scope.update_cache_timeout || 0)
}; };
// Create a string out of selected list of regions // Create a string out of selected list of regions
@@ -1165,7 +1167,6 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
} }
}) })
.error(function (data, status) { .error(function (data, status) {
Wait('stop');
ProcessErrors(properties_scope, data, status, GroupForm, { hdr: 'Error!', ProcessErrors(properties_scope, data, status, GroupForm, { hdr: 'Error!',
msg: 'Failed to create group: ' + group_id + '. POST status: ' + status msg: 'Failed to create group: ' + group_id + '. POST status: ' + status
}); });
@@ -1243,7 +1244,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) {
Prompt({ Prompt({
hdr: 'Delete Group', hdr: 'Delete Group',
body: '<p>Are you sure you want to delete group <em>' + node.name + '?</p>', body: '<div class=\"alert alert-info\">Are you sure you want to delete group <em>' + node.name + '?</div>',
action: action_to_take, action: action_to_take,
'class': 'btn-danger' 'class': 'btn-danger'
}); });

View File

@@ -8,7 +8,7 @@
'use strict'; 'use strict';
angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition',
'LookUpHelper', 'JobSubmissionHelper' ]) 'LookUpHelper', 'JobSubmissionHelper', 'JobTemplateFormDefinition' ])
.factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) { .factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) {
return function(params) { return function(params) {
@@ -48,7 +48,7 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
LookUpInit({ LookUpInit({
url: GetBasePath('credentials') + '?kind=ssh', url: GetBasePath('credentials') + '?kind=ssh',
scope: scope, scope: scope,
form: JobTemplateForm, form: JobTemplateForm(),
current_item: null, current_item: null,
list: CredentialList, list: CredentialList,
field: 'credential', field: 'credential',
@@ -68,7 +68,7 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
callback = params.callback || 'PasswordsAccepted', callback = params.callback || 'PasswordsAccepted',
password, password,
form = CredentialForm, form = CredentialForm,
html, html = "",
acceptedPasswords = {}, acceptedPasswords = {},
scope = parent_scope.$new(); scope = parent_scope.$new();
@@ -80,14 +80,12 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
password = passwords.pop(); password = passwords.pop();
// Prompt for password // Prompt for password
html += "<form class=\"form-horizontal\" name=\"password_form\" novalidate>\n"; html += "<form name=\"password_form\" novalidate>\n";
field = form.fields[password]; field = form.fields[password];
fld = password; fld = password;
scope[fld] = ''; scope[fld] = '';
html += "<div class=\"form-group\">\n"; html += "<div class=\"form-group\">\n";
html += "<label class=\"col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3\" for=\"" + fld + "\">* "; html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
html += "</label>\n";
html += "<div class=\"col-md-8 col-sm-8 col-xs-9\">\n";
html += "<input type=\"password\" "; html += "<input type=\"password\" ";
html += "ng-model=\"" + fld + '" '; html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" '; html += 'name="' + fld + '" ';
@@ -100,7 +98,6 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
"password_form." + fld + ".$error.required\">A value is required!</span>\n"; "password_form." + fld + ".$error.required\">A value is required!</span>\n";
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n"; html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n"; html += "</div>\n";
html += "</div>\n";
// Add the related confirm field // Add the related confirm field
if (field.associated) { if (field.associated) {
@@ -108,9 +105,7 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
field = form.fields[field.associated]; field = form.fields[field.associated];
scope[fld] = ''; scope[fld] = '';
html += "<div class=\"form-group\">\n"; html += "<div class=\"form-group\">\n";
html += "<label class=\"col-md-offset-1 col-md-2 col-sm-offset-1 col-sm-2 col-xs-3\" for=\"" + fld + "\">* "; html += "<label for=\"" + fld + "\">* " + field.label + "</label>\n";
html += "</label>\n";
html += "<div class=\"col-md-8 col-sm-8 col-xs-9\">\n";
html += "<input type=\"password\" "; html += "<input type=\"password\" ";
html += "ng-model=\"" + fld + '" '; html += "ng-model=\"" + fld + '" ';
html += 'name="' + fld + '" '; html += 'name="' + fld + '" ';
@@ -126,7 +121,6 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
".$error.awpassmatch\">Must match Password value</span>\n" : ""; ".$error.awpassmatch\">Must match Password value</span>\n" : "";
html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n"; html += "<span class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></span>\n";
html += "</div>\n"; html += "</div>\n";
html += "</div>\n";
} }
html += "</form>\n"; html += "</form>\n";
$('#password-body').empty().html(html); $('#password-body').empty().html(html);
@@ -139,8 +133,9 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
} }
scope.passwordAccept = function() { scope.passwordAccept = function() {
$('#password-modal').modal('hide');
acceptedPasswords[password] = scope[password]; acceptedPasswords[password] = scope[password];
if (password.length > 0) { if (passwords.length > 0) {
promptPassword(); promptPassword();
} }
else { else {
@@ -149,9 +144,12 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
}; };
scope.passwordCancel = function() { scope.passwordCancel = function() {
Alert('Missing Password', 'Required password(s) not provided. The request will not be submitted.', 'alert-info'); $('#password-modal').modal('hide');
Alert('Missing Password', 'Required password(s) not provided. Your request will not be submitted.', 'alert-info');
parent_scope.$emit('PasswordsCanceled'); parent_scope.$emit('PasswordsCanceled');
}; };
promptPassword();
}; };
}]) }])
@@ -178,7 +176,7 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
new_job_id = data.id; new_job_id = data.id;
launch_url = data.related.start; launch_url = data.related.start;
if (data.passwords_needed_to_start.length > 0) { if (data.passwords_needed_to_start.length > 0) {
scope.$emit('PromptForPasswords'); scope.$emit('PromptForPasswords', data.passwords_needed_to_start);
} else { } else {
scope.$emit('StartPlaybookRun', {}); scope.$emit('StartPlaybookRun', {});
} }
@@ -293,8 +291,13 @@ function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) {
// Refresh the project list after update request submitted // Refresh the project list after update request submitted
Wait('stop'); Wait('stop');
Alert('Update Started', 'The request to start the SCM update process was submitted. ' + Alert('Update Started', 'The request to start the SCM update process was submitted. ' +
'To monitor the update status, refresh the page by clicking the <em>Refresh</em> button.', 'alert-info'); 'To monitor the update status, refresh the page by clicking the <i class="fa fa-refresh"></i> button.', 'alert-info');
scope.refresh(); if (scope.refreshJobs) {
scope.refreshJobs();
}
else if (scope.refresh) {
scope.refresh();
}
}); });
if (scope.removePromptForPasswords) { if (scope.removePromptForPasswords) {

View File

@@ -10,7 +10,98 @@
'use strict'; 'use strict';
angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper', 'GeneratorHelpers', angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper', 'GeneratorHelpers',
'JobSubmissionHelper', 'SchedulesHelper']) 'JobSubmissionHelper', 'SchedulesHelper', 'LogViewerHelper'])
/**
* JobsControllerInit({ scope: $scope });
*
* Initialize calling scope with all the bits required to support a jobs list
*
*/
.factory('JobsControllerInit', ['$location', 'Find', 'DeleteJob', 'RelaunchJob', 'LogViewer',
function($location, Find, DeleteJob, RelaunchJob, LogViewer) {
return function(params) {
var scope = params.scope,
parent_scope = params.parent_scope;
scope.deleteJob = function(id) {
DeleteJob({ scope: scope, id: id });
};
scope.relaunchJob = function(id) {
var list, job, typeId;
if (scope.completed_jobs) {
list = scope.completed_jobs;
}
else if (scope.running_jobs) {
list = scope.running_jobs;
}
else if (scope.queued_jobs) {
list = scope.queued_jobs;
}
job = Find({ list: list, key: 'id', val: id });
if (job.type === 'inventory_update') {
typeId = job.inventory_source;
}
else if (job.type === 'project_update') {
typeId = job.project;
}
else if (job.type === 'job') {
typeId = job.id;
}
RelaunchJob({ scope: scope, id: typeId, type: job.type, name: job.name });
};
scope.refreshJobs = function() {
parent_scope.refreshJobs();
};
scope.viewJobLog = function(id, url) {
var list, job;
if (url) {
$location.path(url);
}
else {
if (scope.completed_jobs) {
list = scope.completed_jobs;
}
else if (scope.running_jobs) {
list = scope.running_jobs;
}
else if (scope.queued_jobs) {
list = scope.queued_jobs;
}
job = Find({ list: list, key: 'id', val: id });
LogViewer({
scope: scope,
url: job.url,
status_icon: 'icon-job-' + job.status
});
}
};
};
}
])
.factory('RelaunchJob', ['RelaunchInventory', 'RelaunchPlaybook', 'RelaunchSCM',
function(RelaunchInventory, RelaunchPlaybook, RelaunchSCM) {
return function(params) {
var scope = params.scope,
id = params.id,
type = params.type,
name = params.name;
if (type === 'inventory_update') {
RelaunchInventory({ scope: scope, id: id});
}
else if (type === 'job') {
RelaunchPlaybook({ scope: scope, id: id, name: name });
}
else if (type === 'project_update') {
RelaunchSCM({ scope: scope, id: id });
}
};
}
])
.factory('JobStatusToolTip', [ .factory('JobStatusToolTip', [
function () { function () {
@@ -170,8 +261,8 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
* Called from JobsList controller to load each section or list on the page * Called from JobsList controller to load each section or list on the page
* *
*/ */
.factory('LoadScope', ['SearchInit', 'PaginateInit', 'GenerateList', 'PageRangeSetup', 'ProcessErrors', 'Rest', .factory('LoadScope', ['SearchInit', 'PaginateInit', 'GenerateList', 'JobsControllerInit', 'Rest',
function(SearchInit, PaginateInit, GenerateList) { function(SearchInit, PaginateInit, GenerateList, JobsControllerInit, Rest) {
return function(params) { return function(params) {
var parent_scope = params.parent_scope, var parent_scope = params.parent_scope,
scope = params.scope, scope = params.scope,
@@ -199,7 +290,7 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
scope: scope, scope: scope,
list: list, list: list,
url: url, url: url,
pageSize: 10 pageSize: 5
}); });
scope.iterator = list.iterator; scope.iterator = list.iterator;
@@ -208,6 +299,8 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
scope.removePostRefresh(); scope.removePostRefresh();
} }
scope.$on('PostRefresh', function(){ scope.$on('PostRefresh', function(){
JobsControllerInit({ scope: scope, parent_scope: parent_scope });
scope[list.name].forEach(function(item, item_idx) { scope[list.name].forEach(function(item, item_idx) {
var fld, field, var fld, field,
@@ -231,6 +324,20 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
} }
return true; return true;
}); });
//Set the name link
if (item.type === "inventory_update") {
Rest.setUrl(item.related.inventory_source);
Rest.get()
.success(function(data) {
itm.nameHref = "/inventories/" + data.inventory;
});
}
else if (item.type === "project_update") {
itm.nameHref = "/projects/" + item.project;
}
else if (item.type === "job") {
itm.nameHref = "";
}
if (list.name === 'completed_jobs' || list.name === 'running_jobs') { if (list.name === 'completed_jobs' || list.name === 'running_jobs') {
itm.status_tip = itm.status_label + '. Click for details.'; itm.status_tip = itm.status_label + '. Click for details.';
@@ -288,7 +395,7 @@ function(Find, GetBasePath, Rest, Wait, ProcessErrors, Prompt){
action_label = 'cancel'; action_label = 'cancel';
hdr = 'Cancel Job'; hdr = 'Cancel Job';
} else { } else {
url = GetBasePath('jobs') + id + '/'; url = job.related.cancel; //GetBasePath('unified_jobs') + id + '/';
action_label = 'delete'; action_label = 'delete';
hdr = 'Delete Job'; hdr = 'Delete Job';
} }
@@ -368,7 +475,7 @@ function(Find, Wait, Rest, InventoryUpdate, ProcessErrors, GetBasePath) {
return function(params) { return function(params) {
var scope = params.scope, var scope = params.scope,
id = params.id; id = params.id;
ProjectUpdate({ scope: scope, id: id }); ProjectUpdate({ scope: scope, project_id: id });
}; };
}]) }])

View File

@@ -7,12 +7,12 @@
'use strict'; 'use strict';
angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator']) angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator', 'VariablesHelper'])
.factory('LogViewer', ['$compile', 'CreateDialog', 'GetJob', 'Wait', 'GenerateForm', 'LogViewerStatusForm', 'AddTable', 'AddTextarea', .factory('LogViewer', ['$compile', 'CreateDialog', 'GetJob', 'Wait', 'GenerateForm', 'LogViewerStatusForm', 'AddTable', 'AddTextarea',
'LogViewerOptionsForm', 'EnvTable', 'GetBasePath', 'LookUpName', 'Empty', 'LogViewerOptionsForm', 'EnvTable', 'GetBasePath', 'LookUpName', 'Empty', 'AddPreFormattedText', 'ParseVariableString',
function($compile, CreateDialog, GetJob, Wait, GenerateForm, LogViewerStatusForm, AddTable, AddTextarea, LogViewerOptionsForm, EnvTable, function($compile, CreateDialog, GetJob, Wait, GenerateForm, LogViewerStatusForm, AddTable, AddTextarea, LogViewerOptionsForm, EnvTable,
GetBasePath, LookUpName, Empty) { GetBasePath, LookUpName, Empty, AddPreFormattedText, ParseVariableString) {
return function(params) { return function(params) {
var parent_scope = params.scope, var parent_scope = params.scope,
url = params.url, url = params.url,
@@ -41,21 +41,19 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator'])
AddTable({ scope: scope, form: LogViewerOptionsForm, id: 'options-form-container', status_icon: status_icon }); AddTable({ scope: scope, form: LogViewerOptionsForm, id: 'options-form-container', status_icon: status_icon });
if (data.result_stdout) { if (data.result_stdout) {
AddTextarea({ AddPreFormattedText({
container_id: 'stdout-form-container', id: 'stdout-form-container',
val: data.result_stdout, val: data.result_stdout
fld_id: 'stdout-textarea'
}); });
} }
else { else {
$('#logview-tabs li:eq(2)').hide(); $('#logview-tabs li:eq(1)').hide();
} }
if (data.result_traceback) { if (data.result_traceback) {
AddTextarea({ AddPreFormattedText({
container_id: 'traceback-form-container', id: 'traceback-form-container',
val: data.result_traceback, val: data.result_traceback
fld_id: 'traceback-textarea'
}); });
} }
else { else {
@@ -68,6 +66,28 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator'])
vars: data.job_env vars: data.job_env
}); });
}*/ }*/
if (data.extra_vars) {
AddTextarea({
container_id: 'variables-container',
fld_id: 'variables',
val: ParseVariableString(data.extra_vars)
});
}
else {
$('#logview-tabs li:eq(4)').hide();
}
if (data.source_vars) {
AddTextarea({
container_id: 'source-container',
fld_id: 'source-variables',
val: ParseVariableString(data.source_vars)
});
}
else {
$('#logview-tabs li:eq(5)').hide();
}
if (!Empty(scope.credential)) { if (!Empty(scope.credential)) {
LookUpName({ LookUpName({
@@ -81,7 +101,7 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator'])
LookUpName({ LookUpName({
scope: scope, scope: scope,
scope_var: 'inventory', scope_var: 'inventory',
url: GetBasePath('inventories') + scope.inventory + '/' url: GetBasePath('inventory') + scope.inventory + '/'
}); });
} }
@@ -115,8 +135,8 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator'])
rows = Math.floor((h - u) / 20); rows = Math.floor((h - u) / 20);
rows -= 3; rows -= 3;
rows = (rows < 6) ? 6 : rows; rows = (rows < 6) ? 6 : rows;
$('#stdout-textarea').attr({ rows: rows }); $('#logviewer-modal-dialog #variables').attr({ rows: rows });
$('#traceback-textarea').attr({ rows: rows }); $('#logviewer-modal-dialog #source-variables').attr({ rows: rows });
}; };
elem = angular.element(document.getElementById('logviewer-modal-dialog')); elem = angular.element(document.getElementById('logviewer-modal-dialog'));
@@ -237,12 +257,22 @@ angular.module('LogViewerHelper', ['ModalDialog', 'Utilities', 'FormGenerator'])
fld_id = params.fld_id, fld_id = params.fld_id,
html; html;
html = "<div class=\"form-group\">\n" + html = "<div class=\"form-group\">\n" +
"<textarea id=\"" + fld_id + "\" class=\"form-control nowrap mono-space\" rows=\"12\" readonly>" + val + "</textarea>" + "<textarea id=\"" + fld_id + "\" class=\"form-control mono-space\" rows=\"12\" readonly>" + val + "</textarea>" +
"</div>\n"; "</div>\n";
$('#' + container_id).empty().html(html); $('#' + container_id).empty().html(html);
}; };
}]) }])
.factory('AddPreFormattedText', [function() {
return function(params) {
var id = params.id,
val = params.val,
html;
html = "<pre>" + val + "</pre>\n";
$('#' + id).empty().html(html);
};
}])
.factory('EnvTable', [ function() { .factory('EnvTable', [ function() {
return function(params) { return function(params) {
var id = params.id, var id = params.id,

View File

@@ -3,8 +3,6 @@
* *
* VariablesHelper * VariablesHelper
* *
* Show the CodeMirror variable editor and allow
* toggle between JSON and YAML
* *
*/ */
@@ -35,6 +33,7 @@ angular.module('VariablesHelper', ['Utilities'])
$log.info('Attempt to parse extra_vars as JSON failed. Attempting to parse as YAML'); $log.info('Attempt to parse extra_vars as JSON failed. Attempting to parse as YAML');
try { try {
json_obj = jsyaml.safeLoad(variables); json_obj = jsyaml.safeLoad(variables);
json_obj = SortVariables(json_obj);
result = jsyaml.safeDump(json_obj); result = jsyaml.safeDump(json_obj);
} }
catch(e2) { catch(e2) {

View File

@@ -22,7 +22,7 @@ angular.module('CompletedJobsDefinition', [])
fields: { fields: {
id: { id: {
label: 'Job ID', label: 'Job ID',
linkTo: '/#/jobs/{{ completed_job.id }}', ngClick:"viewJobLog(completed_job.id)",
key: true, key: true,
desc: true, desc: true,
searchType: 'int', searchType: 'int',
@@ -30,13 +30,15 @@ angular.module('CompletedJobsDefinition', [])
}, },
status: { status: {
label: 'Status', label: 'Status',
columnClass: 'col-md-2 col-sm-2 col-xs-2',
awToolTip: "{{ completed_job.status_tip }}", awToolTip: "{{ completed_job.status_tip }}",
awTipPlacement: "top", awTipPlacement: "top",
dataTitle: "{{ completed_job.status_popover_title }}", dataTitle: "{{ completed_job.status_popover_title }}",
icon: 'icon-job-{{ completed_job.status }}', icon: 'icon-job-{{ completed_job.status }}',
iconOnly: true, iconOnly: true,
awPopOver: "{{ completed_job.status_popover }}", ngClick:"viewJobLog(completed_job.id)",
dataPlacement: 'right', /*awPopOver: "{{ completed_job.status_popover }}",
dataPlacement: 'right',*/
searchType: 'select', searchType: 'select',
searchOptions: [ searchOptions: [
{ name: "Success", value: "successful" }, { name: "Success", value: "successful" },
@@ -50,8 +52,8 @@ angular.module('CompletedJobsDefinition', [])
searchType: 'int', searchType: 'int',
searchOnly: true searchOnly: true
}, },
modified: { finished: {
label: 'Completed On', label: 'Finished On',
link: false, link: false,
searchable: false, searchable: false,
filter: "date:'MM/dd/yy HH:mm:ss'", filter: "date:'MM/dd/yy HH:mm:ss'",
@@ -66,9 +68,7 @@ angular.module('CompletedJobsDefinition', [])
name: { name: {
label: 'Name', label: 'Name',
columnClass: 'col-md-3 col-xs-5', columnClass: 'col-md-3 col-xs-5',
ngHref: 'nameHref', ngClick: "viewJobLog(completed_job.id, completed_job.nameHref)"
sourceModel: 'template',
sourceField: 'name'
}, },
failed: { failed: {
label: 'Job failed?', label: 'Job failed?',
@@ -85,7 +85,7 @@ angular.module('CompletedJobsDefinition', [])
refresh: { refresh: {
mode: 'all', mode: 'all',
awToolTip: "Refresh the page", awToolTip: "Refresh the page",
ngClick: "refresh()" ngClick: "refreshJobs()"
} }
}, },
@@ -93,8 +93,8 @@ angular.module('CompletedJobsDefinition', [])
submit: { submit: {
icon: 'icon-rocket', icon: 'icon-rocket',
mode: 'all', mode: 'all',
ngClick: 'relaunch(completed_job.id)', ngClick: 'relaunchJob(completed_job.id)',
awToolTip: 'Relaunch the job', awToolTip: 'Relaunch using the same parameters',
dataPlacement: 'top' dataPlacement: 'top'
}, },
"delete": { "delete": {
@@ -105,11 +105,12 @@ angular.module('CompletedJobsDefinition', [])
}, },
dropdown: { dropdown: {
type: 'DropDown', type: 'DropDown',
ngShow: "completed_job.type === 'job'",
label: 'View', label: 'View',
icon: 'fa-search-plus', icon: 'fa-search-plus',
'class': 'btn-default btn-xs', 'class': 'btn-default btn-xs',
options: [ options: [
{ ngHref: '/#/jobs/{{ completed_job.id }}', label: 'Status' }, //{ ngHref: '/#/jobs/{{ completed_job.id }}', label: 'Status' },
{ ngHref: '/#/jobs/{{ completed_job.id }}/job_events', label: 'Events', ngHide: "completed_job.status == 'new'" }, { ngHref: '/#/jobs/{{ completed_job.id }}/job_events', label: 'Events', ngHide: "completed_job.status == 'new'" },
{ ngHref: '/#/jobs/{{ completed_job.id }}/job_host_summaries', label: 'Host Summary' } { ngHref: '/#/jobs/{{ completed_job.id }}/job_host_summaries', label: 'Host Summary' }
] ]

View File

@@ -21,12 +21,12 @@ angular.module('JobEventsListDefinition', [])
filterBy: '{ show: true }', filterBy: '{ show: true }',
navigationLinks: { navigationLinks: {
details: { //details: {
href: '/#/jobs/{{ job_id }}', // href: '/#/jobs/{{ job_id }}',
label: 'Status', // label: 'Status',
icon: 'icon-zoom-in', // icon: 'icon-zoom-in',
ngShow: 'job_id !== null' // ngShow: 'job_id !== null'
}, //},
events: { events: {
href: '/#/jobs/{{ job_id }}/job_events', href: '/#/jobs/{{ job_id }}/job_events',
label: 'Events', label: 'Events',

View File

@@ -20,12 +20,12 @@ angular.module('JobHostDefinition', [])
navigationLinks: { navigationLinks: {
ngHide: 'host_id !== null', ngHide: 'host_id !== null',
details: { //details: {
href: "/#/jobs/{{ job_id }}", // href: "/#/jobs/{{ job_id }}",
label: 'Status', // label: 'Status',
icon: 'icon-zoom-in', // icon: 'icon-zoom-in',
ngShow: "job_id !== null" // ngShow: "job_id !== null"
}, //},
events: { events: {
href: "/#/jobs/{{ job_id }}/job_events", href: "/#/jobs/{{ job_id }}/job_events",
label: 'Events', label: 'Events',

View File

@@ -22,11 +22,22 @@ angular.module('QueuedJobsDefinition', [])
fields: { fields: {
id: { id: {
label: 'Job ID', label: 'Job ID',
ngClick:"viewJobLog(queued_job.id)",
key: true, key: true,
desc: true, desc: true,
searchType: 'int', searchType: 'int',
columnClass: 'col-md-1 col-sm-2 col-xs-2' columnClass: 'col-md-1 col-sm-2 col-xs-2'
}, },
status: {
label: 'Status',
columnClass: 'col-md-2 col-sm-2 col-xs-2',
awToolTip: "{{ queued_job.status_tip }}",
awTipPlacement: "top",
dataTitle: "{{ queued_job.status_popover_title }}",
icon: 'icon-job-{{ queued_job.status }}',
iconOnly: true,
ngClick:"viewJobLog(queued_job.id)"
},
inventory: { inventory: {
label: 'Inventory ID', label: 'Inventory ID',
searchType: 'int', searchType: 'int',
@@ -48,9 +59,7 @@ angular.module('QueuedJobsDefinition', [])
name: { name: {
label: 'Name', label: 'Name',
columnClass: 'col-sm-3 col-xs-5', columnClass: 'col-sm-3 col-xs-5',
ngHref: 'nameHref', ngClick: "viewJobLog(queued_job.id, queued_job.nameHref)"
sourceModel: 'template',
sourceField: 'name'
} }
}, },
@@ -59,22 +68,16 @@ angular.module('QueuedJobsDefinition', [])
refresh: { refresh: {
mode: 'all', mode: 'all',
awToolTip: "Refresh the page", awToolTip: "Refresh the page",
ngClick: "refresh()" ngClick: "refreshJobs()"
} }
}, },
fieldActions: { fieldActions: {
status: {
mode: 'all',
iconClass: 'fa icon-job-{{ queued_job.status }}',
awToolTip: "{{ queued_job.statusToolTip }}",
dataPlacement: 'top'
},
submit: { submit: {
icon: 'icon-rocket', icon: 'icon-rocket',
mode: 'all', mode: 'all',
ngClick: 'relaunch(queued_job.id)', ngClick: 'relaunchJob(queued_job.id)',
awToolTip: 'Launch another instance of the job', awToolTip: 'Relaunch using the same parameters',
dataPlacement: 'top' dataPlacement: 'top'
}, },
cancel: { cancel: {

View File

@@ -22,18 +22,29 @@ angular.module('RunningJobsDefinition', [])
fields: { fields: {
id: { id: {
label: 'Job ID', label: 'Job ID',
ngClick:"viewJobLog(running_job.id)",
key: true, key: true,
desc: true, desc: true,
searchType: 'int', searchType: 'int',
columnClass: 'col-md-1 col-sm-2 col-xs-2' columnClass: 'col-md-1 col-sm-2 col-xs-2'
}, },
status: {
label: 'Status',
columnClass: 'col-md-2 col-sm-2 col-xs-2',
awToolTip: "{{ running_job.status_tip }}",
awTipPlacement: "top",
dataTitle: "{{ running_job.status_popover_title }}",
icon: 'icon-job-{{ running_job.status }}',
iconOnly: true,
ngClick:"viewJobLog(running_job.id)"
},
inventory: { inventory: {
label: 'Inventory ID', label: 'Inventory ID',
searchType: 'int', searchType: 'int',
searchOnly: true searchOnly: true
}, },
modified: { started: {
label: 'Last Updated', label: 'Started On',
link: false, link: false,
searchable: false, searchable: false,
filter: "date:'MM/dd/yy HH:mm:ss'", filter: "date:'MM/dd/yy HH:mm:ss'",
@@ -48,9 +59,7 @@ angular.module('RunningJobsDefinition', [])
name: { name: {
label: 'Name', label: 'Name',
columnClass: 'col-md-3 col-xs-5', columnClass: 'col-md-3 col-xs-5',
ngHref: 'nameHref', ngClick: "viewJobLog(running_job.id, running_job.nameHref)"
sourceModel: 'template',
sourceField: 'name'
} }
}, },
@@ -59,25 +68,16 @@ angular.module('RunningJobsDefinition', [])
refresh: { refresh: {
mode: 'all', mode: 'all',
awToolTip: "Refresh the page", awToolTip: "Refresh the page",
ngClick: "refresh()" ngClick: "refreshJobs()"
} }
}, },
fieldActions: { fieldActions: {
status: {
mode: 'all',
awToolTip: "{{ running_job.status_tip }}",
awTipPlacement: "top",
dataTitle: "{{ running_job.status_popover_title }}",
iconClass: 'fa icon-job-{{ running_job.status }}',
awPopOver: "{{ running_job.status_popover }}",
dataPlacement: 'left'
},
submit: { submit: {
icon: 'icon-rocket', icon: 'icon-rocket',
mode: 'all', mode: 'all',
ngClick: 'relaunch(running_job.id)', ngClick: 'relaunchJob(running_job.id)',
awToolTip: 'Launch another instance of the job', awToolTip: 'Relaunch using the same parameters',
dataPlacement: 'top' dataPlacement: 'top'
}, },
cancel: { cancel: {
@@ -88,11 +88,12 @@ angular.module('RunningJobsDefinition', [])
}, },
dropdown: { dropdown: {
type: 'DropDown', type: 'DropDown',
ngShow: "running_job.type === 'job'",
label: 'View', label: 'View',
icon: 'fa-search-plus', icon: 'fa-search-plus',
'class': 'btn-default btn-xs', 'class': 'btn-default btn-xs',
options: [ options: [
{ ngHref: '/#/jobs/{{ running_job.id }}', label: 'Status' }, //{ ngHref: '/#/jobs/{{ running_job.id }}', label: 'Status' },
{ ngHref: '/#/jobs/{{ running_job.id }}/job_events', label: 'Events' }, { ngHref: '/#/jobs/{{ running_job.id }}/job_events', label: 'Events' },
{ ngHref: '/#/jobs/{{ running_job.id }}/job_host_summaries', label: 'Host Summary' } { ngHref: '/#/jobs/{{ running_job.id }}/job_host_summaries', label: 'Host Summary' }
] ]

View File

@@ -53,7 +53,7 @@ angular.module('ScheduledJobsDefinition', [])
refresh: { refresh: {
mode: 'all', mode: 'all',
awToolTip: "Refresh the page", awToolTip: "Refresh the page",
ngClick: "refresh()" ngClick: "refreshJobs()"
} }
}, },

View File

@@ -64,9 +64,14 @@ body.modal-open {
.nowrap { white-space: nowrap; } .nowrap { white-space: nowrap; }
.capitalize { text-transform: capitalize; } .capitalize { text-transform: capitalize; }
.grey-txt { color: @grey; } .grey-txt { color: @grey; }
.red-txt { color: @red; } a.red-txt:hover { color: @red; } //make red links (for things like cancel)
.text-center { text-align: center !important; } .text-center { text-align: center !important; }
.red-txt,
a.red-txt:visited,
a.red-txt:hover,
a.red-txt:active {
color: @red;
}
/* Used on inventory groups/hosts lists for long names */ /* Used on inventory groups/hosts lists for long names */
.ellipsis { .ellipsis {
@@ -973,12 +978,9 @@ input[type="checkbox"].checkbox-no-label {
color: @green; color: @green;
} }
.icon-job-pending:before,
.icon-job-running:before, .icon-job-running:before,
.icon-job-success:before, .icon-job-success:before,
.icon-job-successful:before, .icon-job-successful:before,
.icon-job-waiting:before,
.icon-job-new:before,
.icon-job-changed:before { .icon-job-changed:before {
content: "\f111"; content: "\f111";
} }
@@ -989,12 +991,16 @@ input[type="checkbox"].checkbox-no-label {
content: "\f06a"; content: "\f06a";
} }
.icon-job-pending, .icon-job-pending:before,
.icon-job-waiting:before,
.icon-job-new:before,
.icon-job-none:before {
content: "\f10c";
}
.icon-job-running, .icon-job-running,
.icon-job-success, .icon-job-success,
.icon-job-successful, .icon-job-successful {
.icon-job-waiting,
.icon-job-new {
color: @green; color: @green;
} }
@@ -1013,15 +1019,14 @@ input[type="checkbox"].checkbox-no-label {
color: @red; color: @red;
} }
.icon-job-none { .icon-job-none,
.icon-job-pending,
.icon-job-waiting,
.icon-job-new {
color: @grey; color: @grey;
opacity: 0.45; opacity: 0.45;
} }
.icon-job-none:before {
content: "\f10c";
}
.icon-schedule-enabled-true:before { .icon-schedule-enabled-true:before {
content: "\f04c"; content: "\f04c";
} }
@@ -1048,14 +1053,11 @@ input[type="checkbox"].checkbox-no-label {
.pagination li a { .pagination li a {
font-size: 12px; font-size: 12px;
} }
.list-table-container { /*.list-table-container {
min-height: 338px; min-height: 338px;
} }*/
} }
.job-list-target {
min-height: 445px;
}
/* Inventory job status badge */ /* Inventory job status badge */
.failures-true { .failures-true {
background-color: @red; background-color: @red;

View File

@@ -88,3 +88,29 @@ table.ui-datepicker-calendar {
.ui-dialog-content.ui-widget-content { .ui-dialog-content.ui-widget-content {
padding-top: 20px; padding-top: 20px;
} }
.ui-widget-content {
a,
a:visited,
a:active {
color: @blue;
text-decoration: none;
}
a:hover,
a:focus {
color: @blue-dark;
text-decoration: none;
}
.red-txt,
a.red-txt:visited,
a.red-txt:hover,
a.red-txt:active {
color: @red;
}
.dropdown-menu>li>a {
color: @black;
}
}

View File

@@ -10,7 +10,13 @@
#logviewer-modal-dialog { #logviewer-modal-dialog {
textarea { textarea {
overflow: auto; overflow: scroll;
}
pre {
overflow: scroll;
word-wrap: normal;
word-break: normal;
white-space: pre-wrap;
} }
} }

View File

@@ -162,9 +162,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
} }
}) })
.error(function (data, status) { .error(function (data, status) {
Wait('stop'); ProcessErrors(scope, data, status, null, { hdr: 'Error!',
ProcessErrors(scope, data, status, null, {
hdr: 'Error!',
msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status msg: 'Failed to get inventory tree for: ' + inventory_id + '. GET returned: ' + status
}); });
}); });
@@ -309,10 +307,10 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
html += "<div class=\"modal-body\">\n"; html += "<div class=\"modal-body\">\n";
if (target.id === 1) { if (target.id === 1) {
html += "<p>Are you sure you want to move group " + inbound.name + " to the top level?</p>"; html += "<div class=\"alert alert-info\">Are you sure you want to move group " + inbound.name + " to the top level?</div>";
} else if (inbound.parent === 0) { } else if (inbound.parent === 0) {
html += "<p>Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " + html += "<div class=\"alert alert-info\">Are you sure you want to move group " + inbound.name + " from the top level and make it a child of " +
target.name + "?</p>"; target.name + "?</div>";
} else { } else {
html += "<div class=\"text-center\">\n"; html += "<div class=\"text-center\">\n";
html += "<p>Would you like to copy or move group <em>" + inbound.name + "</em> to group <em>" + target.name + "</em>?</p>\n"; html += "<p>Would you like to copy or move group <em>" + inbound.name + "</em> to group <em>" + target.name + "</em>?</p>\n";
@@ -502,7 +500,7 @@ angular.module('InventoryTree', ['Utilities', 'RestServices', 'GroupsHelper', 'P
html += "<h3>Copy Host</h3>\n"; html += "<h3>Copy Host</h3>\n";
html += "</div>\n"; html += "</div>\n";
html += "<div class=\"modal-body\">\n"; html += "<div class=\"modal-body\">\n";
html += "<p>Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?</p>'; html += "<div class=\"alert alert-info\">Are you sure you want to copy host " + host.name + ' to group ' + target.name + '?</div>';
html += "</div>\n"; html += "</div>\n";
html += "<div class=\"modal-footer\">\n"; html += "<div class=\"modal-footer\">\n";
html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">No</a>\n"; html += "<a href=\"#\" data-target=\"#prompt-modal\" data-dismiss=\"modal\" class=\"btn btn-default\">No</a>\n";

View File

@@ -79,6 +79,7 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
return function (hdr, msg, cls, action, secondAlert, disableButtons) { return function (hdr, msg, cls, action, secondAlert, disableButtons) {
var scope = $rootScope.$new(), e; var scope = $rootScope.$new(), e;
if (secondAlert) { if (secondAlert) {
$('#alert2-modal-msg').attr({ "class": "alert" });
scope.alertHeader2 = hdr; scope.alertHeader2 = hdr;
scope.alertBody2 = msg; scope.alertBody2 = msg;
scope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger scope.alertClass2 = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
@@ -102,9 +103,11 @@ angular.module('Utilities', ['RestServices', 'Utilities'])
} }
}); });
} else { } else {
$('#alert-modal-msg').attr({ "class": "alert" });
scope.alertHeader = hdr; scope.alertHeader = hdr;
scope.alertBody = msg; scope.alertBody = msg;
scope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger scope.alertClass = (cls) ? cls : 'alert-danger'; //default alert class is alert-danger
//console.log('msg: ' + msg + ' cls: ' + cls);
e = angular.element(document.getElementById('alert-modal')); e = angular.element(document.getElementById('alert-modal'));
$compile(e)(scope); $compile(e)(scope);
$('#alert-modal').modal({ $('#alert-modal').modal({

View File

@@ -264,6 +264,7 @@ angular.module('GeneratorHelpers', [])
html += "<a href=\"\" class=\"toggle"; html += "<a href=\"\" class=\"toggle";
html += "\" "; html += "\" ";
html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : ""; html += (field.ngDisabled) ? "ng-disabled=\"" + field.ngDisabled + "\" " : "";
html += (field.ngShow) ? "ng-show=\"" + field.ngShow + "\" " : "";
html += "data-toggle=\"dropdown\" "; html += "data-toggle=\"dropdown\" ";
html += ">"; html += ">";
html += (field.icon) ? Icon(field.icon) : ""; html += (field.icon) ? Icon(field.icon) : "";
@@ -448,7 +449,7 @@ angular.module('GeneratorHelpers', [])
options = params.options, options = params.options,
base = params.base, base = params.base,
field = list.fields[fld], field = list.fields[fld],
html = '', cap; html = '';
if (field.type !== undefined && field.type === 'DropDown') { if (field.type !== undefined && field.type === 'DropDown') {
html = DropDown(params); html = DropDown(params);
@@ -493,21 +494,17 @@ angular.module('GeneratorHelpers', [])
} }
// Start the Link // Start the Link
if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref) && if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref || field.awToolTip || field.awPopOver) &&
options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) { options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) {
cap = false; html += "<a ";
if (field.linkTo) { if (field.linkTo) {
html += "<a href=\"" + field.linkTo + "\" "; html += "href=\"" + field.linkTo + "\" ";
cap = true;
} else if (field.ngClick) { } else if (field.ngClick) {
html += "<a href=\"\"" + Attr(field, 'ngClick') + " "; html += "href=\"\"" + Attr(field, 'ngClick') + " ";
cap = true;
} else if (field.ngHref) { } else if (field.ngHref) {
html += "<a ng-href=\"" + field.ngHref + "\" "; html += "ng-href=\"" + field.ngHref + "\" ";
cap = true;
} else if (field.link || (field.key && (field.link === undefined || field.link))) { } else if (field.link || (field.key && (field.link === undefined || field.link))) {
html += "<a href=\"#/" + base + "/{{" + list.iterator + ".id }}\" "; html += "href=\"#/" + base + "/{{" + list.iterator + ".id }}\" ";
cap = true;
} }
if (field.awDroppable) { if (field.awDroppable) {
html += Attr(field, 'awDroppable'); html += Attr(field, 'awDroppable');
@@ -523,10 +520,15 @@ angular.module('GeneratorHelpers', [])
} }
if (field.awToolTip) { if (field.awToolTip) {
html += Attr(field, 'awToolTip'); html += Attr(field, 'awToolTip');
html += (field.dataPlacement) ? Attr(field, 'dataPlacement') : ""; html += (field.dataPlacement && !field.awPopOver) ? Attr(field, 'dataPlacement') : "";
html += (field.dataTipWatch) ? Attr(field, 'dataTipWatch') : ""; html += (field.dataTipWatch) ? Attr(field, 'dataTipWatch') : "";
html += (field.awTipPlacement) ? Attr(field, 'awTipPlacement') : "";
} }
html += (cap) ? ">" : ""; if (field.awPopOver) {
html += "aw-pop-over=\"" + field.awPopOver + "\" ";
html += (field.dataPlacement) ? "data-placement=\"" + field.dataPlacement + "\" " : "";
}
html += ">";
} }
// Add icon: // Add icon:
@@ -563,7 +565,7 @@ angular.module('GeneratorHelpers', [])
//} //}
// close the link // close the link
if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref) && if ((field.key || field.link || field.linkTo || field.ngClick || field.ngHref || field.awToolTip || field.awPopOver) &&
options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) { options.mode !== 'lookup' && options.mode !== 'select' && !field.noLink && !field.ngBindHtml) {
html += "</a>"; html += "</a>";
} }

View File

@@ -0,0 +1,3 @@
<div class="tab-pane" id="job_events">
<div ng-cloak id="htmlTemplate"></div>
</div>

View File

@@ -0,0 +1,3 @@
<div class="tab-pane" id="job_host_summaries">
<div ng-cloak id="htmlTemplate"></div>
</div>

View File

@@ -33,6 +33,7 @@
</div> </div>
</div> </div>
</div> </div>
<div id="schedule-dialog-target"></div> <div id="schedule-dialog-target"></div>
<div ng-include="'/static/partials/logviewer.html'"></div>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,8 @@
<li><a href="#stdout" id="stdout-link" data-toggle="tab" ng-click="toggleTab($event, 'stdout-link', 'logview-tabs')">Standard Out</a></li> <li><a href="#stdout" id="stdout-link" data-toggle="tab" ng-click="toggleTab($event, 'stdout-link', 'logview-tabs')">Standard Out</a></li>
<li><a href="#traceback" id="traceback-link" data-toggle="tab" ng-click="toggleTab($event, 'traceback-link', 'logview-tabs')">Traceback</a></li> <li><a href="#traceback" id="traceback-link" data-toggle="tab" ng-click="toggleTab($event, 'traceback-link', 'logview-tabs')">Traceback</a></li>
<li><a href="#options" id="options-link" data-toggle="tab" ng-click="toggleTab($event, 'options-link', 'logview-tabs')">Options</a></li> <li><a href="#options" id="options-link" data-toggle="tab" ng-click="toggleTab($event, 'options-link', 'logview-tabs')">Options</a></li>
<li><a href="#variables" id="variables-link" data-toggle="tab" ng-click="toggleTab($event, 'variable-link', 'logview-tabs')">Extra Vars</a></li>
<li><a href="#source-variables" id="source-variables-link" data-toggle="tab" ng-click="toggleTab($event, 'source-variable-link', 'logview-tabs')">Source Vars</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="status"> <div class="tab-pane active" id="status">
@@ -19,5 +21,11 @@
<div class="tab-pane" id="options"> <div class="tab-pane" id="options">
<div id="options-form-container"></div> <div id="options-form-container"></div>
</div> </div>
<div class="tab-pane" id="variables">
<div id="variables-container"></div>
</div>
<div class="tab-pane" id="source-variables">
<div id="source-container"></div>
</div>
</div> </div>
</div> </div>

View File

@@ -331,7 +331,7 @@
<h3 ng-bind="alertHeader"></h3> <h3 ng-bind="alertHeader"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="alert" ng-class="alertClass" ng-bind-html="alertBody"></div> <div id="alert-modal-msg" class="alert" ng-class="alertClass" ng-bind-html="alertBody"></div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" id="alert_ok_btn" class="btn btn-primary">OK</a> <a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" id="alert_ok_btn" class="btn btn-primary">OK</a>
@@ -349,7 +349,7 @@
<h3 ng-bind="alertHeader2"></h3> <h3 ng-bind="alertHeader2"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="alert" ng-class="alertClass2" ng-bind-html="alertBody2"></div> <div id="alert2-modal-msg" class="alert" ng-class="alertClass2" ng-bind-html="alertBody2"></div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" id="alert2_ok_btn" class="btn btn-primary">OK</a> <a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" id="alert2_ok_btn" class="btn btn-primary">OK</a>