diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 4c70cdca4b..732a6625d6 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -147,7 +147,7 @@ angular.module('ansible', [ when('/job_templates/:id/schedules', { templateUrl: urlPrefix + 'partials/schedule_detail.html', - controller: 'ScheduleEdit' + controller: 'ScheduleEditController' }). when('/projects', { @@ -167,7 +167,7 @@ angular.module('ansible', [ when('/projects/:id/schedules', { templateUrl: urlPrefix + 'partials/schedule_detail.html', - controller: 'ScheduleEdit' + controller: 'ScheduleEditController' }). when('/projects/:project_id/organizations', { diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 6c659aebdb..9323b37404 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -11,7 +11,8 @@ 'use strict'; 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, DeleteJob, Find, DeleteSchedule, ToggleSchedule, RelaunchInventory, RelaunchPlaybook, RelaunchSCM, + LoadDialogPartial, ScheduledJobEdit) { ClearScope(); @@ -140,6 +141,10 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea }); }; + scheduled_scope.editSchedule = function(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); @@ -165,7 +170,7 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea } $scope.removeChoicesReady = $scope.$on('choicesReady', function() { choicesCount++; - if (choicesCount === 2) { + if (choicesCount === 3) { $scope.$emit('buildJobsList'); } }); @@ -188,11 +193,16 @@ function JobsListController ($scope, $compile, ClearScope, Breadcrumbs, LoadBrea callback: 'choicesReady' }); + LoadDialogPartial({ + scope: $scope, + element_id: 'schedule-dialog-target', + callback: 'choicesReady' + }); } JobsListController.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadBreadCrumbs', 'LoadScope', 'RunningJobsList', 'CompletedJobsList', 'QueuedJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'Wait', 'DeleteJob', 'Find', 'DeleteSchedule', 'ToggleSchedule', 'RelaunchInventory', - 'RelaunchPlaybook', 'RelaunchSCM']; + 'RelaunchPlaybook', 'RelaunchSCM', 'LoadDialogPartial', 'ScheduledJobEdit']; function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, @@ -464,6 +474,7 @@ function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, J JobsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords', - 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString', 'GetChoices' + 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString', 'GetChoices', + 'LoadDialogPartial' ]; diff --git a/awx/ui/static/js/controllers/Schedules.js b/awx/ui/static/js/controllers/Schedules.js index 962b1d3f37..cda9f9cd45 100644 --- a/awx/ui/static/js/controllers/Schedules.js +++ b/awx/ui/static/js/controllers/Schedules.js @@ -10,8 +10,9 @@ 'use strict'; -function ScheduleEdit($scope, $compile, $location, $routeParams, SchedulesList, GenerateList, Rest, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, -GetBasePath, LookUpInit, Wait, SchedulerInit, Breadcrumbs, SearchInit, PaginateInit, PageRangeSetup, EditSchedule, AddSchedule, Find, ToggleSchedule, DeleteSchedule) { +function ScheduleEditController($scope, $compile, $location, $routeParams, SchedulesList, GenerateList, Rest, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, +GetBasePath, LookUpInit, Wait, SchedulerInit, Breadcrumbs, SearchInit, PaginateInit, PageRangeSetup, EditSchedule, AddSchedule, Find, ToggleSchedule, DeleteSchedule, +LoadDialogPartial) { ClearScope(); @@ -156,21 +157,33 @@ GetBasePath, LookUpInit, Wait, SchedulerInit, Breadcrumbs, SearchInit, PaginateI }); }; - // Load the parent object - id = $routeParams.id; - Rest.setUrl(GetBasePath(base) + id); - Rest.get() - .success(function(data) { - parentObject = data; - $scope.$emit('ParentLoaded'); - }) - .error(function(status) { - ProcessErrors($scope, null, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. GET returned: ' + status }); - }); + if ($scope.removeLoadParent) { + $scope.removeLoadParent(); + } + $scope.removeLoadParent = $scope.$on('LoadParent', function() { + // Load the parent object + id = $routeParams.id; + url = GetBasePath(base) + id; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + parentObject = data; + $scope.$emit('ParentLoaded'); + }) + .error(function(status) { + ProcessErrors($scope, null, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status }); + }); + }); + + LoadDialogPartial({ + scope: $scope, + element_id: 'schedule-dialog-target', + callback: 'LoadParent', + }); } -ScheduleEdit.$inject = ['$scope', '$compile', '$location', '$routeParams', 'SchedulesList', 'GenerateList', 'Rest', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', +ScheduleEditController.$inject = ['$scope', '$compile', '$location', '$routeParams', 'SchedulesList', 'GenerateList', 'Rest', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'LookUpInit', 'Wait', 'SchedulerInit', 'Breadcrumbs', 'SearchInit', 'PaginateInit', 'PageRangeSetup', 'EditSchedule', 'AddSchedule', -'Find', 'ToggleSchedule', 'DeleteSchedule' +'Find', 'ToggleSchedule', 'DeleteSchedule', 'LoadDialogPartial' ]; \ No newline at end of file diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 833283b3cf..05d58c2d20 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -678,6 +678,7 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { autoOpen: false, minWidth: 440, title: 'Edit Group', + closeOnEscape: false, create: function () { $('.ui-dialog[aria-describedby="group-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).text('x'); $('.ui-dialog[aria-describedby="group-modal-dialog"]').find('.ui-dialog-buttonset button').each(function () { @@ -705,9 +706,13 @@ function(SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize) { resizeStop: function () { // for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100% var dialog = $('.ui-dialog[aria-describedby="group-modal-dialog"]'), + titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(), + buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(), content = dialog.find('#group-modal-dialog'), w; content.width(dialog.width() - 28); + content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) }); + if ($('#group_tabs .active a').text() === 'Properties') { textareaResize('group_variables', properties_scope); } diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 93efd6f655..d8a49ebf7d 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -470,6 +470,7 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener minWidth: 400, title: 'Host Properties', id: 'host-modal-dialog', + clonseOnEscape: false, onClose: function() { Wait('stop'); scope.codeMirror.destroy(); @@ -485,6 +486,7 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener }); }, onOpen: function() { + $('#host_name').focus(); setTimeout(function() { TextareaResize({ scope: scope, diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index 11567cfae4..4732c69887 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -10,7 +10,7 @@ 'use strict'; angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'JobSummaryDefinition', 'InventoryHelper', 'GeneratorHelpers', - 'JobSubmissionHelper']) + 'JobSubmissionHelper', 'SchedulesHelper']) .factory('JobStatusToolTip', [ function () { @@ -370,5 +370,15 @@ function(Find, Wait, Rest, InventoryUpdate, ProcessErrors, GetBasePath) { id = params.id; ProjectUpdate({ scope: scope, id: id }); }; +}]) + +.factory('ScheduledJobEdit', ['Find', 'EditSchedule', 'GetBasePath', function(Find, EditSchedule, GetBasePath) { + return function(params) { + var scope = params.scope, + id = params.id, + url = GetBasePath('schedules'), + schedule = Find({ list: scope.scheduled_jobs, key: 'id', val: id }); + EditSchedule({ scope: scope, schedule: schedule, url: url }); + }; }]); diff --git a/awx/ui/static/js/helpers/Schedules.js b/awx/ui/static/js/helpers/Schedules.js index aebdb14151..3a4245a2b8 100644 --- a/awx/ui/static/js/helpers/Schedules.js +++ b/awx/ui/static/js/helpers/Schedules.js @@ -52,6 +52,7 @@ angular.module('SchedulesHelper', ['Utilities', 'SchedulesHelper']) width: x, height: y, autoOpen: false, + closeOnEscape: false, create: function () { $('.ui-dialog[aria-describedby="scheduler-modal-dialog"]').find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).text('x'); $('.ui-dialog[aria-describedby="scheduler-modal-dialog"]').find('.ui-dialog-buttonset button').each(function () { @@ -79,9 +80,12 @@ angular.module('SchedulesHelper', ['Utilities', 'SchedulesHelper']) }, resizeStop: function () { // for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100% - var dialog = $('.ui-dialog[aria-describedby="status-modal-dialog"]'), - content = dialog.find('#scheduler-modal-dialog'); + var dialog = $('.ui-dialog[aria-describedby="scheduler-modal-dialog"]'), + titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(), + buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(), + content = dialog.find('#scheduler-modal-dialog'); content.width(dialog.width() - 28); + content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) }); }, close: function () { // Destroy on close @@ -114,7 +118,6 @@ angular.module('SchedulesHelper', ['Utilities', 'SchedulesHelper']) schedule = params.schedule, url = params.url, scheduler; - Wait('start'); $('#form-container').empty(); scheduler = SchedulerInit({ scope: scope, requireFutureStartTime: false }); @@ -124,6 +127,10 @@ angular.module('SchedulesHelper', ['Utilities', 'SchedulesHelper']) ShowSchedulerModal({ scope: scope }); scope.showRRuleDetail = false; + if (!/DTSTART/.test(schedule.rrule)) { + schedule.rrule += ";DTSTART=" + schedule.dtstart; + } + setTimeout(function(){ $('#scheduler-modal-dialog').dialog('open'); scope.$apply(function() { @@ -216,6 +223,31 @@ angular.module('SchedulesHelper', ['Utilities', 'SchedulesHelper']) }; }]) + .factory('LoadDialogPartial', ['Rest', '$compile', 'ProcessErrors', function(Rest, $compile, ProcessErrors) { + return function(params) { + + var scope = params.scope, + element_id = params.element_id, + callback = params.callback, + url; + + // Add the schedule_dialog.html partial + url = '/static/partials/schedule_dialog.html'; + Rest.setUrl(url); + Rest.get() + .success(function(data) { + var e = angular.element(document.getElementById(element_id)); + e.append(data); + $compile(e)(scope); + scope.$emit(callback); + }) + .error(function(data, status) { + ProcessErrors(scope, null, status, null, { hdr: 'Error!', + msg: 'Call to ' + url + ' failed. GET returned: ' + status }); + }); + }; + }]) + /** * Flip a schedule's enable flag * diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index 6d4f924322..b1ba03e777 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -733,7 +733,7 @@ select.page-size { .nav-path { padding: 5px 0 10px 0; margin-right: 5px; - margin-bottom: 25px; + margin-bottom: 20px; font-size: 14px; font-weight: bold; background-color: #f5f5f5; diff --git a/awx/ui/static/less/jquery-ui-overrides.less b/awx/ui/static/less/jquery-ui-overrides.less index 5d0882fc73..bcb1d8de1e 100644 --- a/awx/ui/static/less/jquery-ui-overrides.less +++ b/awx/ui/static/less/jquery-ui-overrides.less @@ -76,6 +76,7 @@ table.ui-datepicker-calendar { text-decoration: none; font-weight: normal; } + max-height: 48px; } .ui-widget-overlay.ui-front { diff --git a/awx/ui/static/lib/ansible/Modal.js b/awx/ui/static/lib/ansible/Modal.js index be43142756..58e9ab147d 100644 --- a/awx/ui/static/lib/ansible/Modal.js +++ b/awx/ui/static/lib/ansible/Modal.js @@ -45,6 +45,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) onClose = params.onClose, onOpen = params.onOpen, callback = params.callback, + closeOnEscape = (params.closeOnEscape === undefined) ? false : params.closeOnEscape, buttons, id = params.id, x, y, wh, ww; @@ -82,6 +83,7 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) autoOpen: false, minWidth: minWidth, title: title, + closeOnEscape: closeOnEscape, create: function () { // Fix the close button $('.ui-dialog[aria-describedby="' + id + '"]').find('.ui-dialog-titlebar button').empty().attr({'class': 'close'}).text('x'); @@ -108,8 +110,11 @@ angular.module('ModalDialog', ['Utilities', 'ParseHelper']) resizeStop: function () { // for some reason, after resizing dialog the form and fields (the content) doesn't expand to 100% var dialog = $('.ui-dialog[aria-describedby="' + id + '"]'), + titleHeight = dialog.find('.ui-dialog-titlebar').outerHeight(), + buttonHeight = dialog.find('.ui-dialog-buttonpane').outerHeight(), content = dialog.find('#' + id); content.width(dialog.width() - 28); + content.css({ height: (dialog.height() - titleHeight - buttonHeight - 10) }); if (onResizeStop) { onResizeStop(); } diff --git a/awx/ui/static/lib/ansible/directives.js b/awx/ui/static/lib/ansible/directives.js index ca7858ef5d..d3b934de74 100644 --- a/awx/ui/static/lib/ansible/directives.js +++ b/awx/ui/static/lib/ansible/directives.js @@ -287,7 +287,7 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'AuthService', 'Job var placement = (attrs.placement !== undefined && attrs.placement !== null) ? attrs.placement : 'left', title = (attrs.title !== undefined && attrs.title !== null) ? attrs.title : 'Help', container = (attrs.container !== undefined) ? attrs.container : false, - trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manua'; + trigger = (attrs.trigger !== undefined) ? attrs.trigger : 'manual'; $(element).popover({ placement: placement, delay: 0, title: title, content: attrs.awPopOver, trigger: trigger, html: true, container: container }); $(element).click(function() { diff --git a/awx/ui/static/partials/jobs.html b/awx/ui/static/partials/jobs.html index 3180521f4f..94a2addb39 100644 --- a/awx/ui/static/partials/jobs.html +++ b/awx/ui/static/partials/jobs.html @@ -32,6 +32,7 @@ - + +
\ No newline at end of file diff --git a/awx/ui/static/partials/schedule_detail.html b/awx/ui/static/partials/schedule_detail.html index 103ac7207a..01d9947b3e 100644 --- a/awx/ui/static/partials/schedule_detail.html +++ b/awx/ui/static/partials/schedule_detail.html @@ -8,16 +8,4 @@ -
- -
-
-
-
-
-
-
-
\ No newline at end of file +
\ No newline at end of file diff --git a/awx/ui/static/partials/schedule_dialog.html b/awx/ui/static/partials/schedule_dialog.html new file mode 100644 index 0000000000..d9feaf4e38 --- /dev/null +++ b/awx/ui/static/partials/schedule_dialog.html @@ -0,0 +1,13 @@ +
+ +
+
+
+
+
+
+
+
\ No newline at end of file