diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 445ddf735b..f8da1e772f 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -9,10 +9,11 @@ 'use strict'; -angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', +angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'GroupsHelper', 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', 'PromptDialog', 'CredentialsListDefinition', 'InventoryTree', - 'InventoryStatusDefinition', 'VariablesHelper', 'SchedulesListDefinition', 'SourceFormDefinition', 'LogViewerHelper']) + 'InventoryStatusDefinition', 'VariablesHelper', 'SchedulesListDefinition', 'SourceFormDefinition', 'LogViewerHelper', + 'SchedulesHelper' ]) .factory('GetSourceTypeOptions', ['Rest', 'ProcessErrors', 'GetBasePath', function (Rest, ProcessErrors, GetBasePath) { @@ -335,13 +336,14 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G * */ .factory('ScheduleList', ['ScheduleEdit', 'SchedulesList', 'GenerateList', 'SearchInit', 'PaginateInit', 'Rest', 'PageRangeSetup', -'Wait', 'ProcessErrors', 'Find', 'ToggleSchedule', 'DeleteSchedule', +'Wait', 'ProcessErrors', 'Find', 'ToggleSchedule', 'DeleteSchedule', 'GetBasePath', 'SchedulesListInit', function(ScheduleEdit, SchedulesList, GenerateList, SearchInit, PaginateInit, Rest, PageRangeSetup, Wait, ProcessErrors, Find, -ToggleSchedule, DeleteSchedule) { +ToggleSchedule, DeleteSchedule, GetBasePath, SchedulesListInit) { return function(params) { var parent_scope = params.scope, + url = params.url, schedule_scope = parent_scope.$new(), - url, list; + list; // Clean up $('#schedules-list').hide().empty(); @@ -369,8 +371,16 @@ ToggleSchedule, DeleteSchedule) { $('#schedules-list').show(); - // Change later to use GetBasePath(base) - url = '/static/sample/data/schedules/inventory/data.json'; + if (schedule_scope.removePostRefresh) { + schedule_scope.removePostRefresh(); + } + schedule_scope.removePostRefresh = schedule_scope.$on('PostRefresh', function() { + SchedulesListInit({ + scope: schedule_scope, + list: list, + choices: null + }); + }); SearchInit({ scope: schedule_scope, set: 'schedules', @@ -380,48 +390,28 @@ ToggleSchedule, DeleteSchedule) { PaginateInit({ scope: schedule_scope, list: SchedulesList, - url: url + url: url, + pageSize: 5 }); - Rest.setUrl(url); - Rest.get() - .success(function(data) { - var i, modifier; - PageRangeSetup({ - scope: schedule_scope, - count: data.count, - next: data.next, - previous: data.previous, - iterator: SchedulesList.iterator - }); - schedule_scope[SchedulesList.iterator + 'Loading'] = false; - for (i = 1; i <= 3; i++) { - modifier = (i === 1) ? '' : i; - schedule_scope[SchedulesList.iterator + 'HoldInput' + modifier] = false; - } - schedule_scope.schedules = data.results; - window.scrollTo(0, 0); - Wait('stop'); - schedule_scope.schedules = data.results; - }) - .error(function(data, status) { - ProcessErrors(schedule_scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status }); - }); + schedule_scope.search(list.iterator); + + parent_scope.refreshSchedule = function() { + schedule_scope.search(list.iterator); + }; schedule_scope.editSchedule = function(id) { - var schedule = Find({ list: schedule_scope[SchedulesList.name], key: 'id', val: id }); - ScheduleEdit({ scope: parent_scope, schedule: schedule, mode: 'edit' }); + ScheduleEdit({ scope: parent_scope, mode: 'edit', url: GetBasePath('schedules') + id + '/' }); }; schedule_scope.addSchedule = function() { - ScheduleEdit({ scope: parent_scope, schedule: {}, mode: 'add'}); + ScheduleEdit({ scope: parent_scope, mode: 'add', url: url }); }; if (schedule_scope.removeSchedulesRefresh) { schedule_scope.removeSchedulesRefresh(); } schedule_scope.removeSchedulesRefresh = schedule_scope.$on('SchedulesRefresh', function() { - schedule_scope.search(SchedulesList.iterator); + schedule_scope.search(list.iterator); }); schedule_scope.toggleSchedule = function(id) { @@ -458,13 +448,14 @@ ToggleSchedule, DeleteSchedule) { * Remove the schedule list, add the schedule widget and populate it with an rrule * */ -.factory('ScheduleEdit', ['SchedulerInit', 'Rest', 'Wait', 'SetSchedulesInnerDialogSize', -function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { +.factory('ScheduleEdit', ['SchedulerInit', 'Rest', 'Wait', 'SetSchedulesInnerDialogSize', 'SchedulePost', 'ProcessErrors', +function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, SchedulePost, ProcessErrors) { return function(params) { var parent_scope = params.scope, mode = params.mode, // 'create' or 'edit' - schedule = params.schedule, + url = params.url, scope = parent_scope.$new(), + schedule = {}, scheduler, target, showForm, @@ -489,47 +480,53 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { $(this).remove(); }); - // Insert the scheduler widget into the hidden div - scheduler = SchedulerInit({ scope: scope, requireFutureStartTime: false }); - scheduler.inject('schedules-form', false); - scheduler.injectDetail('schedules-detail', false); - scheduler.clear(); - scope.showRRuleDetail = false; - parent_scope.schedulesTitle = 'Edit Schedule'; + if (scope.removeScheduleReady) { + scope.removeScheduleReady(); + } + scope.removeScheduleReady = scope.$on('ScheduleReady', function() { + // Insert the scheduler widget into the hidden div + scheduler = SchedulerInit({ scope: scope, requireFutureStartTime: false }); + scheduler.inject('schedules-form', false); + scheduler.injectDetail('schedules-detail', false); + scheduler.clear(); + scope.showRRuleDetail = false; + parent_scope.schedulesTitle = (mode === 'edit') ? 'Edit Schedule' : 'Create Schedule'; - // display the scheduler widget - showForm = function() { - Wait('stop'); - $('#schedules-overlay').width($('#schedules-tab') - .width()).height($('#schedules-tab').height()).show(); - container.width($('#schedules-tab').width() - 18); - SetSchedulesInnerDialogSize(); - container.show('slide', { direction: 'left' }, 300); - $('#group-save-button').prop('disabled', true); - target.show(); - if (mode === 'edit') { - scope.$apply(function() { - scheduler.setRRule(schedule.rrule); - scheduler.setName(schedule.name); - }); - } - }; - setTimeout(function() { showForm(); }, 1000); + // display the scheduler widget + showForm = function() { + Wait('stop'); + $('#schedules-overlay').width($('#schedules-tab') + .width()).height($('#schedules-tab').height()).show(); + container.width($('#schedules-tab').width() - 18); + SetSchedulesInnerDialogSize(); + container.show('slide', { direction: 'left' }, 300); + $('#group-save-button').prop('disabled', true); + target.show(); + if (mode === 'edit') { + scope.$apply(function() { + scheduler.setRRule(schedule.rrule); + scheduler.setName(schedule.name); + }); + } + }; + setTimeout(function() { showForm(); }, 1000); + }); restoreList = function() { $('#group-save-button').prop('disabled', false); list.show('slide', { direction: 'right' }, 500); $('#schedules-overlay').width($('#schedules-tab').width()).height($('#schedules-tab').height()).hide(); - //refresh the list + parent_scope.refreshSchedule(); }; parent_scope.showScheduleDetail = function() { if (parent_scope.formShowing) { - scheduler.isValid(); - detail.width($('#schedules-form').width()).height($('#schedules-form').height()); - target.hide(); - detail.show(); - parent_scope.formShowing = false; + if (scheduler.isValid()) { + detail.width($('#schedules-form').width()).height($('#schedules-form').height()); + target.hide(); + detail.show(); + parent_scope.formShowing = false; + } } else { detail.hide(); @@ -538,38 +535,25 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { } }; + if (scope.removeScheduleSaved) { + scope.removeScheduleSaved(); + } + scope.removeScheduleSaved = scope.$on('ScheduleSaved', function() { + Wait('stop'); + container.hide('slide', { direction: 'right' }, 500, restoreList); + }); + parent_scope.saveScheduleForm = function() { - var newSchedule, - url = '/static/sample/data/schedules/inventory/data.json'; if (scheduler.isValid()) { scope.schedulerIsValid = true; - Wait('start'); - newSchedule = scheduler.getValue(); - schedule.name = newSchedule.name; - schedule.rrule = newSchedule.rrule; - Rest.setUrl(url); - if (mode === 'edit') { - Rest.put(schedule) - .success(function(){ - Wait('stop'); - container.hide('slide', { direction: 'right' }, 500, restoreList); - }) - .error(function(){ - Wait('stop'); - container.hide('slide', { direction: 'right' }, 500, restoreList); - }); - } - else { - Rest.post(schedule) - .success(function(){ - Wait('stop'); - container.hide('slide', { direction: 'right' }, 500, restoreList); - }) - .error(function(){ - Wait('stop'); - container.hide('slide', { direction: 'right' }, 500, restoreList); - }); - } + SchedulePost({ + scope: scope, + url: url, + scheduler: scheduler, + callback: 'ScheduleSaved', + mode: mode, + schedule: schedule + }); } else { scope.schedulerIsValid = false; @@ -579,6 +563,28 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { parent_scope.cancelScheduleForm = function() { container.hide('slide', { direction: 'right' }, 500, restoreList); }; + + if (mode === 'edit') { + // Get the existing record + Rest.setUrl(url); + Rest.get() + .success(function(data) { + schedule = data; + if (!/DTSTART/.test(schedule.rrule)) { + schedule.rrule += ";DTSTART=" + schedule.dtstart.replace(/\.\d+Z$/,'Z'); + } + schedule.rrule = schedule.rrule.replace(/ RRULE:/,';'); + schedule.rrule = schedule.rrule.replace(/DTSTART:/,'DTSTART='); + scope.$emit('ScheduleReady'); + }) + .error(function(data,status){ + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to get: ' + url + ' GET returned: ' + status }); + }); + } + else { + scope.$emit('ScheduleReady'); + } }; }]) @@ -606,7 +612,8 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { modal_scope = parent_scope.$new(), properties_scope = parent_scope.$new(), sources_scope = parent_scope.$new(), - x, y, ww, wh, maxrows; + x, y, ww, wh, maxrows, + schedules_url = ''; if (mode === 'edit') { defaultUrl = GetBasePath('groups') + group_id + '/'; @@ -778,7 +785,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { else if ($(e.target).text() === 'Schedule') { $('#schedules-overlay').hide(); parent_scope.formShowing = true; - ScheduleList({ scope: parent_scope }); + ScheduleList({ scope: parent_scope, url: schedules_url }); } }); @@ -933,6 +940,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { master[fld] = properties_scope[fld]; } } + schedules_url = data.related.inventory_source + 'schedules/'; properties_scope.variable_url = data.related.variable_data; sources_scope.source_url = data.related.inventory_source; modal_scope.$emit('groupLoaded'); diff --git a/awx/ui/static/js/helpers/Schedules.js b/awx/ui/static/js/helpers/Schedules.js index 813dfda531..3d53c4c1b2 100644 --- a/awx/ui/static/js/helpers/Schedules.js +++ b/awx/ui/static/js/helpers/Schedules.js @@ -64,8 +64,8 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe }; }]) - .factory('EditSchedule', ['SchedulerInit', 'ShowSchedulerModal', 'Wait', 'Rest', 'ToAPI', 'ProcessErrors', 'GetBasePath', - function(SchedulerInit, ShowSchedulerModal, Wait, Rest, ToAPI, ProcessErrors, GetBasePath) { + .factory('EditSchedule', ['SchedulerInit', 'ShowSchedulerModal', 'Wait', 'Rest', 'ProcessErrors', 'GetBasePath', 'SchedulePost', + function(SchedulerInit, ShowSchedulerModal, Wait, Rest, ProcessErrors, GetBasePath, SchedulePost) { return function(params) { var scope = params.scope, id = params.id, @@ -96,42 +96,38 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe scheduler.inject('form-container', false); scheduler.injectDetail('occurrences', false); - ShowSchedulerModal({ scope: scope, callback: 'DialogReady' }); - scope.showRRuleDetail = false; - if (!/DTSTART/.test(schedule.rrule)) { schedule.rrule += ";DTSTART=" + schedule.dtstart.replace(/\.\d+Z$/,'Z'); } schedule.rrule = schedule.rrule.replace(/ RRULE:/,';'); schedule.rrule = schedule.rrule.replace(/DTSTART:/,'DTSTART='); + + ShowSchedulerModal({ scope: scope, callback: 'DialogReady' }); + scope.showRRuleDetail = false; + }); + + + if (scope.removeScheduleSaved) { + scope.removeScheduleSaved(); + } + scope.removeScheduleSaved = scope.$on('ScheduleSaved', function() { + Wait('stop'); + $('#scheduler-modal-dialog').dialog('close'); + if (callback) { + scope.$emit(callback); + } }); scope.saveSchedule = function() { - var newSchedule, rrule; $('#scheduler-tabs a:first').tab('show'); - if (scheduler.isValid()) { - Wait('start'); - newSchedule = scheduler.getValue(); - rrule = scheduler.getRRule(); - schedule.name = newSchedule.name; - schedule.rrule = ToAPI(rrule.toString()); - schedule.description = (/error/.test(rrule.toText())) ? '' : rrule.toText(); - Rest.setUrl(url); - Rest.put(schedule) - .success(function(){ - $('#scheduler-modal-dialog').dialog('close'); - if (callback) { - scope.$emit(callback); - } - else { - Wait('stop'); - } - }) - .error(function(data, status){ - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'POST to ' + url + ' returned: ' + status }); - }); - } + SchedulePost({ + scope: scope, + url: url, + scheduler: scheduler, + callback: 'ScheduleSaved', + mode: 'edit', + schedule: schedule + }); }; $('#scheduler-tabs li a').on('shown.bs.tab', function(e) { @@ -158,8 +154,9 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe }; }]) - .factory('AddSchedule', ['$location', '$routeParams', 'SchedulerInit', 'ShowSchedulerModal', 'Wait', 'Rest', 'ToAPI', 'ProcessErrors', 'GetBasePath', 'Empty', - function($location, $routeParams, SchedulerInit, ShowSchedulerModal, Wait, Rest, ToAPI, ProcessErrors, GetBasePath, Empty) { + .factory('AddSchedule', ['$location', '$routeParams', 'SchedulerInit', 'ShowSchedulerModal', 'Wait', 'GetBasePath', 'Empty', + 'SchedulePost', + function($location, $routeParams, SchedulerInit, ShowSchedulerModal, Wait, GetBasePath, Empty, SchedulePost) { return function(params) { var scope = params.scope, callback= params.callback, @@ -186,20 +183,59 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe ShowSchedulerModal({ scope: scope, callback: 'DialogReady' }); scope.showRRuleDetail = false; + if (scope.removeScheduleSaved) { + scope.removeScheduleSaved(); + } + scope.removeScheduleSaved = scope.$on('ScheduleSaved', function() { + Wait('stop'); + $('#scheduler-modal-dialog').dialog('close'); + if (callback) { + scope.$emit(callback); + } + }); + scope.saveSchedule = function() { - var newSchedule, rrule, schedule = {}; $('#scheduler-tabs a:first').tab('show'); - if (scheduler.isValid()) { - Wait('start'); - newSchedule = scheduler.getValue(); - rrule = scheduler.getRRule(); - schedule.name = newSchedule.name; - schedule.rrule = ToAPI(rrule.toString()); - schedule.description = (/error/.test(rrule.toText())) ? '' : rrule.toText(); - Rest.setUrl(url); + SchedulePost({ + scope: scope, + url: url, + scheduler: scheduler, + callback: 'ScheduleSaved', + mode: 'add' + }); + }; + + $('#scheduler-tabs li a').on('shown.bs.tab', function(e) { + if ($(e.target).text() === 'Details') { + if (!scheduler.isValid()) { + $('#scheduler-tabs a:first').tab('show'); + } + } + }); + }; + }]) + + .factory('SchedulePost', ['Rest', 'ProcessErrors', 'RRuleToAPI', 'Wait', function(Rest, ProcessErrors, RRuleToAPI, Wait) { + return function(params) { + var scope = params.scope, + url = params.url, + scheduler = params.scheduler, + mode = params.mode, + schedule = (params.schedule) ? params.schedule : {}, + callback = params.callback, + newSchedule, rrule; + + if (scheduler.isValid()) { + Wait('start'); + newSchedule = scheduler.getValue(); + rrule = scheduler.getRRule(); + schedule.name = newSchedule.name; + schedule.rrule = RRuleToAPI(rrule.toString()); + schedule.description = (/error/.test(rrule.toText())) ? '' : rrule.toText(); + Rest.setUrl(url); + if (mode === 'add') { Rest.post(schedule) .success(function(){ - $('#scheduler-modal-dialog').dialog('close'); if (callback) { scope.$emit(callback); } @@ -212,15 +248,25 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe msg: 'POST to ' + url + ' returned: ' + status }); }); } - }; - - $('#scheduler-tabs li a').on('shown.bs.tab', function(e) { - if ($(e.target).text() === 'Details') { - if (!scheduler.isValid()) { - $('#scheduler-tabs a:first').tab('show'); - } + else { + Rest.put(schedule) + .success(function(){ + if (callback) { + scope.$emit(callback); + } + else { + Wait('stop'); + } + }) + .error(function(data, status){ + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'POST to ' + url + ' returned: ' + status }); + }); } - }); + } + else { + return false; + } }; }]) @@ -363,7 +409,7 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe * Convert rrule string to an API agreeable format * */ - .factory('ToAPI', [ function() { + .factory('RRuleToAPI', [ function() { return function(rrule) { var response; response = rrule.replace(/(^.*(?=DTSTART))(DTSTART=.*?;)(.*$)/, function(str, p1, p2, p3) { @@ -437,13 +483,56 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe }; }]) + .factory('SchedulesListInit', [ function() { + return function(params) { + var scope = params.scope, + list = params.list, + choices = params.choices; + scope[list.name].forEach(function(item, item_idx) { + var fld, field, + itm = scope[list.name][item_idx]; + itm.enabled = (itm.enabled) ? true : false; + if (itm.enabled) { + itm.play_tip = 'Schedule is active. Click to stop.'; + itm.status = 'active'; + itm.status_tip = 'Schedule is active. Click to stop.'; + } + else { + itm.play_tip = 'Schedule is stopped. Click to activate.'; + itm.status = 'stopped'; + itm.status_tip = 'Schedule is stopped. Click to activate.'; + } + itm.nameTip = item.name + " schedule. Click to edit."; + // Copy summary_field values + for (field in list.fields) { + fld = list.fields[field]; + if (fld.sourceModel) { + if (itm.summary_fields[fld.sourceModel]) { + itm[field] = itm.summary_fields[fld.sourceModel][fld.sourceField]; + } + } + } + // Set the item type label + if (list.fields.type) { + choices.every(function(choice) { + if (choice.value === item.type) { + itm.type_label = choice.label; + return false; + } + return true; + }); + } + }); + }; + }]) + /** * * Called from a controller to setup the scope for a schedules list * */ - .factory('LoadSchedulesScope', ['SearchInit', 'PaginateInit', 'GenerateList', 'SchedulesControllerInit', - function(SearchInit, PaginateInit, GenerateList, SchedulesControllerInit) { + .factory('LoadSchedulesScope', ['SearchInit', 'PaginateInit', 'GenerateList', 'SchedulesControllerInit', 'SchedulesListInit', + function(SearchInit, PaginateInit, GenerateList, SchedulesControllerInit, SchedulesListInit) { return function(params) { var parent_scope = params.parent_scope, scope = params.scope, @@ -481,51 +570,15 @@ angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelpe scope.removePostRefresh(); } scope.$on('PostRefresh', function(){ - SchedulesControllerInit({ scope: scope, parent_scope: parent_scope, list: list }); - - scope[list.name].forEach(function(item, item_idx) { - var fld, field, - itm = scope[list.name][item_idx]; - itm.enabled = (itm.enabled) ? true : false; - if (itm.enabled) { - itm.play_tip = 'Schedule is active. Click to stop.'; - itm.status = 'active'; - itm.status_tip = 'Schedule is active. Click to stop.'; - } - else { - itm.play_tip = 'Schedule is stopped. Click to activate.'; - itm.status = 'stopped'; - itm.status_tip = 'Schedule is stopped. Click to activate.'; - } - - itm.nameTip = item.name + " schedule. Click to edit."; - - // Copy summary_field values - for (field in list.fields) { - fld = list.fields[field]; - if (fld.sourceModel) { - if (itm.summary_fields[fld.sourceModel]) { - itm[field] = itm.summary_fields[fld.sourceModel][fld.sourceField]; - } - } - } - - // Set the item type label - if (list.fields.type) { - parent_scope.type_choices.every(function(choice) { - if (choice.value === item.type) { - itm.type_label = choice.label; - return false; - } - return true; - }); - } - + SchedulesListInit({ + scope: scope, + list: list, + choices: parent_scope.type_choices }); parent_scope.$emit('listLoaded'); }); diff --git a/awx/ui/static/lib/ansible/Utilities.js b/awx/ui/static/lib/ansible/Utilities.js index c9efa0f6c9..e412e49777 100644 --- a/awx/ui/static/lib/ansible/Utilities.js +++ b/awx/ui/static/lib/ansible/Utilities.js @@ -199,7 +199,7 @@ angular.module('Utilities', ['RestServices', 'Utilities']) if ((!fieldErrors) && defaultMsg) { Alert(defaultMsg.hdr, defaultMsg.msg); } - } else if (Object.keys(data).length > 0) { + } else if (typeof data === 'object' && Object.keys(data).length > 0) { keys = Object.keys(data); if (Array.isArray(data[keys[0]])) { msg = data[keys[0]][0]; diff --git a/awx/ui/static/partials/inventory-edit.html b/awx/ui/static/partials/inventory-edit.html index 93f7889259..ecbb7c880d 100644 --- a/awx/ui/static/partials/inventory-edit.html +++ b/awx/ui/static/partials/inventory-edit.html @@ -39,7 +39,7 @@
View Details - Options + Back to options