Schedules - audit, bugs, allow HH:MM:SS end time granularity (#1857)

* cleanup unused code artifacts #1851

* fix bug found during audit where empty extra_data was being POSTd as null, #1593

* cleanup schedule helper #1851, update angular-scheduler dependency, automatically set end dt to start dt + 1 day in schedule > add, add hh:mm:ss end date grandularity, resolves #1758, resolves #1856'

* clean up dead schedule dependencies #1851

* fix extra vars in schedule > edit view, fix munge of nested yaml, resolves #1547

squash

* update angular-scheduler to v0.0.19

* re-add ng-toast dependency to bower manifest
This commit is contained in:
Leigh 2016-05-13 10:43:07 -04:00
parent 1e26df639f
commit 89bd66f1f6
26 changed files with 212 additions and 344 deletions

View File

@ -1,6 +1,6 @@
{
"name": "angular-scheduler",
"version": "0.0.14",
"version": "0.0.19",
"authors": [
"Chris Houseknecht <chouse@ansible.com>"
],
@ -36,13 +36,13 @@
"rrule",
"calendar"
],
"_release": "0.0.14",
"_release": "0.0.19",
"_resolution": {
"type": "version",
"tag": "v0.0.14",
"commit": "618c50fabaf774f91db3ed3fb086ac9f45c22136"
"tag": "v0.0.19",
"commit": "952fb090bae47fe748bbb502d7409915c68bb572"
},
"_source": "git://github.com/chouseknecht/angular-scheduler.git",
"_target": "~0.0.14",
"_source": "https://github.com/chouseknecht/angular-scheduler.git",
"_target": "~0.0.19",
"_originalSource": "angular-scheduler"
}

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015 Ansible, Inc.
Copyright (c) 2014 Ansible, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

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,6 +1,6 @@
{
"name": "angular-scheduler",
"version": "0.0.14",
"version": "0.0.19",
"authors": [
"Chris Houseknecht <chouse@ansible.com>"
],
@ -30,7 +30,7 @@
"angular-tz-extensions": "*"
},
"homepage": "https://github.com/chouseknecht/angular-scheduler",
"main": "./lib/angular-scheduler.js",
"main": "git@github.com:chouseknecht/angular-scheduler.git",
"keywords": [
"schedule",
"rrule",

View File

@ -3,7 +3,7 @@
Partial to be injected on inectDetail() method call, providing occurrence list, rrule and a natural language description.
Copyright (c) 2015 Ansible, Inc.
Copyright (c) 2014 Ansible, Inc.
Maintainers:
Chris Houseknecht

View File

@ -1,7 +1,7 @@
/***************************************************************************
* angular-scheruler.css
*
* Copyright (c) 2015 Ansible, Inc.
* Copyright (c) 2014 Ansible, Inc.
*
* Maintainers:
*

View File

@ -1,69 +1,27 @@
<!--
angular-scheruler.html
Partial to be injected on inect() method call, providing the form for our widget.
Copyright (c) 2015 Ansible, Inc.
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">A schedule name is required.</div>
<div class="error" ng-show="scheduler_form.schedulerName.$dirty && scheduler_form.schedulerName.$error.required">Schedule name is required</div>
</div>
<div class="factDetailsNote" ng-if="isFactCleanup"><span class="factDetailsHeader">Note:</span> For facts collected older than the time period specified, save one fact scan (snapshot) per time window (frequency). For example, facts older than 30 days are purged, while one weekly fact scan is kept.
Caution: Setting both numerical variables to "0" will delete all facts.</div>
<div class="form-group" ng-if="cleanupJob && !isFactCleanup">
<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 a valid number.</div>
</div>
<div class="form-group cleanupStretcher factDaysToKeepCompacter" ng-if="isFactCleanup">
<div class="col-md-12">
<label><span class="red-text">*</span> Select a time period after which to remove old facts</label>
</div>
<div class="col-md-6 inputSpacer inputCompactMobile">
<input type="number" id="keep_amount" name="keep_amount" ng-model="keep_amount" ng-required="true" class="form-control input-sm" aw-min=0 aw-max=9999 integer></input>
<div class="error" ng-show="scheduler_form.keep_amount.$dirty && scheduler_form.keep_amount.$error.required">Please enter the number of days you would like to keep this data.</div>
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.number || scheduler_form.keep_amount.$error.integer" >Please enter a valid number.</div>
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.awMin">Please enter a non-negative number.</div>
<div class="error survey_error" ng-show="scheduler_form.keep_amount.$error.awMax">Please enter a number smaller than 9999.</div>
</div>
<div class="col-md-6 inputSpacer">
<select id="keep_unit" name="keep_unit" ng-model="keep_unit" ng-options="type.label for type in keep_unit_choices track by type.value" ng-required="true" class="form-control input-sm"></select>
</div>
</div>
<div class="form-group cleanupStretcher" ng-if="isFactCleanup">
<div class="col-md-12">
<label><span class="red-text">*</span> Select a frequency for snapshot retention</label>
</div>
<div class="col-md-6 inputSpacer inputCompactMobile">
<input type="number" class="form-control input-sm" id="granularity_keep_amount" name="granularity_keep_amount" ng-model="granularity_keep_amount" ng-required="true" aw-min=0 aw-max=9999 >
<div class="error" ng-show="scheduler_form.granularity_keep_amount.$dirty && scheduler_form.granularity_keep_amount.$error.required">Please enter the number of days you would like to keep this data.</div>
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.number || scheduler_form.granularity_keep_amount.$error.integer" >Please enter a valid number.</div>
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.awMin">Please enter a non-negative number.</div>
<div class="error survey_error" ng-show="scheduler_form.granularity_keep_amount.$error.awMax">Please enter a number smaller than 9999.</div>
</div>
<div class="col-md-6 inputSpacer">
<select id="granularity_keep_unit" name="granularity_keep_unit" ng-model="granularity_keep_unit" ng-options="type.label for type in granularity_keep_unit_choices track by type.value" ng-required="true" class="form-control input-sm"></select>
</div>
</div>
<div class="row">
<div class="col-md-5">
<div class="form-group">
@ -83,16 +41,16 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<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()" >
</div>
<div class="error" ng-show="scheduler_startTime_error">The time must be in HH24:MM:SS format.</div>
<div class="error" ng-show="scheduler_startTime_error">Time must be in HH24:MM:SS format</div>
</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>
@ -114,7 +72,7 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
@ -131,7 +89,7 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<input name="schedulerInterval" id="schedulerInterval" sch-spinner="scheduler_form" class="scheduler-spinner"
ng-model="schedulerInterval" min="1" max="999" ng-change="resetError('scheduler_interval_error')">
<label class="inline-label" ng-bind="schedulerIntervalLabel"></label>
<div class="error" ng-show="scheduler_interval_error">Please provide a value between 1 and 999.</div>
<div class="error" ng-show="scheduler_interval_error">Provide a value between 1 and 999</div>
</div>
</div>
</div>
@ -146,12 +104,12 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<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">The day 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">
@ -183,12 +141,12 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<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">The day 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">
@ -225,7 +183,7 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<button type="button" ng-class="weekDaySAClass" class="btn btn-default" data-value="SA" ng-click="setWeekday($event,'sa')">Sat</button>
</div>
</div>
<div class="error" ng-show="scheduler_weekDays_error">Please select one or more days.</div>
<div class="error" ng-show="scheduler_weekDays_error">Select one or more days</div>
</div>
<div class="row">
@ -242,9 +200,9 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<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">Please provide a value between 1 and 999.</div>
<div class="error" ng-show="scheduler_occurrenceCount_error">Provide a value between 1 and 999</div>
</div>
</div>
<div class="col-md-4" ng-show="schedulerEnd && schedulerEnd.value == 'on'">
@ -257,7 +215,7 @@ Caution: Setting both numerical variables to "0" will delete all facts.</div>
<i class="fa fa-calendar"></i></button>
</span>
</div>
<div class="error" ng-show="scheduler_endDt_error">Please provide a valid date.</div>
<div class="error" ng-show="scheduler_endDt_error">Provide a valid date</div>
</div>
</div>
</div>

View File

@ -1,13 +1,13 @@
/***************************************************************************
* angular-scheruler.js
*
* Copyright (c) 2015 Ansible, Inc.
*
* 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)
@ -59,7 +59,7 @@ angular.module('AngularScheduler', ['underscore'])
scope.scheduleRepeatChange();
};
scope.scheduleTimeChange = function() {
scope.scheduleTimeChange = function(callback) {
if (scope.schedulerStartDt === "" || scope.schedulerStartDt === null || scope.schedulerStartDt === undefined) {
scope.startDateError("Provide a valid start date and time");
scope.schedulerUTCTime = '';
@ -91,6 +91,9 @@ angular.module('AngularScheduler', ['underscore'])
':' + scope.schedulerStartSecond + '.000Z');
}
}
if (callback){
callback();
}
};
scope.resetError = function(variable) {
@ -108,7 +111,6 @@ angular.module('AngularScheduler', ['underscore'])
scope.schedulerEnd = scope.endOptions[0];
}
scope.sheduler_frequency_error = false;
scope.$emit("updateSchedulerSelects");
};
@ -169,12 +171,8 @@ angular.module('AngularScheduler', ['underscore'])
}
};
scope.schedulerEndChange = function() {
var dt = new Date(), // date adjusted to local zone automatically
month = $filter('schZeroPad')(dt.getMonth() + 1, 2),
day = $filter('schZeroPad')(dt.getDate(), 2);
scope.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear();
scope.schedulerOccurrenceCount = 1;
scope.schedulerEndChange = function(key, value) {
scope[key] = $filter('schZeroPad')(parseInt(value), 2);
};
// When timezones become available, use to set defaults
@ -195,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 = {};
@ -225,7 +223,10 @@ angular.module('AngularScheduler', ['underscore'])
if (this.scope.schedulerEnd.value === 'on') {
options.endDate = scope.schedulerEndDt.replace(/(\d{2})\/(\d{2})\/(\d{4})/, function(match, p1, p2, p3) {
return p3 + '-' + p1 + '-' + p2;
}) + 'T' + this.scope.schedulerUTCTime.replace(/\d{2}\/\d{2}\/\d{4} /,'').replace(/ UTC/,'') + 'Z';
}) + 'T' +
$filter('schZeroPad')(this.scope.schedulerEndHour,2) + ':' +
$filter('schZeroPad')(this.scope.schedulerEndMinute,2) + ':' +
$filter('schZeroPad')(this.scope.schedulerEndSecond,2)+ 'Z';
}
if (this.scope.schedulerFrequency.value === 'weekly') {
options.weekDays = this.scope.weekDays;
@ -263,7 +264,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();
@ -299,10 +300,7 @@ angular.module('AngularScheduler', ['underscore'])
}
return false;
});
scope.rrule_nlp_description = rrule.toText().replace(/^RRule error.*$/,'Minutely or hourly frequency selected');
if(rrule === "none"){
scope.rrule_nlp_description = 'Natural language description not available';
}
scope.rrule_nlp_description = rrule.toText().replace(/^RRule error.*$/,'Natural language description not available');
scope.rrule = rrule.toString();
}
};
@ -321,7 +319,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;
@ -346,11 +344,6 @@ 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;
@ -374,7 +367,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 {
@ -408,7 +401,6 @@ angular.module('AngularScheduler', ['underscore'])
return validity;
};
var that = this;
that.scope.$on("loadSchedulerDetailPane", function() {
@ -442,7 +434,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) {
@ -499,7 +491,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;
@ -529,7 +521,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;
@ -559,11 +551,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
@ -572,7 +564,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;
}
@ -588,7 +580,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()];
}
@ -644,7 +636,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) {
@ -806,17 +798,13 @@ angular.module('AngularScheduler', ['underscore'])
});
}
scope.schedulerEnd = scope.endOptions[2];
if (useTimezone) {
dt = new Date(value); // date adjusted to local zone automatically
month = $filter('schZeroPad')(dt.getMonth() + 1, 2);
day = $filter('schZeroPad')(dt.getDate(), 2);
scope.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear();
}
else {
scope.schedulerEndDt = value.replace(/T.*$/,'').replace(/(\d{4})-(\d{2})-(\d{2})/, function(match, p1, p2, p3) {
return p2 + '/' + p3 + '/' + p1;
});
}
timeString = value.replace(/^.*T/,'');
scope.schedulerEndHour = $filter('schZeroPad')(timeString.substr(0,2),2);
scope.schedulerEndMinute = $filter('schZeroPad')(timeString.substr(3,2),2);
scope.schedulerEndSecond = $filter('schZeroPad')(timeString.substr(6,2),2);
}
if (key === 'BYMONTH') {
@ -849,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.
@ -896,7 +884,6 @@ 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';
@ -936,7 +923,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' },
@ -991,16 +978,12 @@ angular.module('AngularScheduler', ['underscore'])
};
}])
// $filter('schZeroPad')(n, pad) -- or -- {{ n | afZeroPad:pad }}
.filter('schZeroPad', [ function() {
return function (n, pad) {
var str = (Math.pow(10,pad) + '').replace(/^1/,'') + (n + '').trim();
if (str.substr(str.length - pad) === 'll') {
return undefined;
} else {
return str.substr(str.length - pad);
}
return str.substr(str.length - pad);
};
}])
@ -1051,15 +1034,11 @@ angular.module('AngularScheduler', ['underscore'])
};
}])
// Custom directives
// Custom directives
.directive('schSpinner', ['$filter', function($filter) {
return {
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
if (element.attr("ng-model").indexOf("$parent") > -1) {
scope = scope.$parent;
attr.ngModel = attr.ngModel.split("$parent.")[1];
}
// Add jquerui spinner to 'spinner' type input
var form = attr.schSpinner,
zeroPad = attr.zeroPad,
@ -1084,25 +1063,16 @@ angular.module('AngularScheduler', ['underscore'])
});
}, 100);
},
icons: {
down: "Form-numberInputButton fa fa-angle-down",
up: "Form-numberInputButton fa fa-angle-up"
},
spin: function() {
if (scope[form][attr.ngModel]) {
scope[form][attr.ngModel].$setDirty();
scope[form][attr.ngModel].$dirty = true;
scope[form][attr.ngModel].$pristine = false;
}
scope[form].$setDirty();
ctrl.$dirty = true;
ctrl.$pristine = false;
if (!scope.$$phase) {
scope.$digest();
}
}
});
$('.ui-icon').text('');
$(".ui-icon").removeClass('ui-icon ui-icon-triangle-1-n ui-icon-triangle-1-s');
$(element).on("click", function () {
$(element).select();
});

View File

@ -1,6 +1,6 @@
{
"name": "angular-scheduler",
"version": "0.0.14",
"version": "0.0.19",
"devDependencies": {
"grunt": "~0.4.2",
"grunt-contrib-jshint": "~0.6.3",

View File

@ -11,7 +11,7 @@
"tag": "v1.4.7",
"commit": "6bdc6b4855b416bf029105324080ca7d6aca0e9f"
},
"_source": "git://github.com/angular/bower-angular.git",
"_target": "~1.4.0",
"_source": "https://github.com/angular/bower-angular.git",
"_target": "1.4.7",
"_originalSource": "angular"
}

View File

@ -18,6 +18,6 @@
"commit": "622a619d25358b86a93c2335f88e1884acc9ccb8"
},
"_source": "https://github.com/ivaynberg/select2.git",
"_target": "~4.0.2",
"_target": "~4.0.0",
"_originalSource": "select2"
}

View File

@ -12,7 +12,7 @@
export function ScheduleEditController($scope, $compile, $location, $stateParams, SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
GetBasePath, Wait, Find, LoadDialogPartial, LoadSchedulesScope, GetChoices) {
GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices) {
ClearScope();
@ -82,4 +82,4 @@ GetBasePath, Wait, Find, LoadDialogPartial, LoadSchedulesScope, GetChoices) {
}
ScheduleEditController.$inject = [ '$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest', 'ProcessErrors', 'ReturnToCaller', 'ClearScope',
'GetBasePath', 'Wait', 'Find', 'LoadDialogPartial', 'LoadSchedulesScope', 'GetChoices'];
'GetBasePath', 'Wait', 'Find', 'LoadSchedulesScope', 'GetChoices'];

View File

@ -20,41 +20,9 @@ export default
angular.module('SchedulesHelper', [ 'Utilities', 'RestServices', 'SchedulesHelper', 'SearchHelper', 'PaginationHelpers', listGenerator.name, 'ModalDialog',
'GeneratorHelpers'])
.factory('ShowSchedulerModal', ['$rootScope', function($rootScope) {
return function(params) {
// Set modal dimensions based on viewport width
var buttons,
scope = params.scope;
buttons = [{
"label": "Cancel",
"onClick": function() {
$(this).dialog('close');
},
"icon": "fa-times",
"class": "btn btn-default",
"id": "schedule-close-button"
},{
"label": "Save",
"onClick": function() {
setTimeout(function(){
scope.$apply(function(){
scope.saveSchedule();
});
});
},
"icon": "fa-check",
"class": "btn btn-primary",
"id": "schedule-save-button"
}];
$rootScope.$broadcast("ScheduleFormCreated", scope);
};
}])
.factory('EditSchedule', ['SchedulerInit', 'ShowSchedulerModal', 'Wait',
'Rest', 'ProcessErrors', 'GetBasePath', 'SchedulePost', '$state',
function(SchedulerInit, ShowSchedulerModal, Wait, Rest, ProcessErrors,
.factory('EditSchedule', ['SchedulerInit', '$rootScope', 'Wait', 'Rest',
'ProcessErrors', 'GetBasePath', 'SchedulePost', '$state',
function(SchedulerInit, $rootScope, Wait, Rest, ProcessErrors,
GetBasePath, SchedulePost, $state) {
return function(params) {
var scope = params.scope,
@ -155,7 +123,7 @@ export default
scope.$on("htmlDetailReady", function() {
scheduler.setRRule(schedule.rrule);
scheduler.setName(schedule.name);
ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Edit Schedule' });
$rootScope.$broadcast("ScheduleFormCreated", scope);
});
scope.showRRuleDetail = false;
});
@ -172,7 +140,7 @@ export default
$state.go("^");
});
scope.saveSchedule = function() {
schedule.extra_data = scope.serializedExtraVars;
schedule.extra_data = scope.extraVars;
SchedulePost({
scope: scope,
url: url,
@ -190,7 +158,8 @@ export default
Rest.get()
.success(function(data) {
schedule = data;
scope.serializedExtraVars = schedule.extra_data;
scope.extraVars = data.extra_data === '' ? '---' : '---\n' + jsyaml.safeDump(data.extra_data);
if(schedule.extra_data.hasOwnProperty('granularity')){
scope.isFactCleanup = true;
}
@ -207,10 +176,9 @@ export default
};
}])
.factory('AddSchedule', ['$location', '$stateParams', 'SchedulerInit',
'ShowSchedulerModal', 'Wait', 'GetBasePath', 'Empty',
'SchedulePost', '$state', 'Rest', 'ProcessErrors',
function($location, $stateParams, SchedulerInit, ShowSchedulerModal,
.factory('AddSchedule', ['$location', '$rootScope', '$stateParams',
'SchedulerInit', 'Wait', 'GetBasePath', 'Empty', 'SchedulePost', '$state', 'Rest', 'ProcessErrors',
function($location, $rootScope, $stateParams, SchedulerInit,
Wait, GetBasePath, Empty, SchedulePost, $state, Rest,
ProcessErrors) {
return function(params) {
@ -286,11 +254,12 @@ export default
Wait('start');
$('#form-container').empty();
scheduler = SchedulerInit({ scope: scope, requireFutureStartTime: false });
scope.processSchedulerEndDt();
scheduler.inject('form-container', false);
scheduler.injectDetail('occurrences', false);
scheduler.clear();
scope.$on("htmlDetailReady", function() {
ShowSchedulerModal({ scope: scope, callback: 'DialogReady', title: 'Add Schedule' });
$rootScope.$broadcast("ScheduleFormCreated", scope);
});
scope.showRRuleDetail = false;
@ -356,12 +325,9 @@ export default
};
schedule.extra_data = JSON.stringify(extra_vars);
}
else if (scope.serializedExtraVars){
schedule.extra_data = scope.serializedExtraVars;
}
else if(scope.extraVars){
schedule.extra_data = ToJSON(scope.parseType,
scope.extraVars, false);
schedule.extra_data = scope.parseType === 'yaml' ?
(scope.extraVars === '---' ? "" : jsyaml.safeLoad(scope.extraVars)) : scope.extraVars;
}
Rest.setUrl(url);
if (mode === 'add') {
@ -401,34 +367,6 @@ export default
};
}])
/**
* Inject the scheduler_dialog.html wherever needed
*/
.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, data, status, null, { hdr: 'Error!',
msg: 'Call to ' + url + ' failed. GET returned: ' + status });
});
};
}])
/**
* Flip a schedule's enable flag
*

View File

@ -420,6 +420,4 @@
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
</div>

View File

@ -1,7 +1,6 @@
<div class="tab-pane" id="job_templates">
<div ui-view></div>
<div ng-cloak id="htmlTemplate" class="Panel"></div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
<div ng-include="'/static/partials/logviewer.html'"></div>
</div>

View File

@ -13,7 +13,7 @@
<form class="form Form"
role="form"
name="scheduler_form_new"
name="scheduler_form"
novalidate>
<div class="form-group SchedulerForm-formGroup">
@ -25,13 +25,13 @@
type="text"
class="form-control input-sm
Form-textInput"
ng-class="{'RepeatFrequencyOptions-nameBorderErrorFix': scheduler_form_new.$dirty && scheduler_form_new.schedulerName.$error.required}"
ng-class="{'RepeatFrequencyOptions-nameBorderErrorFix': scheduler_form.$dirty && scheduler_form.schedulerName.$error.required}"
name="schedulerName"
id="schedulerName"
ng-model="schedulerName" required
placeholder="Schedule name">
<div class="error"
ng-show="scheduler_form_new.$dirty && scheduler_form_new.schedulerName.$error.required">
ng-show="scheduler_form.$dirty && scheduler_form.schedulerName.$error.required">
A schedule name is required.
</div>
</div>
@ -85,7 +85,7 @@
<div class="input-group SchedulerTime">
<input name="schedulerStartHour"
id="schedulerStartHour"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
ScheduleTime-input SpinnerInput"
ng-model="schedulerStartHour"
@ -99,7 +99,7 @@
</span>
<input name="schedulerStartMinute"
id="schedulerStartMinute"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="schedulerStartMinute"
@ -113,7 +113,7 @@
</span>
<input name="schedulerStartSecond"
id="schedulerStartSecond"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="schedulerStartSecond"
@ -188,7 +188,7 @@
</label>
<input name="schedulerInterval"
id="schedulerInterval"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.schedulerInterval"
@ -224,7 +224,7 @@
<input
name="monthDay"
id="monthDay"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner SpinnerInput"
ng-model="$parent.monthDay"
min="1" max="31"
@ -301,7 +301,7 @@
</select>
<input name="yearlyMonthDay"
id="yearlyMonthDay"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.yearlyMonthDay"
@ -459,8 +459,7 @@
ng-options="e.name for e in endOptions"
required
class="MakeSelect2
form-control input-sm"
ng-change="schedulerEndChange()">
form-control input-sm">
</select>
</div>
</div>
@ -475,7 +474,7 @@
<input
ng-name="schedulerOccurrenceCount"
ng-id="schedulerOccurrenceCount"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.schedulerOccurrenceCount"
@ -574,7 +573,7 @@
</form>
<div class="SchedulerFormDetail-container
SchedulerFormDetail-container--error"
ng-show="!schedulerIsValid && scheduler_form_new.$dirty">
ng-show="!schedulerIsValid && scheduler_form.$dirty">
<p class="SchedulerFormDetail-errorText">
The scheduler options are invalid or incomplete.
</p>

View File

@ -20,7 +20,6 @@
<dashboard></dashboard>
</div>
<div>
<!-- <div ng-include="'/static/partials/schedule_dialog.html'"></div>
<!--
<div ng-include="'/static/partials/logviewer.html'"></div>
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div> -->
-->

View File

@ -43,7 +43,5 @@
<div id="schedule-dialog-target"></div>
<div ng-include="'/static/partials/logviewer.html'"></div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
</div>
</div>

View File

@ -2,5 +2,4 @@
<div ui-view></div>
<div ng-cloak id="htmlTemplate" class="Panel"></div>
<div ng-include="'/static/partials/logviewer.html'"></div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
</div>

View File

@ -1,5 +1,3 @@
<div class="Panel">
<div id="schedule-list-target"></div>
</div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>

View File

@ -1,13 +0,0 @@
<div id="scheduler-modal-dialog">
<ul id="scheduler-tabs" class="nav nav-tabs">
<li class="active"><a href="#schedule" id="schedule-link" data-toggle="tab" ng-click="toggleTab($event, 'schedule-link', 'scheduler-tabs')">Options</a></li>
<li><a href="#occurrences" id="occurrence-link" data-toggle="tab" ng-click="toggleTab($event, 'occurrence-link', 'scheduler-tabs')">Details</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="schedule">
<div id="form-container"></div>
</div>
<div class="tab-pane" id="occurrences">
</div>
</div>
</div>

View File

@ -14,15 +14,19 @@
export default [
'$scope', '$compile', '$location', '$stateParams', 'SchedulesList', 'Rest',
'ProcessErrors', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'Wait',
'Find', 'LoadDialogPartial', 'LoadSchedulesScope', 'GetChoices', '$q',
'Find', 'LoadSchedulesScope', 'GetChoices', '$q',
function ($scope, $compile, $location, $stateParams,
SchedulesList, Rest, ProcessErrors, ReturnToCaller, ClearScope,
GetBasePath, Wait, Find, LoadDialogPartial, LoadSchedulesScope, GetChoices,
GetBasePath, Wait, Find, LoadSchedulesScope, GetChoices,
$q) {
ClearScope();
$scope.schedulerStartDT = 'test';
var base, id, url,parentObject, title;
$scope.schedulerStartDT = 'test';
base = $location.path().replace(/^\//, '').split('/')[0];
if (base === 'management_jobs') {

View File

@ -2,5 +2,3 @@
<div class="Panel">
<div id="schedule-list-target"></div>
</div>
<div ng-include="'/static/partials/schedule_dialog.html'"></div>

View File

@ -4,12 +4,27 @@
* All Rights Reserved
*************************************************/
export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait',
export default ['$compile', '$filter', '$state', '$stateParams', 'AddSchedule', 'Wait',
'$scope', '$rootScope', 'CreateSelect2', 'ParseTypeChange', 'GetBasePath',
'Rest', 'ParamPass',
function($compile, $state, $stateParams, AddSchedule, Wait, $scope,
function($compile, $filter, $state, $stateParams, AddSchedule, Wait, $scope,
$rootScope, CreateSelect2, ParseTypeChange, GetBasePath, Rest, ParamPass) {
$scope.processSchedulerEndDt = function(){
// set the schedulerEndDt to be equal to schedulerStartDt + 1 day @ midnight
var dt = new Date($scope.schedulerUTCTime);
// increment date by 1 day
dt.setDate(dt.getDate() + 1);
var month = $filter('schZeroPad')(dt.getMonth() + 1, 2),
day = $filter('schZeroPad')(dt.getDate(), 2);
$scope.$parent.schedulerEndDt = month + '/' + day + '/' + dt.getFullYear();
};
// initial end @ midnight values
$scope.schedulerEndHour = "00";
$scope.schedulerEndMinute = "00";
$scope.schedulerEndSecond = "00";
$scope.$on("ScheduleFormCreated", function(e, scope) {
$scope.hideForm = false;
$scope = angular.extend($scope, scope);
@ -37,7 +52,10 @@ export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait',
"yearlyOtherMonth",
"schedulerEnd",
"schedulerOccurrenceCount",
"schedulerEndDt"
"schedulerEndDt",
"schedulerEndHour",
"schedulerEndMinute",
"schedularEndSecond"
], function() {
$scope.$emit("formUpdated");
}, true);
@ -73,20 +91,6 @@ export default ['$compile', '$state', '$stateParams', 'AddSchedule', 'Wait',
field_id: 'SchedulerForm-extraVars'
});
});
$scope.$watch('extraVars', function(){
if ($scope.parseType === 'yaml'){
try{
$scope.serializedExtraVars = jsyaml.safeLoad($scope.extraVars);
}
catch(err){ return; }
}
else if ($scope.parseType === 'json'){
try{
$scope.serializedExtraVars = JSON.parse($scope.extraVars);
}
catch(err){ return; }
}
});
}
else if ($state.current.name === 'projectSchedules.add'){
$scope.extraVars = '---';

View File

@ -51,18 +51,6 @@ export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$
// extra_data field is not manifested in the UI when scheduling a Management Job
if ($state.current.name !== ('managementJobSchedules.add' || 'managementJobSchedules.edit')){
$scope.$on('ScheduleFound', function(){
if ($scope.parseType === 'yaml'){
try{
$scope.extraVars = '---\n' + jsyaml.safeDump($scope.serializedExtraVars);
}
catch(err){ return; }
}
else if ($scope.parseType === 'json'){
try{
$scope.extraVars = JSON.stringify($scope.serializedExtraVars, null, ' ');
}
catch(err){ return; }
}
ParseTypeChange({
scope: $scope,
variable: 'extraVars',
@ -70,21 +58,6 @@ export default ['$compile', '$state', '$stateParams', 'EditSchedule', 'Wait', '$
field_id: 'SchedulerForm-extraVars'
});
});
$scope.$watch('extraVars', function(){
if ($scope.parseType === 'yaml'){
try{
$scope.serializedExtraVars = jsyaml.safeLoad($scope.extraVars);
}
catch(err){ return; }
}
else if ($scope.parseType === 'json'){
try{
$scope.serializedExtraVars = JSON.parse($scope.extraVars);
}
catch(err){ return; }
}
});
}
EditSchedule({

View File

@ -12,7 +12,7 @@
<div id="SchedulerFormTarget">
<form class="form Form"
role="form"
name="scheduler_form_new"
name="scheduler_form"
novalidate>
<div class="form-group SchedulerForm-formGroup">
@ -24,13 +24,13 @@
type="text"
class="form-control input-sm
Form-textInput"
ng-class="{'RepeatFrequencyOptions-nameBorderErrorFix': scheduler_form_new.$dirty && scheduler_form_new.schedulerName.$error.required}"
ng-class="{'RepeatFrequencyOptions-nameBorderErrorFix': scheduler_form.$dirty && scheduler_form.schedulerName.$error.required}"
name="schedulerName"
id="schedulerName"
ng-model="schedulerName" required
placeholder="Schedule name">
<div class="error"
ng-show="scheduler_form_new.$dirty && scheduler_form_new.schedulerName.$error.required">
ng-show="scheduler_form.$dirty && scheduler_form.schedulerName.$error.required">
A schedule name is required.
</div>
</div>
@ -52,7 +52,7 @@
sch-date-picker
placeholder="mm/dd/yyyy"
required
ng-change="scheduleTimeChange()" >
ng-change="scheduleTimeChange(processSchedulerEndDt)" >
<span class="input-group-btn">
<button
class="btn btn-default btn-sm
@ -84,7 +84,7 @@
<div class="input-group SchedulerTime">
<input name="schedulerStartHour"
id="schedulerStartHour"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
ScheduleTime-input SpinnerInput"
ng-model="schedulerStartHour"
@ -98,7 +98,7 @@
</span>
<input name="schedulerStartMinute"
id="schedulerStartMinute"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="schedulerStartMinute"
@ -112,7 +112,7 @@
</span>
<input name="schedulerStartSecond"
id="schedulerStartSecond"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="schedulerStartSecond"
@ -120,18 +120,6 @@
min="0" max="59" data-zero-pad="2"
required
ng-change="scheduleTimeChange()" >
<!-- <div class="form-group
SchedulerTime-utc"
ng-show="schedulerShowUTCStartTime">
<label
class="SchedulerTime-utcLabel">
UTC Start Time
</label>
<div id="schedulerUTCTime"
class="SchedulerTime-utcTime">
{{ schedulerUTCTime.split("UTC")[0] }}
</div>
</div> -->
</div>
<div class="error"
ng-show="scheduler_startTime_error">
@ -187,7 +175,7 @@
</label>
<input name="schedulerInterval"
id="schedulerInterval"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.schedulerInterval"
@ -223,7 +211,7 @@
<input
name="monthDay"
id="monthDay"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner SpinnerInput"
ng-model="$parent.monthDay"
min="1" max="31"
@ -300,7 +288,7 @@
</select>
<input name="yearlyMonthDay"
id="yearlyMonthDay"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.yearlyMonthDay"
@ -458,8 +446,7 @@
ng-options="e.name for e in endOptions"
required
class="MakeSelect2
form-control input-sm"
ng-change="schedulerEndChange()">
form-control input-sm">
</select>
</div>
</div>
@ -474,7 +461,7 @@
<input
ng-name="schedulerOccurrenceCount"
ng-id="schedulerOccurrenceCount"
sch-spinner="scheduler_form_new"
sch-spinner="scheduler_form"
class="scheduler-spinner
SpinnerInput"
ng-model="$parent.schedulerOccurrenceCount"
@ -522,6 +509,65 @@
Please provide a valid date.
</div>
</div>
<div class="form-group SchedulerForm-formGroup"
ng-if="schedulerEnd && schedulerEnd.value == 'on'">
<label class="Form-inputLabel">
<span class="red-text">*</span>
End Time
<span class="fmt-help"
ng-show="schedulerShowTimeZone">
(HH24:MM:SS)
</span>
<span class="fmt-help"
ng-show="!schedulerShowTimeZone">
(HH24:MM:SS UTC)
</span>
</label>
<div class="input-group SchedulerTime">
<input name="schedulerEndHour"
id="schedulerEndHour"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
ScheduleTime-input SpinnerInput"
ng-model="$parent.schedulerEndHour"
placeholder="HH24"
aw-min="0" min="0" aw-max="23"
max="23" data-zero-pad="2" required
ng-change="schedulerEndChange('schedulerEndHour', $parent.schedulerEndHour)" >
<span
class="SchedulerTime-separator">
:
</span>
<input name="schedulerEndMinute"
id="$parent.schedulerEndMinute"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="$parent.schedulerEndMinute"
placeholder="MM"
min="0" max="59" data-zero-pad="2"
required
ng-change="schedulerEndChange('schedulerEndMinute', $parent.schedulerEndMinute)" >
<span
class="SchedulerTime-separator">
:
</span>
<input name="schedulerEndSecond"
id="schedulerEndSecond"
sch-spinner="scheduler_form"
class="scheduler-time-spinner
SchedulerTime-input SpinnerInput"
ng-model="$parent.schedulerEndSecond"
placeholder="SS"
min="0" max="59" data-zero-pad="2"
required
ng-change="schedulerEndChange('schedulerEndSecond', $parent.schedulerEndSecond)" >
</div>
<div class="error"
ng-show="scheduler_startTime_error">
The time must be in HH24:MM:SS format.
</div>
</div>
</div>
<div class="RepeatFrequencyOptions-subFormBorderFixer"
ng-show="schedulerFrequency.value && schedulerFrequency.value !== 'none'">
@ -529,7 +575,7 @@
</form>
<div class="SchedulerFormDetail-container
SchedulerFormDetail-container--error"
ng-show="!schedulerIsValid && scheduler_form_new.$dirty">
ng-show="!schedulerIsValid && scheduler_form.$dirty">
<p class="SchedulerFormDetail-errorText">
The scheduler options are invalid or incomplete.
</p>