1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 15:21:13 +03:00

Configure Tower

adding changes to app and index for configure tower files. also included are updates to the scheduler widget for system jobs
This commit is contained in:
Jared Tabor 2014-11-13 11:29:42 -05:00
parent 6a08738071
commit dfeaea0148
7 changed files with 222 additions and 45 deletions

View File

@ -119,7 +119,9 @@ angular.module('Tower', [
'SocketHelper',
'AboutAnsibleHelpModal',
'SurveyQuestionFormDefinition',
'PortalJobsListDefinition'
'PortalJobsListDefinition',
'ConfigureTowerHelper',
'ConfigureTowerJobsListDefinition'
])
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
@ -432,9 +434,9 @@ angular.module('Tower', [
}])
.run(['$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', 'ClearScope', 'HideStream', 'Socket',
'LoadConfig', 'Store', 'ShowSocketHelp', 'LicenseViewer', 'AboutAnsibleHelp',
'LoadConfig', 'Store', 'ShowSocketHelp', 'LicenseViewer', 'AboutAnsibleHelp', 'ConfigureTower',
function ($compile, $cookieStore, $rootScope, $log, CheckLicense, $location, Authorization, LoadBasePaths, Timer, ClearScope, HideStream, Socket,
LoadConfig, Store, ShowSocketHelp, LicenseViewer, AboutAnsibleHelp) {
LoadConfig, Store, ShowSocketHelp, LicenseViewer, AboutAnsibleHelp, ConfigureTower) {
var e, html, sock, checkCount = 0;
@ -586,6 +588,12 @@ angular.module('Tower', [
$location.path('/home/');
};
$rootScope.configureTower = function(){
ConfigureTower({
scope: $rootScope
});
};
html = "<a href=\"\" ng-click=\"socketHelp()\" aw-pop-over=\"{{ socketTip }}\" aw-pop-over-watch=\"socketTip\" data-placement=\"bottom\" data-trigger=\"hover\" " +
"data-popover-title=\"Live Events\" data-container=\"body\" style=\"font-size: 10px;\"><i class=\"fa icon-socket-{{ socketStatus }}\"></i></a>";
e = angular.element(document.getElementById('socket-beacon-div'));

View File

@ -671,6 +671,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
return function (params) {
var scope = params.scope,
id = params.id,
system_job = params.system_job || false,
base = $location.path().replace(/^\//, '').split('/')[0],
url,
job_template,

View File

@ -186,6 +186,126 @@ a:focus {
}
}
#configure-schedules-tab {
position: relative;
top: 0;
left: 0;
}
#configure-schedules-overlay {
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 100;
background-color: @black;
opacity: 0;
}
#configure-schedules-buttons{
height: 46px;
padding-top: 10px;
text-align: right;
border-top: 1px solid #A6C9E2;
margin-top: 5px;
a {
margin-right: 8px;
font-size: 12px;
}
}
#configure-schedules-form-container {
position: absolute;
top: 0;
left: 0;
display: none;
border: 1px solid #e5e5e5;
border-radius: 4px;
box-shadow: 3px 3px 6px 0 #666;
padding: 0 10px 15px 8px;
background-color: @white;
z-index: 200;
}
#configure-schedules-title {
border-bottom: 1px solid #e5e5e5;
padding-bottom: 8px;
margin-bottom: 10px;
margin-top: 0;
h4 {
display: inline-block;
margin: 0;
}
button {
display: inline-block;
}
}
#configure-schedules-list {
overflow-x: hidden;
overflow-y: auto;
}
#configure-schedules-overlay {
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 100;
background-color: @black;
opacity: 0;
}
#configure-tower-dialog, #configure-schedules-form-container {
display: none;
overflow-x: hidden;
overflow-y: auto;
padding-top: 25px;
form {
width: 100%;
}
.sublabel {
font-weight: normal;
}
#occurrence-label {
display: inline-block;
}
.occurrence-list {
border: 1px solid @well-border;
padding: 8px 10px;
border-radius: 4px;
background-color: @well;
list-style: none;
margin-bottom: 5px;
}
#date-choice {
display: inline-block;
margin-left: 15px;
font-size: 12px;
.label-inline {
display: inline-block;
vertical-align: middle;
}
input {
margin-bottom: 2px;
height: 11px;
width: 10px;
}
.label-inline:first-child {
padding-bottom: 2px;
margin-right: 10px;
}
.label-inline:nth-child(3) {
margin-right: 10px;
}
}
}
#home_groups_table .actions .cancel { padding-right: 3px; }
.success-badge {

View File

@ -1,7 +1,7 @@
<div class="row">
<div class="col-md-8">
<ul id="scheduler-tabs" class="nav nav-tabs">
<li class="active"><a id="scheduler-link" href="#scheduler-tab" data-toggle="tab"
ng-click="toggleTab($event, 'scheduler-link', 'scheduler-tabs')">Scheduler</a></li>

View File

@ -1,27 +1,34 @@
<!--
angular-scheruler.html
Partial to be injected on inect() method call, providing the form for our widget.
Copyright (c) 2014 Ansible, Inc.
Maintainers:
Maintainers:
Chris Houseknecht
@chouseknecht
@chouseknecht
chouse@ansible.com
-->
<div class="row">
<div class="col-md-12">
<form class="form" role="form" name="scheduler_form" novalidate>
<form class="form" role="form" name="scheduler_form" novalidate>
<div class="form-group">
<label><span class="red-text">*</span> Name</label>
<input type="text" class="form-control input-sm" name="schedulerName" id="schedulerName" ng-model="schedulerName" required placeholder="Schedule name">
<div class="error" ng-show="scheduler_form.schedulerName.$dirty && scheduler_form.schedulerName.$error.required">Schedule name is required</div>
</div>
<div class="form-group" ng-show="cleanupJob">
<label><span class="red-text">*</span>Days of data to keep</label>
<input type="number" class="form-control input-sm" name="schedulerPurgeDays" id="schedulerPurgeDays" min="1" ng-model="schedulerPurgeDays" required placeholder="Days of data to keep">
<div class="error" ng-show="scheduler_form.schedulerPurgeDays.$dirty && scheduler_form.schedulerPurgeDays.$error.required">A value is required</div>
<div class="error" ng-show="scheduler_form.schedulerPurgeDays.$error.number">This is not valid number</div>
</div>
<div class="row">
<div class="col-md-5">
<div class="form-group">
@ -41,7 +48,7 @@
<label><span class="red-text">*</span> Start Time <span class="fmt-help">HH24:MM:SS</span><span class="fmt-help" ng-show="!schedulerShowTimeZone">UTC</span></label>
<div class="input-group">
<input name="schedulerStartHour" id="schedulerStartHour" sch-spinner="scheduler_form" class="scheduler-time-spinner"
ng-model="schedulerStartHour" placeholder="HH24" min="0" max="23" data-zero-pad="2" required
ng-model="schedulerStartHour" placeholder="HH24" min="0" max="23" data-zero-pad="2" required
ng-change="scheduleTimeChange()" >
<span>:</span><input name="schedulerStartMinute" id="schedulerStartMinute" sch-spinner="scheduler_form" class="scheduler-time-spinner" ng-model="schedulerStartMinute" placeholder="MM" min="0" max="59" data-zero-pad="2" required ng-change="scheduleTimeChange()" >
<span>:</span><input name="schedulerStartSecond" id="schedulerStartSecond" sch-spinner="scheduler_form" class="scheduler-time-spinner" ng-model="schedulerStartSecond" placeholder="SS" min="0" max="59" data-zero-pad="2" required ng-change="scheduleTimeChange()" >
@ -50,7 +57,7 @@
</div>
</div>
</div>
<div class="row error-pull-up">
<div class="col-md-12">
<div class="error" ng-show="scheduler_form_schedulerStartDt_error" ng-bind="scheduler_form_schedulerStartDt_error"></div>
@ -72,7 +79,7 @@
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
@ -104,12 +111,12 @@
<div class="col-md-3" style="padding-top:5px">
<input name="monthDay" id="monthDay" sch-spinner="scheduler_form" class="scheduler-spinner"
ng-model="monthDay" min="1" max="31" ng-change="resetError('scheduler_monthDay_error')" >
<div class="error" ng-show="scheduler_monthDay_error">Must be between 1 and 31</div>
<div class="error" ng-show="scheduler_monthDay_error">Must be between 1 and 31</div>
</div>
</div>
</div>
</div>
<div class="row option-pad-bottom" ng-show="schedulerFrequency && schedulerFrequency.value == 'monthly'">
<div class="col-md-12">
<div class="form-group option-pad-left">
@ -141,12 +148,12 @@
<div class="col-md-3 padding-top-slim">
<input name="yearlyMonthDay" id="yearlyMonthDay" sch-spinner="scheduler_form" class="scheduler-spinner"
ng-model="yearlyMonthDay" min="1" max="31" ng-change="resetError('scheduler_yearlyMonthDay_error')" >
<div class="error" ng-show="scheduler_yearlyMonthDay_error">Must be between 1 and 31</div>
<div class="error" ng-show="scheduler_yearlyMonthDay_error">Must be between 1 and 31</div>
</div>
</div>
</div>
</div>
<div class="row option-pad-bottom" ng-show="schedulerFrequency && schedulerFrequency.value == 'yearly'">
<div class="col-md-12">
<div class="form-group option-pad-left">
@ -200,7 +207,7 @@
<div class="input-group">
<input ng-name="schedulerOccurrenceCount" ng-id="schedulerOccurrenceCount" sch-spinner="scheduler_form" class="scheduler-spinner"
ng-model="schedulerOccurrenceCount" min="1" max="999" on-change="resetError('scheduler_occurrenceCount_error')" >
<label class="inline-label">Occurrence(s)</label>
<label class="inline-label">Occurrence(s)</label>
</div>
<div class="error" ng-show="scheduler_occurrenceCount_error">Provide a value between 1 and 999</div>
</div>

View File

@ -1,13 +1,13 @@
/***************************************************************************
* angular-scheruler.js
*
*
* Copyright (c) 2014 Ansible, Inc.
*
* Maintainers:
*
* Chris Houseknecht
* @chouseknecht
* chouse@ansible.com
* chouse@ansible.com
*
*/
@ -23,7 +23,7 @@ angular.module('underscore',[])
angular.module('AngularScheduler', ['underscore'])
.constant('AngularScheduler.partials', '/lib/')
.constant('AngularScheduler.useTimezone', false)
.constant('AngularScheduler.showUTCField', false)
@ -193,24 +193,24 @@ angular.module('AngularScheduler', ['underscore'])
}
return CreateObject(scope, requireFutureStartTime);
};
}])
/**
Return an AngularScheduler object we can use to get the RRule result from user input, check if
user input is valid, reset the form, etc. All the things we need to access and manipulate the
scheduler widget
user input is valid, reset the form, etc. All the things we need to access and manipulate the
scheduler widget
*/
.factory('CreateObject', ['AngularScheduler.useTimezone', '$filter', 'GetRule', 'Inject', 'InjectDetail', 'SetDefaults', '$timezones', 'SetRule', 'InRange',
function(useTimezone, $filter, GetRule, Inject, InjectDetail, SetDefaults, $timezones, SetRule, InRange) {
return function(scope, requireFutureST) {
var fn = function() {
this.scope = scope;
this.useTimezone = useTimezone;
this.requireFutureStartTime = requireFutureST;
// Evaluate user intput and build options for passing to rrule
this.getOptions = function() {
var options = {};
@ -261,7 +261,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.scheduler_occurrenceCount_error = false;
this.scope.scheduler_monthDay_error = false;
this.scope.scheduler_yearlyMonthDay_error = false;
if (this.scope.scheduler_form && this.scope.scheduler_form.schedulerEndDt) {
this.scope.scheduler_form.schedulerEndDt.$setValidity('custom-error', true);
this.scope.scheduler_form.schedulerEndDt.$setPristine();
@ -316,7 +316,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.scheduler_occurrenceCount_error = true;
validity = false;
}
if (this.scope.schedulerFrequency.value === 'weekly' && this.scope.weekDays.length === 0) {
this.scope.scheduler_weekDays_error = true;
validity = false;
@ -341,6 +341,11 @@ angular.module('AngularScheduler', ['underscore'])
$('#schedulerName').addClass('ng-dirty');
validity = false;
}
if(this.scope.cleanupJob===true && !this.scope.scheduler_form.schedulerPurgeDays.$valid){
this.scope.scheduler_form.schedulerPurgeDays.$dirty = true;
$('#schedulerPurgeDays').addClass('ng-dirty');
validity = false;
}
if (this.scope.schedulerEnd.value === 'on') {
if (!/^\d{2}\/\d{2}\/\d{4}$/.test(this.scope.schedulerEndDt)) {
this.scope.scheduler_form.schedulerEndDt.$pristine = false;
@ -364,7 +369,7 @@ angular.module('AngularScheduler', ['underscore'])
$filter('schZeroPad')(now.getHours(),2) + ':' +
$filter('schZeroPad')(now.getMinutes(),2) + ':' +
$filter('schZeroPad')(now.getSeconds(),2) + '.000Z';
adjNow = $timezones.toUTC(dateStr, this.scope.schedulerTimeZone.name); //Adjust to the selected TZ
adjNow = $timezones.toUTC(dateStr, this.scope.schedulerTimeZone.name); //Adjust to the selected TZ
timeNow = adjNow.getTime();
}
else {
@ -425,7 +430,7 @@ angular.module('AngularScheduler', ['underscore'])
this.scope.schedulerName = name;
};
// Read in the HTML partial, compile and inject it into the DOM.
// Read in the HTML partial, compile and inject it into the DOM.
// Pass in the target element's id attribute value or an angular.element()
// object.
this.inject = function(element, showButtons) {
@ -482,7 +487,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('Inject', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) {
return function(params) {
var scope = params.scope,
target = params.target,
buttons = params.buttons;
@ -512,7 +517,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('InjectDetail', ['AngularScheduler.partials', '$compile', '$http', '$log', function(scheduler_partial, $compile, $http) {
return function(params) {
var scope = params.scope,
target = params.target,
showRRule = params.showRRule;
@ -542,11 +547,11 @@ angular.module('AngularScheduler', ['underscore'])
.factory('GetRule', ['$log', function($log) {
return function(params) {
// Convert user inputs to an rrule. Returns rrule object using https://github.com/jkbr/rrule
// **list of 'valid values' found below in LoadLookupValues
// **list of 'valid values' found below in LoadLookupValues
var startDate = params.startDate, // date object or string in yyyy-MM-ddTHH:mm:ss.sssZ format
frequency = params.frequency, // string, optional, valid value from frequencyOptions
interval = params.interval, // integer, optional
interval = params.interval, // integer, optional
occurrenceCount = params.occurrenceCount, //integer, optional
endDate = params.endDate, // date object or string in yyyy-MM-dd format, optional
// ignored if occurrenceCount provided
@ -555,7 +560,7 @@ angular.module('AngularScheduler', ['underscore'])
weekDays = params.weekDays, // integer, optional, valid value from weekdays
setOccurrence = params.setOccurrence, // integer, optional, valid value from occurrences
options = {}, i;
if (angular.isDate(startDate)) {
options.dtstart = startDate;
}
@ -571,7 +576,7 @@ angular.module('AngularScheduler', ['underscore'])
if (frequency && frequency !== 'none') {
options.freq = RRule[frequency.toUpperCase()];
options.interval = interval;
if (weekDays && typeof weekDays === 'string') {
options.byweekday = RRule[weekDays.toUpperCase()];
}
@ -627,7 +632,7 @@ angular.module('AngularScheduler', ['underscore'])
return function(rule, scope) {
var set, result = '', i,
setStartDate = false;
// Search the set of RRule keys for a particular key, returning its value
function getValue(set, key) {
var pair = _.find(set, function(x) {
@ -832,7 +837,7 @@ angular.module('AngularScheduler', ['underscore'])
}
}
}
function isValid() {
// Check what was put into scope vars, and see if anything is
// missing or not quite right.
@ -879,6 +884,7 @@ angular.module('AngularScheduler', ['underscore'])
defaultDay = $filter('schZeroPad')(defaultDate.getDate(), 2),
defaultDateStr = defaultMonth + '/' + defaultDay + '/' + defaultDate.getFullYear();
scope.schedulerName = '';
scope.schedulerPurgeDays = 30;
scope.weekDays = [];
scope.schedulerStartHour = '00';
scope.schedulerStartMinute = '00';
@ -918,7 +924,7 @@ angular.module('AngularScheduler', ['underscore'])
.factory('LoadLookupValues', [ function() {
return function(scope) {
scope.frequencyOptions = [
{ name: 'None (run once)', value: 'none', intervalLabel: '' },
{ name: 'Minute', value: 'minutely', intervalLabel: 'minutes' },
@ -973,7 +979,7 @@ angular.module('AngularScheduler', ['underscore'])
};
}])
// $filter('schZeroPad')(n, pad) -- or -- {{ n | afZeroPad:pad }}
.filter('schZeroPad', [ function() {
return function (n, pad) {
@ -1029,7 +1035,7 @@ angular.module('AngularScheduler', ['underscore'])
};
}])
// Custom directives
// Custom directives
.directive('schSpinner', ['$filter', function($filter) {
return {
require: 'ngModel',
@ -1067,7 +1073,7 @@ angular.module('AngularScheduler', ['underscore'])
}
}
});
$(element).on("click", function () {
$(element).select();
});

View File

@ -106,6 +106,7 @@
<script src="{{ STATIC_URL }}js/forms/LogViewerStatus.js"></script>
<script src="{{ STATIC_URL }}js/forms/LogViewerOptions.js"></script>
<script src="{{ STATIC_URL }}js/lists/Users.js"></script>
<script src="{{ STATIC_URL }}js/lists/ConfigureTowerJobs.js"></script>
<script src="{{ STATIC_URL }}js/lists/Organizations.js"></script>
<script src="{{ STATIC_URL }}js/lists/Admins.js"></script>
<script src="{{ STATIC_URL }}js/lists/Inventories.js"></script>
@ -131,6 +132,7 @@
<script src="{{ STATIC_URL }}js/lists/ScheduledJobs.js"></script>
<script src="{{ STATIC_URL }}js/helpers/SocketHelper.js"></script>
<script src="{{ STATIC_URL }}js/helpers/LoadConfig.js"></script>
<script src="{{ STATIC_URL }}js/helpers/ConfigureTower.js"></script>
<script src="{{ STATIC_URL }}js/helpers/refresh-related.js"></script>
<script src="{{ STATIC_URL }}js/helpers/related-search.js"></script>
<script src="{{ STATIC_URL }}js/helpers/refresh.js"></script>
@ -194,6 +196,7 @@
<a href="" id="mobile_about" ng-click ="viewAboutTower()" ng-hide="portalMode===true">About Tower</a> </li>
<a href="" id="mobile_view_user" ng-click="viewCurrentUser()" ng-hide="portalMode===true">Account Settings</a></li>
<a id="main_configure_tower" ng-click="configureTower()" ng-show="user_is_superuser" href="" ng-hide="portalMode===true">Configure Tower</a></li>
<a href="https://ansibleworks.zendesk.com/anonymous_requests/new" id="mobile_contact_support" target="_blank" ng-hide="portalMode===true">Contact Support</a></li>
<a id="mobile_munin" target="_blank" ng-show="user_is_superuser" href="/munin" ng-hide="portalMode===true">Monitor Tower</a></li>
<a href="#portal" id="mobile_portal_link" ng-hide="portalMode===true">Portal Mode</a></li>
@ -234,8 +237,9 @@
<ul class="nav navbar-nav" id="account-submenu">
<li><a href="" id="main_about" ng-click ="viewAboutTower()" ng-hide="portalMode===true">About Tower</a> </li>
<li><a id="main_view_user" href="" ng-click="viewCurrentUser()" ng-hide="portalMode===true">Account Settings</a></li>
<li><a id="main_configure_tower" ng-click="configureTower()" ng-show="user_is_superuser" href="" ng-hide="portalMode===true">Configure Tower</a></li>
<li><a id="main_contact_support" target="_blank" href="https://ansibleworks.zendesk.com/anonymous_requests/new" ng-hide="portalMode===true">Contact Support</a></li>
<li><a id="main_munin" target="_blank" ng-show="user_is_superuser" href="/munin" ng-hide="portalMode===true">Monitor Tower</a></li>
<li><a id="main_munin" target="_blank" ng-show="user_is_superuser" href="/munin" ng-hide="portalMode===true">Monitor Tower</a></li>
<li><a href="#portal" id="main_view_portal_link" >Portal Mode</a></li>
<li><a id="main_view_license" href="" ng-click="viewLicense()" ng-hide="portalMode===true">View License</a></li>
<li><a id="main_view_leave_portal" href="" ng-click="leavePortal()" ng-show="portalMode===true">Exit Portal</a></li>
@ -252,6 +256,7 @@
<ul class="dropdown-menu" id="account-submenu">
<li><a href="" id="main_about" ng-click ="viewAboutTower()" ng-hide="portalMode===true">About Tower</a> </li>
<li><a id="main_view_user" href="" ng-click="viewCurrentUser()" ng-hide="portalMode===true">Account Settings</a></li>
<li><a id="configure_tower" ng-click="configureTower()" ng-show="user_is_superuser" href="" ng-hide="portalMode===true">Configure Tower</a></li>
<li><a id="main_contact_support" target="_blank" href="https://ansibleworks.zendesk.com/anonymous_requests/new" ng-hide="portalMode===true">Contact Support</a></li>
<li><a id="main_munin" target="_blank" ng-show="user_is_superuser" href="/munin" ng-hide="portalMode===true">Monitor Tower</a></li>
<li><a href="#portal" id="main_view_portal_link" ng-hide="portalMode===true">Portal Mode</a></li>
@ -386,6 +391,36 @@
<div id="help-modal-dialog" style="display: none;"></div>
<div id="license-modal-dialog" style="display: none;"></div>
<div id="about-modal-dialog" style="display: none;" ng-include="'static/partials/cowsay-about.html '"></div>
<div id='configure-tower-dialog' style="display:none">
<div id="configure-jobs" > </div>
<div class="tab-pane" id="configure-schedules-tab">
<div id="configure-schedules-overlay"></div>
<div id="configure-schedules-list"></div>
<div id="configure-schedules-form-container">
<div id="configure-schedules-title">
<h4 ng-bind="schedulesTitle"></h4>
<button type="button" class="close pull-right" ng-click="cancelScheduleForm()">x</button>
</div>
<div id="configure-schedules-form-container-body">
<div id="configure-schedules-form"></div>
<div id="configure-schedules-detail"></div>
</div>
<div id="configure-schedules-buttons" >
<a id="configure-schedules-flip-link" ng-show="formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-search-plus"></i> View Details</a>
<a id="configure-schedules-flip-link" ng-show="!formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-arrow-circle-left"></i> Back to options</a>
<button type="button" class="btn btn-default btn-sm" id="configure-reset-button" ng-click="cancelScheduleForm()"><i class="fa fa-times"></i> Cancel</button>
<button type="button" class="btn btn-primary btn-sm" id="configure-save-button" ng-click="saveScheduleForm()"><i class="fa fa-check"></i> Save</button>
</div>
</div>
</div>
</div>
<div id="prompt-for-days" style="display:none">
<form name="prompt_for_days_form" id="prompt_for_days_form">
How many days of data would you like to <b>keep</b>? <br>
<input type="number" min="1" id="days_to_keep" name="days_to_keep" value="30" ng-required="true" class="form-control ng-pristine ng-invalid-required ng-invalid" style="margin-top:10px;">
<div class="error" ng-show="prompt_for_days_form.days_to_keep.$dirty && copy_form.new_copy_name.$error.required">A value is required!</div></input>
</form>
</div>
</div><!-- container -->