diff --git a/lib/ui/static/css/ansible-ui.css b/lib/ui/static/css/ansible-ui.css
index d0aafec9b5..e053b0c85e 100644
--- a/lib/ui/static/css/ansible-ui.css
+++ b/lib/ui/static/css/ansible-ui.css
@@ -16,6 +16,10 @@
padding-top: 40px;
}
+ hr {
+ border-color: #e3e3e3;
+ }
+
.container-fluid {
min-height: 700px ;
}
@@ -175,6 +179,13 @@
display: inline-block;
font-size: 18px;
margin-left: 15px;
+ min-width: 30px;
+ }
+
+ .search-widget label {
+ display:inline-block;
+ vertical-align: middle;
+ padding-right: 15px;
}
.nav-path {
@@ -241,7 +252,7 @@
.list-actions {
display: inline-block;
vertical-align: top;
- margin-left: 15px;
+ margin-left: 10px;
margin-top: 3px;
}
/* End Display list actions */
@@ -256,15 +267,20 @@
background-color: #fff;
}
- .job-error, .job-failed {
+ .job-error, .job-failed,
+ input[type="text"].job-failed,
+ input[type="text"].job-error
+ {
color: #da4f49;
}
- .job-new {
+ .job-new, input[type="text"].job-new {
color: #778899;
}
- .job-pending, .job-running {
+ .job-pending, .job-running, .job-success,
+ input[type="text"].job-success
+ {
color: #5bb75b;
}
@@ -273,5 +289,28 @@
font-weight: bold;
padding-left: 15px;
}
+
+ #job_events label {
+ margin-right: 10px;
+ }
+
+ #job_events {
+ text-align: center;
+ }
+
+ #job_events_items_form {
+ margin-top: 15px;
+ }
+
+ .form-items .search-widget {
+ margin-top: 15px;
+ }
+
+ .form-items .item-count {
+ display: inline-block;
+ font-size: small;
+ margin-top: 25px;
+ }
+
/* End Jobs Page */
diff --git a/lib/ui/static/js/app.js b/lib/ui/static/js/app.js
index aab51d05fb..a781080b77 100644
--- a/lib/ui/static/js/app.js
+++ b/lib/ui/static/js/app.js
@@ -52,7 +52,7 @@ angular.module('ansible', [
.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/jobs',
- { templateUrl: urlPrefix + 'partials/jobs.html', controller: JobsList }).
+ { templateUrl: urlPrefix + 'partials/jobs.html', controller: JobsListCtrl }).
when('/jobs/:id',
{ templateUrl: urlPrefix + 'partials/jobs.html', controller: JobsEdit }).
diff --git a/lib/ui/static/js/controllers/JobTemplates.js b/lib/ui/static/js/controllers/JobTemplates.js
index b8fd18281a..345dd149d7 100644
--- a/lib/ui/static/js/controllers/JobTemplates.js
+++ b/lib/ui/static/js/controllers/JobTemplates.js
@@ -167,7 +167,7 @@ function JobTemplatesList ($scope, $rootScope, $location, $log, $routeParams, Re
Rest.setUrl(data.related.start);
Rest.post()
.success( function(data, status, headers, config) {
- $location.path(GetBasePath('jobs'));
+ $location.path('/jobs');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
diff --git a/lib/ui/static/js/controllers/Jobs.js b/lib/ui/static/js/controllers/Jobs.js
index 7834e718a8..4582f01f36 100644
--- a/lib/ui/static/js/controllers/Jobs.js
+++ b/lib/ui/static/js/controllers/Jobs.js
@@ -10,9 +10,9 @@
'use strict';
-function JobsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList,
- GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
- ClearScope, ProcessErrors, GetBasePath, LookUpInit)
+function JobsListCtrl ($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList,
+ GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller,
+ ClearScope, ProcessErrors, GetBasePath, LookUpInit)
{
ClearScope('htmlTemplate');
var list = JobList;
@@ -33,16 +33,73 @@ function JobsList ($scope, $rootScope, $location, $log, $routeParams, Rest, Aler
}
scope.viewEvents = function(id) {
- console.log('headed to: ' + $location.path() + '/' + id + '/job_events');
$location.path($location.path() + '/' + id + '/job_events');
}
+
+ scope.deleteJob = function(id, name) {
+ Rest.setUrl(defaultUrl + id + '/');
+ Rest.get()
+ .success( function(data, status, headers, config) {
+
+ var url, action_label, restcall, hdr;
+
+ if (data.status == 'pending') {
+ url = data.related.cancel;
+ action_label = 'cancel';
+ hdr = 'Cancel Job';
+ }
+ else {
+ url = defaultUrl + id + '/';
+ action_label = 'delete';
+ hdr = 'Delete Job';
+ }
+
+ var action = function() {
+ Rest.setUrl(url);
+ if (action_label == 'cancel') {
+ Rest.post()
+ .success( function(data, status, headers, config) {
+ $('#prompt-modal').modal('hide');
+ scope.search(list.iterator);
+ })
+ .error( function(data, status, headers, config) {
+ $('#prompt-modal').modal('hide');
+ ProcessErrors(scope, data, status, null,
+ { hdr: 'Error!', msg: 'Call to ' + url + ' failed. POST returned status: ' + status });
+ });
+ }
+ else {
+ Rest.delete()
+ .success( function(data, status, headers, config) {
+ $('#prompt-modal').modal('hide');
+ scope.search(list.iterator);
+ })
+ .error( function(data, status, headers, config) {
+ $('#prompt-modal').modal('hide');
+ ProcessErrors(scope, data, status, null,
+ { hdr: 'Error!', msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
+ });
+ }
+ };
+
+ Prompt({ hdr: hdr,
+ body: 'Are you sure you want to ' + action_label + ' job ' + id + '?',
+ action: action
+ });
+ })
+ .error( function(data, status, headers, config) {
+ ProcessErrors(scope, data, status, null,
+ { hdr: 'Error!', msg: 'Failed to get job details. GET returned status: ' + status });
+ });
+
+ }
}
-JobsList.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
- 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
- 'ProcessErrors','GetBasePath', 'LookUpInit'
- ];
+JobsListCtrl.$inject = [ '$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList',
+ 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
+ 'ProcessErrors','GetBasePath', 'LookUpInit'
+ ];
function JobsEdit ($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm,
@@ -274,7 +331,8 @@ JobsEdit.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$
function JobEvents ($scope, $rootScope, $compile, $location, $log, $routeParams, JobEventForm,
- GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, GetBasePath)
+ GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ClearScope, SearchInit,
+ PaginateInit, GetBasePath)
{
ClearScope('htmlTemplate'); //Garbage collection. Don't leave behind any listeners/watchers from the prior
//scope.
@@ -285,31 +343,57 @@ function JobEvents ($scope, $rootScope, $compile, $location, $log, $routeParams,
var scope = GenerateForm.inject(form, {mode: 'edit', related: true});
generator.reset();
- var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events';
+ var defaultUrl = GetBasePath('jobs') + $routeParams.id + '/job_events/';
var base = $location.path().replace(/^\//,'').split('/')[0];
var master = {};
var id = $routeParams.id;
var relatedSets = {};
-
+ if (scope.PostRefreshRemove){
+ scope.PostRefreshRemove();
+ }
+ scope.PostRefreshRemove = scope.$on('PostRefresh', function() {
+ var results = scope[form.items.event.set][0];
+ // Disable Next/Prev buttons when we rich the end/beginning of array
+ scope[form.items.event.iterator + 'NextUrlDisable'] = (scope[form.items.event.iterator + 'NextUrl']) ? "" : "disabled";
+ scope[form.items.event.iterator + 'PrevUrlDisable'] = (scope[form.items.event.iterator + 'PrevUrl']) ? "" : "disabled";
+
+ // Set the scope input field values
+ for (var fld in form.items.event.fields) {
+ if (fld == 'event_data') {
+ scope.event_data = JSON.stringify(results[fld]);
+ }
+ else {
+ if (results[fld]) {
+ scope[fld] = results[fld];
+ }
+ }
+ }
+ scope['event_status'] = (results.failed) ? 'failed' : 'success';
+ });
+
// Retrieve detail record and prepopulate the form
Rest.setUrl(defaultUrl);
Rest.get({ params: {page_size: 1} })
.success( function(data, status, headers, config) {
- LoadBreadCrumbs({ path: '/organizations/' + id, title: data.name });
+ var results = data.results[0];
+ scope[form.items.event.iterator + 'NextUrl'] = data.next;
+ scope[form.items.event.iterator + 'PrevUrl'] = data.previous;
+ scope[form.items.event.iterator + 'Count'] = data.count;
+ LoadBreadCrumbs({ path: '/jobs/' + id, title: results["summary_fields"].job.name });
for (var fld in form.fields) {
- if (data[fld]) {
- scope[fld] = data[fld];
+ if (results[fld]) {
+ scope[fld] = results[fld];
+ }
+ if (form.fields[fld].sourceModel && results.summary_fields[form.fields[fld].sourceModel]) {
+ scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
+ results.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
}
}
- for (var fld in form.items) {
- if (data[fld]) {
- scope[fld] = data[fld];
- }
- }
- scope['event_satus'] = (data.failed) ? 'failed' : 'success';
- scope.next = data.next;
- scope.previous = data.previous;
+ scope[form.items.event.set] = data.results;
+ SearchInit({ scope: scope, set: form.items.event.set, list: form.items.event, iterator: form.items.event.iterator, url: defaultUrl });
+ PaginateInit({ scope: scope, list: form.items.event, iterator: form.items.event.iterator, url: defaultUrl , pageSize: 1 });
+ scope.$emit('PostRefresh');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, form,
@@ -319,5 +403,6 @@ function JobEvents ($scope, $rootScope, $compile, $location, $log, $routeParams,
}
JobEvents.$inject = [ '$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobEventForm',
- 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'GetBasePath' ];
+ 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ClearScope', 'SearchInit',
+ 'PaginateInit', 'GetBasePath' ];
diff --git a/lib/ui/static/js/forms/JobEvents.js b/lib/ui/static/js/forms/JobEvents.js
index 566bdfbcc5..05083146c6 100644
--- a/lib/ui/static/js/forms/JobEvents.js
+++ b/lib/ui/static/js/forms/JobEvents.js
@@ -13,26 +13,27 @@ angular.module('JobEventFormDefinition', [])
editTitle: '{{ name }} Events', //Legend in edit mode
name: 'job_events',
well: true,
- formInline: true,
+ fieldsAsHeader: true,
fields: {
job: {
- label: 'Job ID',
+ label: 'Job',
type: 'text',
+ class: 'span1',
readonly: true
},
- name: {
- label: 'Name',
+ job_name: {
type: 'text',
sourceModel: 'job',
sourceField: 'name',
+ class: 'span5',
readonly: true
},
- description: {
- label: 'Description',
+ job_description: {
type: 'text',
sourceModel: 'job',
sourceField: 'description',
+ class: 'span5',
readonly: true
}
},
@@ -43,29 +44,54 @@ angular.module('JobEventFormDefinition', [])
items: {
event: {
+ set: 'job_events',
+ iterator: 'job_event',
label: 'Event',
- type: 'text',
- readonly: true
- },
- created: {
- label: 'Event Timestamp',
- type: 'text',
- readonly: true
- },
- event_status: {
- label: 'Event Status \{\{ status \}\} ',
- type: 'text',
- readonly: true,
- control: false
- },
- event_data: {
- label: 'Event Data',
- type: 'textarea',
- class: 'span12',
- rows: 10
- }
+ fields: {
+ id: {
+ label: 'Event ID',
+ type: 'text',
+ readonly: true,
+ class: 'span2',
+ key: true,
+ searchType: 'int'
+ },
+ created: {
+ label: 'Event Timestamp',
+ type: 'text',
+ readonly: true,
+ class: 'span4'
+ },
+ event: {
+ label: 'Event',
+ type: 'text',
+ readonly: true
+ },
+ host: {
+ label: 'Host',
+ type: 'text',
+ readonly: true
+ },
+ event_status: {
+ label: 'Event Status',
+ type: 'text',
+ class: 'job-\{\{ event_status \}\}',
+ readonly: true,
+ searchField: 'failed',
+ searchType: 'boolean',
+ searchOptions: [{ name: "success", value: 0 }, { name: "failed", value: 1 }],
+ },
+ event_data: {
+ label: 'Event Data',
+ type: 'textarea',
+ class: 'span12',
+ rows: 10,
+ readonly: true
+ }
+ }
+ }
},
-
+
related: { //related colletions (and maybe items?)
}
diff --git a/lib/ui/static/js/helpers/JobTemplate.js b/lib/ui/static/js/helpers/JobTemplate.js
index 58903dd454..6e54500219 100644
--- a/lib/ui/static/js/helpers/JobTemplate.js
+++ b/lib/ui/static/js/helpers/JobTemplate.js
@@ -24,7 +24,7 @@ angular.module('JobTemplateHelper', [ 'RestServices', 'Utilities', 'CredentialFo
Rest.setUrl(start_url);
Rest.post(pswd)
.success( function(data, status, headers, config) {
- $location.path(GetBasPath('jobs'));
+ $location.path('/jobs');
})
.error( function(data, status, headers, config) {
ProcessErrors(scope, data, status, null,
@@ -37,6 +37,7 @@ angular.module('JobTemplateHelper', [ 'RestServices', 'Utilities', 'CredentialFo
// Add the password field
field = form.fields[passwords[i]];
fld = passwords[i];
+ scope[fld] = '';
html += "
\n";
html += "
' + field.label + ' ' + "\n";
html += "
\n";
@@ -57,6 +58,7 @@ angular.module('JobTemplateHelper', [ 'RestServices', 'Utilities', 'CredentialFo
// Add the related confirm field
fld = field.associated;
field = form.fields[field.associated];
+ scope[fld] = '';
html += "
\n";
html += "
' + field.label + ' ' + "\n";
html += "
\n";
diff --git a/lib/ui/static/js/helpers/paginate.js b/lib/ui/static/js/helpers/paginate.js
index c850a436ad..7534101b52 100644
--- a/lib/ui/static/js/helpers/paginate.js
+++ b/lib/ui/static/js/helpers/paginate.js
@@ -20,32 +20,44 @@ angular.module('PaginateHelper', ['RefreshHelper'])
var scope = params.scope;
var list = params.list;
+ var iterator = (params.iterator) ? params.iterator : list.iterator;
var url = params.url;
var mode = (params.mode) ? params.mode : null;
- scope[list.iterator + 'Page'] = 0;
+ scope[iterator + 'Page'] = 0;
- if (mode == 'lookup') {
- scope[list.iterator + 'PageSize'] = 5;
+ if (params.pageSize) {
+ scope[iterator + 'PageSize'] = params.pageSize;
+ }
+ else if (mode == 'lookup') {
+ scope[iterator + 'PageSize'] = 5;
}
else {
- scope[list.iterator + 'PageSize'] = 20;
+ scope[iterator + 'PageSize'] = 20;
}
scope.nextSet = function(set, iterator) {
- scope[iterator + 'Page']++;
- Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'NextUrl'] });
+ if (scope[iterator + 'NextUrl']) {
+ scope[iterator + 'Page']++;
+ Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'NextUrl'] });
+ }
};
scope.prevSet = function(set, iterator) {
- scope[iterator + 'Page']--;
- Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'PrevUrl'] });
+ if (scope[iterator + 'PrevUrl']) {
+ scope[iterator + 'Page']--;
+ Refresh({ scope: scope, set: set, iterator: iterator, url: scope[iterator + 'PrevUrl'] });
+ }
};
scope.changePageSize = function(set, iterator) {
// Called when a new page size is selected
scope[iterator + 'Page'] = 0;
- url += (scope[iterator + 'SearchParams']) ? scope[iterator + 'SearchParams'] : '';
+ console.log(url);
+ url = url.replace(/\/\?.*$/,'/');
+ console.log(url);
+ url += (scope[iterator + 'SearchParams']) ? scope[iterator + 'SearchParams'] + '&page_size=' + scope[iterator + 'PageSize' ] :
+ '?page_size=' + scope[iterator + 'PageSize' ];
Refresh({ scope: scope, set: set, iterator: iterator, url: url });
}
}
diff --git a/lib/ui/static/js/helpers/refresh.js b/lib/ui/static/js/helpers/refresh.js
index 8f43c24b98..f7aec7994f 100644
--- a/lib/ui/static/js/helpers/refresh.js
+++ b/lib/ui/static/js/helpers/refresh.js
@@ -22,7 +22,6 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities'])
var set = params.set;
var iterator = params.iterator;
var url = params.url;
-
Rest.setUrl(url);
Rest.get()
.success( function(data, status, headers, config) {
@@ -32,6 +31,7 @@ angular.module('RefreshHelper', ['RestServices', 'Utilities'])
scope[iterator + 'PageCount'] = Math.ceil((data.count / scope[iterator + 'PageSize']));
scope[iterator + 'SearchSpin'] = false;
scope[set] = data['results'];
+ scope.$emit('PostRefresh');
})
.error ( function(data, status, headers, config) {
scope[iterator + 'SearchSpin'] = false;
diff --git a/lib/ui/static/js/helpers/search.js b/lib/ui/static/js/helpers/search.js
index 50e4935b0c..736616f9c2 100644
--- a/lib/ui/static/js/helpers/search.js
+++ b/lib/ui/static/js/helpers/search.js
@@ -21,12 +21,12 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
return function(params) {
var scope = params.scope;
- var set = params.set;
+ var set = params.set;
var defaultUrl = params.url;
var list = params.list;
- var iterator = list.iterator;
+ var iterator = (params.iterator) ? params.iterator : list.iterator;
var default_order;
-
+
// Set default values
for (fld in list.fields) {
if (list.fields[fld].key) {
@@ -40,11 +40,34 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
scope[iterator + 'SearchTypeLabel'] = 'Contains';
scope[iterator + 'SearchParams'] = '';
scope[iterator + 'SearchValue'] = '';
+ scope[iterator + 'SelectShow'] = false; // show/hide the Select
+ scope[iterator + 'HideSearchType'] = false;
+
+ var f = scope[iterator + 'SearchField']
+ if (list.fields[f].searchType && list.fields[f].searchType == 'boolean') {
+ scope[iterator + 'SelectShow'] = true;
+ scope[iterator + 'SearchSelectOpts'] = list.fields[fld].searchOptions;
+ }
+ if (list.fields[f].searchType && list.fields[f].searchType == 'int') {
+ scope[iterator + 'HideSearchType'] = true;
+ }
// Functions to handle search widget changes
scope.setSearchField = function(iterator, fld, label) {
scope[iterator + 'SearchFieldLabel'] = label;
scope[iterator + 'SearchField'] = fld;
+ scope[iterator + 'SearchValue'] = '';
+ scope[iterator + 'SelectShow'] = false;
+ scope[iterator + 'HideSearchType'] = false;
+
+ if (list.fields[fld].searchType && list.fields[fld].searchType == 'boolean') {
+ scope[iterator + 'SelectShow'] = true;
+ scope[iterator + 'SearchSelectOpts'] = list.fields[f].searchOptions;
+ }
+ if (list.fields[fld].searchType && list.fields[fld].searchType == 'int') {
+ scope[iterator + 'HideSearchType'] = true;
+ }
+
scope.search(iterator);
}
@@ -60,19 +83,37 @@ angular.module('SearchHelper', ['RestServices', 'Utilities', 'RefreshHelper'])
//
scope[iterator + 'SearchSpin'] = true;
var url = defaultUrl;
- if (scope[iterator + 'SearchValue'] != '' && scope[iterator + 'SearchValue'] != undefined) {
+ if ( (scope[iterator + 'SelectShow'] == false && scope[iterator + 'SearchValue'] != '' && scope[iterator + 'SearchValue'] != undefined) ||
+ (scope[iterator + 'SelectShow'] && scope[iterator + 'SearchSelectValue']) ) {
if (list.fields[scope[iterator + 'SearchField']].sourceModel) {
// handle fields whose source is a related model e.g. inventories.organization
scope[iterator + 'SearchParams'] = '?' + list.fields[scope[iterator + 'SearchField']].sourceModel + '__' +
- list.fields[scope[iterator + 'SearchField']].sourceField + '__' +
- scope[iterator + 'SearchType'] + '=' + escape(scope[iterator + 'SearchValue']);
- scope[iterator + 'SearchParams'] += (default_order) ? '&order_by=' + escape(default_order) : '';
+ list.fields[scope[iterator + 'SearchField']].sourceField + '__';
+ }
+ else if (list.fields[scope[iterator + 'SearchField']].searchField) {
+ scope[iterator + 'SearchParams'] = '?' + list.fields[scope[iterator + 'SearchField']].searchField + '__';
}
else {
- scope[iterator + 'SearchParams'] = '?' + scope[iterator + 'SearchField'] + '__' +
- scope[iterator + 'SearchType'] + '=' + escape(scope[iterator + 'SearchValue']);
- scope[iterator + 'SearchParams'] += (default_order) ? '&order_by=' + escape(default_order) : '';
+ scope[iterator + 'SearchParams'] = '?' + scope[iterator + 'SearchField'] + '__';
}
+
+ if ( list.fields[scope[iterator + 'SearchField']].searchType &&
+ (list.fields[scope[iterator + 'SearchField']].searchType == 'int' ||
+ list.fields[scope[iterator + 'SearchField']].searchType == 'boolean') ) {
+ scope[iterator + 'SearchParams'] += 'int=';
+ }
+ else {
+ scope[iterator + 'SearchParams'] += scope[iterator + 'SearchType'] + '=';
+ }
+
+ if ( list.fields[scope[iterator + 'SearchField']].searchType &&
+ list.fields[scope[iterator + 'SearchField']].searchType == 'boolean' ) {
+ scope[iterator + 'SearchParams'] += scope[iterator + 'SearchSelectValue'].value;
+ }
+ else {
+ scope[iterator + 'SearchParams'] += escape(scope[iterator + 'SearchValue']);
+ }
+ scope[iterator + 'SearchParams'] += (default_order) ? '&order_by=' + escape(default_order) : '';
}
else {
scope[iterator + 'SearchParams'] = '';
diff --git a/lib/ui/static/js/lists/Jobs.js b/lib/ui/static/js/lists/Jobs.js
index 87213869e9..9c877b1177 100644
--- a/lib/ui/static/js/lists/Jobs.js
+++ b/lib/ui/static/js/lists/Jobs.js
@@ -21,7 +21,8 @@ angular.module('JobsListDefinition', [])
id: {
label: 'Job ID',
key: true,
- desc: true
+ desc: true,
+ searchType: 'int'
},
created: {
label: 'Creation Date',
@@ -69,7 +70,7 @@ angular.module('JobsListDefinition', [])
title: 'Cancel',
icon: 'icon-minus-sign',
mode: 'all',
- ngClick: 'cancel(\{\{ job.id \}\})',
+ ngClick: 'deleteJob(\{\{ job.id \}\})',
class: 'btn-danger btn-mini',
awToolTip: 'Cancel job',
ngDisabled: "job.status == 'error' || job.status == 'failed'"
diff --git a/lib/ui/static/lib/ansible/form-generator.js b/lib/ui/static/lib/ansible/form-generator.js
index c7c88160a9..f8526e96bd 100644
--- a/lib/ui/static/lib/ansible/form-generator.js
+++ b/lib/ui/static/lib/ansible/form-generator.js
@@ -68,9 +68,9 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
}
this.setForm(form);
- element.html(this.build(options)); // Inject the html
- this.scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference
- // From here use 'scope' to manipulate the form, as the form is not in '$scope'
+ element.html(this.build(options)); // Inject the html
+ this.scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference
+ // From here use 'scope' to manipulate the form, as the form is not in '$scope'
$compile(element)(this.scope);
if ((!options.modal) && options.related) {
@@ -142,245 +142,258 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
});
},
+ headerField: function(fld, field, options) {
+ var html = '';
+ if (field.label) {
+ html += "
" + field.label + " \n";
+ }
+ html += "
\n";
+ return html;
+ },
+
buildField: function(fld, field, options) {
- var html='';
+ var html='';
- //Assuming horizontal form for now. This will need to be more flexible later.
+ //Assuming horizontal form for now. This will need to be more flexible later.
- //text fields
- if (field.type == 'text' || field.type == 'password' || field.type == 'email') {
- if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
- html += "
\n";
- html += "
';
- html += (field.icon) ? this.icon(field.icon) : "";
- html += field.label + ' ' + "\n";
- html += "
\n";
- html += (field.clear) ? "
\n" : "";
- if (field.control === null || field.control === undefined || field.control) {
- html += " ";
- if (field.clear) {
- html += " \n \n";
- html += "
\n";
- }
- if (field.ask) {
- html += " \n
Ask at runtime?";
- }
- html += "
\n";
- // Add error messages
- if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
- html += "
A value is required! \n";
- }
- if (field.type == "email") {
- html += "
A valid email address is required! \n";
- }
- if (field.awPassMatch) {
- html += "
Must match Password value \n";
- }
- html += "
\n";
- }
- html += "
\n";
- html += "
\n";
- }
+ //text fields
+ if (field.type == 'text' || field.type == 'password' || field.type == 'email') {
+ if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
+ html += "
\n";
+ html += "
';
+ html += (field.icon) ? this.icon(field.icon) : "";
+ html += field.label + ' ' + "\n";
+ html += "
\n";
+ html += (field.clear) ? "
\n" : "";
+ if (field.control === null || field.control === undefined || field.control) {
+ html += " ";
+ if (field.clear) {
+ html += " \n \n";
+ html += "
\n";
+ }
+ if (field.ask) {
+ html += " \n
Ask at runtime?";
+ }
+ html += "
\n";
+ // Add error messages
+ if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
+ html += "
A value is required! \n";
+ }
+ if (field.type == "email") {
+ html += "
A valid email address is required! \n";
+ }
+ if (field.awPassMatch) {
+ html += "
Must match Password value \n";
+ }
+ html += "
\n";
+ }
+ html += "
\n";
+ html += "
\n";
}
+ }
- //textarea fields
- if (field.type == 'textarea') {
- if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
- html += "
\n";
- html += "
' + field.label + ' ' + "\n";
- html += "
\n";
- html += " \n";
- // Add error messages
- if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
- html += "A value is required! \n";
- }
- html += " \n";
- html += "
\n";
- html += "
\n";
- }
- }
+ //textarea fields
+ if (field.type == 'textarea') {
+ if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
+ html += "
\n";
+ html += "
' + field.label + ' ' + "\n";
+ html += "
\n";
+ html += " \n";
+ // Add error messages
+ if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
+ html += "A value is required! \n";
+ }
+ html += " \n";
+ html += "
\n";
+ html += "
\n";
+ }
+ }
- //select field
- if (field.type == 'select') {
- if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
- html += "
\n";
- html += "
' + field.label + ' ' + "\n";
- html += "
\n";
- html += "\n";
- html += "Choose " + field.label + " \n";
- html += " \n";
- // Add error messages
- if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
- html += "A value is required! \n";
- }
- html += " \n";
- html += "
\n";
- html += "
\n";
- }
- }
+ //select field
+ if (field.type == 'select') {
+ if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
+ html += "
\n";
+ html += "
' + field.label + ' ' + "\n";
+ html += "
\n";
+ html += "\n";
+ html += "Choose " + field.label + " \n";
+ html += " \n";
+ // Add error messages
+ if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
+ html += "A value is required! \n";
+ }
+ html += " \n";
+ html += "
\n";
+ html += "
\n";
+ }
+ }
- //number field
- if (field.type == 'number') {
- if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
- html += "
\n";
- html += "
' + field.label + ' ' + "\n";
- html += "
\n";
- // Use 'text' rather than 'number' so that our integer directive works correctly
- html += " \n";
- // Add error messages
- if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
- html += "A value is required! \n";
- }
- if (field.integer) {
- html += "Must be an integer value \n";
- }
- if (field.min || field.max) {
- html += "Must be in range " + field.min + " to " +
- field.max + " \n";
- }
- html += " \n";
- html += "
\n";
- html += "
\n";
- }
- }
+ //number field
+ if (field.type == 'number') {
+ if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
+ html += "
\n";
+ html += "
' + field.label + ' ' + "\n";
+ html += "
\n";
+ // Use 'text' rather than 'number' so that our integer directive works correctly
+ html += " \n";
+ // Add error messages
+ if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
+ html += "A value is required! \n";
+ }
+ if (field.integer) {
+ html += "Must be an integer value \n";
+ }
+ if (field.min || field.max) {
+ html += "Must be in range " + field.min + " to " +
+ field.max + " \n";
+ }
+ html += " \n";
+ html += "
\n";
+ html += "
\n";
+ }
+ }
- //checkbox
- if (field.type == 'checkbox') {
- if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
- html += "
\n";
- html += "
\n";
- html += "
";
- html += " " + field.label + "\n";
- html += " \n";
- html += "
\n";
+ //checkbox
+ if (field.type == 'checkbox') {
+ if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) {
+ html += "
\n";
+ html += "
\n";
+ html += "";
+ html += " " + field.label + "\n";
+ html += " \n";
+ html += " \n";
- html += "
\n";
- html += "
\n";
- }
- }
+ html += "
\n";
+ html += "
\n";
+ }
+ }
- if (field.type == 'hidden') {
- if ( (options.mode == 'edit' && field.includeOnEdit) ||
- (options.mode == 'add' && field.includeOnAdd) ) {
- html += "
";
- }
- }
+ if (field.type == 'hidden') {
+ if ( (options.mode == 'edit' && field.includeOnEdit) ||
+ (options.mode == 'add' && field.includeOnAdd) ) {
+ html += "
";
+ }
+ }
- //lookup type fields
- if (field.type == 'lookup') {
- html += "
\n";
- html += "
' + field.label + ' ' + "\n";
- html += "
\n";
- html += "
\n";
- html += " \n";
- html += " \n";
- html += "
\n";
- // Add error messages
- if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
- html += "
A value is required! \n";
- }
- html += "
Value not found \n";
- html += "
\n";
- html += "
\n";
- html += "
\n";
- }
+ //lookup type fields
+ if (field.type == 'lookup') {
+ html += "
\n";
+ html += "
' + field.label + ' ' + "\n";
+ html += "
\n";
+ html += "
\n";
+ html += " \n";
+ html += " \n";
+ html += "
\n";
+ // Add error messages
+ if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) {
+ html += "
A value is required! \n";
+ }
+ html += "
Value not found \n";
+ html += "
\n";
+ html += "
\n";
+ html += "
\n";
+ }
- return html;
+ return html;
},
build: function(options) {
@@ -406,91 +419,102 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
html += "\n\n
\n";
}
- // Start the well
- if ( this.has('well') ) {
+ if (this.form.fieldsAsHeader) {
html += "
\n";
- }
-
- html += "
\n";
-
- if ( this.has('well') ) {
+ html += "\n";
html += "
\n";
}
-
+ else {
+ // Start the well
+ if ( this.has('well') ) {
+ html += "
\n";
+ }
+
+ html += "
' + "\n";
+ html += "{{ flashMessage }}
\n";
+
+ var field;
+ if (this.form.twoColumns) {
+ html += "\n";
+ html += "
\n";
+ for (var fld in this.form.fields) {
+ field = this.form.fields[fld];
+ if (field.column == 1) {
+ html += this.buildField(fld, field, options);
+ }
+ }
+ html += "
\n";
+ html += "
\n";
+ for (var fld in this.form.fields) {
+ field = this.form.fields[fld];
+ if (field.column == 2) {
+ html += this.buildField(fld, field, options);
+ }
+ }
+ html += "
\n";
+ html += "
\n";
+ }
+ else {
+ // original, single-column form
+ for (var fld in this.form.fields) {
+ var field = this.form.fields[fld];
+ html += this.buildField(fld, field, options);
+ }
+ }
+
+ //buttons
+ if (!this.modal) {
+ if (this.has('buttons')) {
+ html += "\n";
+ html += "
\n";
+ }
+ for (var btn in this.form.buttons) {
+ var button = this.form.buttons[btn];
+ //button
+ html += "";
+ if (button.icon) {
+ html += this.icon(button.icon);
+ }
+ html += button.label + " \n";
+ }
+ if (this.has('buttons')) {
+ html += "
\n";
+ html += "
\n";
+ }
+ html += " \n";
+ }
+
+ if ( this.has('well') ) {
+ html += "
\n";
+ }
+ }
+
if ((!this.modal && this.form.statusFields)) {
// Add status fields section (used in Jobs form)
html += "
\n";
@@ -500,6 +524,35 @@ angular.module('FormGenerator', ['GeneratorHelpers'])
}
html += "
\n";
}
+
+ if ((!this.modal && this.form.items)) {
+ for (itm in this.form.items) {
+ html += "
\n";
+ html += SearchWidget({ iterator: this.form.items[itm].iterator, template: this.form.items[itm], mini: false, label: 'Filter Events'});
+ html += "
Viewing" + " \{\{ " + this.form.items[itm].iterator + "Page + 1 \}\} of " +
+ "\{\{ " + this.form.items[itm].iterator + "Count \}\}
\n";
+ html += "
\n";
+ html += "\n";
+ html += "
' + "\n";
+ for (var fld in this.form.items[itm].fields) {
+ var field = this.form.items[itm].fields[fld];
+ html += this.buildField(fld, field, options);
+ }
+ html += " \n";
+ html += "\n";
+ html += "
\n";
+ }
+ }
if ((!this.modal) && options.related && this.form.related) {
html += this.buildCollections();
diff --git a/lib/ui/static/lib/ansible/generator-helpers.js b/lib/ui/static/lib/ansible/generator-helpers.js
index 335a25deed..81d6292e49 100644
--- a/lib/ui/static/lib/ansible/generator-helpers.js
+++ b/lib/ui/static/lib/ansible/generator-helpers.js
@@ -16,9 +16,11 @@ angular.module('GeneratorHelpers', [])
var iterator = params.iterator;
var form = params.template;
var useMini = params.mini;
+ var label = (params.label) ? params.label : null;
var html= '';
html += "
\n";
return html;
diff --git a/lib/ui/static/lib/ansible/list-generator.js b/lib/ui/static/lib/ansible/list-generator.js
index 6bc9670a44..5007c42570 100644
--- a/lib/ui/static/lib/ansible/list-generator.js
+++ b/lib/ui/static/lib/ansible/list-generator.js
@@ -140,7 +140,7 @@ angular.module('ListGenerator', ['GeneratorHelpers',])
if (list.actions[action].mode == 'all' || list.actions[action].mode == options.mode) {
if ( (list.basePaths == undefined) || (list.basePaths && list.basePaths.indexOf(base) > -1) ) {
html += "
" + this.icon(list.actions[action].icon) + " ";
}