diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 40f874cf6b..00b19eda61 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -68,6 +68,7 @@ import './job-templates/main'; import './shared/features/main'; import './login/authenticationServices/pendo/ng-pendo'; import footer from './footer/main'; +import scheduler from './scheduler/main'; /*#if DEBUG#*/ import {__deferLoadIfEnabled} from './debug'; @@ -184,6 +185,7 @@ var tower = angular.module('Tower', [ 'pendolytics', 'ui.router', 'ncy-angular-breadcrumb', + 'scheduler' ]) .constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/') @@ -412,22 +414,6 @@ var tower = angular.module('Tower', [ }] } }). - - state('jobTemplateSchedules', { - url: '/job_templates/:id/schedules', - templateUrl: urlPrefix + 'partials/schedule_detail.html', - controller: ScheduleEditController, - data: { - activityStream: true, - activityStreamTarget: 'schedule' - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }] - } - }). - state('projects', { url: '/projects', templateUrl: urlPrefix + 'partials/projects.html', @@ -474,22 +460,6 @@ var tower = angular.module('Tower', [ }] } }). - - state('projectSchedules', { - url: '/projects/:id/schedules', - templateUrl: urlPrefix + 'partials/schedule_detail.html', - controller: ScheduleEditController, - data: { - activityStream: true, - activityStreamTarget: 'schedule' - }, - resolve: { - features: ['FeaturesService', function(FeaturesService) { - return FeaturesService.get(); - }] - } - }). - state('projectOrganizations', { url: '/projects/:project_id/organizations', templateUrl: urlPrefix + 'partials/projects.html', diff --git a/awx/ui/client/src/controllers/JobTemplates.js b/awx/ui/client/src/controllers/JobTemplates.js index b8b37c5a72..6c1969ea53 100644 --- a/awx/ui/client/src/controllers/JobTemplates.js +++ b/awx/ui/client/src/controllers/JobTemplates.js @@ -238,7 +238,7 @@ export function JobTemplatesList($scope, $rootScope, $location, $log, }; $scope.scheduleJob = function (id) { - $state.transitionTo('jobTemplateSchedules', {id: id}); + $state.go('jobTemplateSchedules', {id: id}); } } diff --git a/awx/ui/client/src/helpers/Schedules.js b/awx/ui/client/src/helpers/Schedules.js index 59af9229a2..f73a7ee042 100644 --- a/awx/ui/client/src/helpers/Schedules.js +++ b/awx/ui/client/src/helpers/Schedules.js @@ -20,7 +20,7 @@ export default angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelper', 'SearchHelper', 'PaginationHelpers', listGenerator.name, 'ModalDialog', 'GeneratorHelpers']) - .factory('ShowSchedulerModal', ['Wait', 'CreateDialog', function(Wait, CreateDialog) { + .factory('ShowSchedulerModal', ['$rootScope', 'Wait', 'CreateDialog', function($rootScope, Wait, CreateDialog) { return function(params) { // Set modal dimensions based on viewport width @@ -50,28 +50,7 @@ export default "class": "btn btn-primary", "id": "schedule-save-button" }]; - - CreateDialog({ - id: 'scheduler-modal-dialog', - scope: scope, - buttons: buttons, - title: title, - width: 700, - height: 725, - minWidth: 400, - onClose: function() { - $('#scheduler-modal-dialog #form-container').empty(); - }, - onOpen: function() { - Wait('stop'); - $('#scheduler-tabs a:first').tab('show'); - $('#schedulerName').focus(); - $('#rrule_nlp_description').dblclick(function() { - setTimeout(function() { scope.$apply(function() { scope.showRRule = (scope.showRRule) ? false : true; }); }, 100); - }); - }, - callback: callback - }); + $rootScope.$broadcast("ScheduleFormCreated", scope); }; }]) @@ -175,7 +154,11 @@ export default } schedule.rrule = schedule.rrule.replace(/ RRULE:/,';'); schedule.rrule = schedule.rrule.replace(/DTSTART:/,'DTSTART='); - ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Edit Schedule' }); + scope.$on("htmlDetailReady", function() { + scheduler.setRRule(schedule.rrule); + scheduler.setName(schedule.name); + ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Edit Schedule' }); + }); scope.showRRuleDetail = false; }); @@ -185,14 +168,12 @@ export default } scope.removeScheduleSaved = scope.$on('ScheduleSaved', function(e, data) { Wait('stop'); - $('#scheduler-modal-dialog').dialog('close'); if (callback) { scope.$emit(callback, data); } }); scope.saveSchedule = function() { - $('#scheduler-tabs a:first').tab('show'); SchedulePost({ scope: scope, url: url, @@ -203,16 +184,6 @@ export default }); }; - - - $('#scheduler-tabs li a').on('shown.bs.tab', function(e) { - if ($(e.target).text() === 'Details') { - if (!scheduler.isValid()) { - $('#scheduler-tabs a:first').tab('show'); - } - } - }); - Wait('start'); // Get the existing record @@ -290,21 +261,15 @@ export default } } - if (scope.removeDialogReady) { - scope.removeDialogReady(); - } - scope.removeDialogReady = scope.$on('DialogReady', function() { - $('#scheduler-modal-dialog').dialog('open'); - $('#schedulerName').focus(); - }); - Wait('start'); $('#form-container').empty(); scheduler = SchedulerInit({ scope: scope, requireFutureStartTime: false }); scheduler.inject('form-container', false); scheduler.injectDetail('occurrences', false); scheduler.clear(); - ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Add Schedule' }); + scope.$on("htmlDetailReady", function() { + ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Add Schedule' }); + }); scope.showRRuleDetail = false; if (scope.removeScheduleSaved) { @@ -312,14 +277,12 @@ export default } scope.removeScheduleSaved = scope.$on('ScheduleSaved', function(e, data) { Wait('stop'); - $('#scheduler-modal-dialog').dialog('close'); if (callback) { scope.$emit(callback, data); } }); scope.saveSchedule = function() { - $('#scheduler-tabs a:first').tab('show'); SchedulePost({ scope: scope, url: url, @@ -565,9 +528,9 @@ export default }]) - .factory('SchedulesControllerInit', ['$location', 'ToggleSchedule', + .factory('SchedulesControllerInit', ['$state', '$location', 'ToggleSchedule', 'DeleteSchedule', 'EditSchedule', 'AddSchedule', - function($location, ToggleSchedule, DeleteSchedule, EditSchedule, + function($state, $location, ToggleSchedule, DeleteSchedule, EditSchedule, AddSchedule) { return function(params) { var scope = params.scope, @@ -598,18 +561,13 @@ export default }; scope.editSchedule = function(id) { - EditSchedule({ - scope: scope, - id: id, - callback: 'SchedulesRefresh' - }); + var base = $state.current.name.split(".")[0]; + $state.go(base + ".edit", {schedule_id: id}); }; scope.addSchedule = function() { - AddSchedule({ - scope: scope, - callback: 'SchedulesRefresh' - }); + var base = $state.current.name.split(".")[0]; + $state.go(base + ".add", {passedScope: scope}); }; scope.refreshSchedules = function() { diff --git a/awx/ui/client/src/lists/Schedules.js b/awx/ui/client/src/lists/Schedules.js index 2e47d6a03d..c6bed3edfa 100644 --- a/awx/ui/client/src/lists/Schedules.js +++ b/awx/ui/client/src/lists/Schedules.js @@ -50,6 +50,7 @@ export default awToolTip: "Refresh the page", ngClick: "refreshSchedules()", actionClass: 'btn List-buttonDefault', + ngShow: "socketStatus == 'error'", buttonContent: 'REFRESH' }, add: { diff --git a/awx/ui/client/src/scheduler/main.js b/awx/ui/client/src/scheduler/main.js new file mode 100644 index 0000000000..46fa46d94e --- /dev/null +++ b/awx/ui/client/src/scheduler/main.js @@ -0,0 +1,84 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import controller from './scheduler.controller'; +import addController from './schedulerAdd.controller'; +import editController from './schedulerEdit.controller'; +import {templateUrl} from '../shared/template-url/template-url.factory'; + +export default + angular.module('scheduler', []) + .controller('schedulerController', controller) + .controller('schedulerAddController', addController) + .controller('schedulerEditController', editController) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState({ + name: 'jobTemplateSchedules', + route: '/job_templates/:id/schedules', + templateUrl: templateUrl("scheduler/scheduler"), + controller: 'schedulerController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + $stateExtender.addState({ + name: 'jobTemplateSchedules.add', + route: '/add', + templateUrl: templateUrl("scheduler/schedulerForm"), + controller: 'schedulerAddController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + $stateExtender.addState({ + name: 'jobTemplateSchedules.edit', + route: '/:schedule_id', + templateUrl: templateUrl("scheduler/schedulerForm"), + controller: 'schedulerEditController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + $stateExtender.addState({ + name: 'projectSchedules', + route: '/projects/:id/schedules', + templateUrl: templateUrl("scheduler/scheduler"), + controller: 'schedulerController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + $stateExtender.addState({ + name: 'projectSchedules.add', + route: '/add', + templateUrl: templateUrl("scheduler/schedulerForm"), + controller: 'schedulerAddController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + $stateExtender.addState({ + name: 'projectSchedules.edit', + route: '/:schedule_id', + templateUrl: templateUrl("scheduler/schedulerForm"), + controller: 'schedulerEditController', + resolve: { + features: ['FeaturesService', function(FeaturesService) { + return FeaturesService.get(); + }] + } + }); + }]); diff --git a/awx/ui/client/src/scheduler/scheduler.controller.js b/awx/ui/client/src/scheduler/scheduler.controller.js new file mode 100644 index 0000000000..e014eae18b --- /dev/null +++ b/awx/ui/client/src/scheduler/scheduler.controller.js @@ -0,0 +1,95 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +/** + * @ngdoc function + * @name controllers.function:Schedules + * @description This controller's for schedules +*/ + + +export default [ + '$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest', 'ProcessErrors', 'ReturnToCaller', 'ClearScope', + 'GetBasePath', 'Wait', 'Find', 'LoadDialogPartial', 'LoadSchedulesScope', 'GetChoices', 'Stream', + function ($scope, $compile, $location, $stateParams, + SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope, + GetBasePath, Wait, Find, LoadDialogPartial, LoadSchedulesScope, GetChoices, + Stream) { + + ClearScope(); + + var base, e, id, url, parentObject; + + base = $location.path().replace(/^\//, '').split('/')[0]; + + if ($scope.removePostRefresh) { + $scope.removePostRefresh(); + } + $scope.removePostRefresh = $scope.$on('PostRefresh', function() { + var list = $scope.schedules; + list.forEach(function(element, idx) { + list[idx].play_tip = (element.enabled) ? 'Schedule is Active. Click to temporarily stop.' : 'Schedule is temporarily stopped. Click to activate.'; + }); + }); + + if ($scope.removeParentLoaded) { + $scope.removeParentLoaded(); + } + $scope.removeParentLoaded = $scope.$on('ParentLoaded', function() { + url += "schedules/"; + SchedulesList.well = true; + + // include name of item in listTitle + SchedulesList.listTitle = parentObject.name + "
Schedules"; + + LoadSchedulesScope({ + parent_scope: $scope, + scope: $scope, + list: SchedulesList, + id: 'schedule-list-target', + url: url, + pageSize: 20 + }); + }); + + + if ($scope.removeChoicesReady) { + $scope.removeChocesReady(); + } + $scope.removeChoicesReady = $scope.$on('choicesReady', function() { + // Load the parent object + id = $stateParams.id; + url = GetBasePath(base) + id + '/'; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + parentObject = data; + $scope.$emit('ParentLoaded'); + }) + .error(function(data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status }); + }); + }); + + $scope.refreshJobs = function() { + $scope.search(SchedulesList.iterator); + }; + + $scope.showActivity = function () { + Stream({ scope: $scope }); + }; + + Wait('start'); + + GetChoices({ + scope: $scope, + url: GetBasePath('unified_jobs'), //'/static/sample/data/types/data.json' + field: 'type', + variable: 'type_choices', + callback: 'choicesReady' + }); + }]; diff --git a/awx/ui/client/src/scheduler/scheduler.partial.html b/awx/ui/client/src/scheduler/scheduler.partial.html new file mode 100644 index 0000000000..b4b87d1f92 --- /dev/null +++ b/awx/ui/client/src/scheduler/scheduler.partial.html @@ -0,0 +1,6 @@ + +The scheduler options are invalid or incomplete. Make the needed changes on the options tab, then come back here to see details.
+