Skip to content

Commit

Permalink
Merge pull request #2701 from icfantv/execution_window
Browse files Browse the repository at this point in the history
(core) add day selector to execution window
  • Loading branch information
icfantv committed Sep 19, 2016
2 parents 0871a45 + f2c828b commit 74fc68c
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 12 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"ecmaFeatures": {
"jsx": false,
"modules": true,
},
"extends": "eslint:recommended",
"rules": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { DAYS_OF_WEEK} from './daysOfWeek';

describe('Component: Execution Window Day Picker', () => {

let $componentController;
beforeEach(window.module(require('./executionWindowDayPicker.component.js')));
beforeEach(window.inject((_$componentController_) => $componentController = _$componentController_));

function constructController(bindings) {
return $componentController('executionWindowDayPicker', null, bindings);
}

it('should not have any days selected when the days property is not defined', () => {
const ctrl = constructController({days: undefined});
expect(ctrl.days).toBeUndefined();
});

it('should not have any days selected when the days property is null', () => {
const ctrl = constructController({days: null});
expect(ctrl.days).toBe(null);
});

it('should not have any days selected when the days property is an empty array', () => {
const ctrl = constructController({days: []});
expect(ctrl.days.length).toBe(0);
});

DAYS_OF_WEEK.forEach((day) => {
it(`should have ${day.key} selected when the days property contains ${day.ordinal}`, () => {
const ctrl = constructController({days: [day.ordinal]});
expect(ctrl.days.length).toBe(1);
expect(ctrl.days[0]).toBe(day.ordinal);
});
});

it('should select all the days when the all button is clicked', () => {
const ctrl = constructController({});
ctrl.all();
expect(ctrl.days.length).toBe(7);
});

it('should select none of the days when the none button is clicked', () => {
const ctrl = constructController({});
ctrl.all();
expect(ctrl.days.length).toBe(7);
ctrl.none();
expect(ctrl.days.length).toBe(0);
});

it('should select just the weekdays when the weekday button is clicked', () => {
const ctrl = constructController({});
ctrl.weekdays();
expect(ctrl.days.length).toBe(5);
expect(ctrl.days).toEqual([2,3,4,5,6]);
});

it('should select just the weekend when the weekend button is clicked', () => {
const ctrl = constructController({});
ctrl.weekend();
expect(ctrl.days.length).toBe(2);
expect(ctrl.days[0]).toBe(1); // sunday
expect(ctrl.days[1]).toBe(7); // saturday
});

it('should specify whether or not a day is selected', () => {
const ctrl = constructController({
days: [1]
});
expect(ctrl.daySelected(1)).toBe(true);
expect(ctrl.daySelected(2)).toBe(false);

ctrl.days = [1, 2];
expect(ctrl.daySelected(2)).toBe(true);
expect(ctrl.daySelected(3)).toBe(false);
});

it('should add a day to the model when selected', () => {
const ctrl = constructController({});
ctrl.updateModel(DAYS_OF_WEEK[0]);
expect(ctrl.daySelected(1)).toBe(true);
});

it('should remove a day from the model when unselected', () => {
const ctrl = constructController({
days: [1] // pre-select sunday
});
ctrl.updateModel(DAYS_OF_WEEK[0]);
expect(ctrl.daySelected(1)).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export const DAYS_OF_WEEK = [
{
key: 'sunday',
label: 'Sun',
ordinal: 1
}, {
key: 'monday',
label: 'Mon',
ordinal: 2
}, {
key: 'tuesday',
label: 'Tue',
ordinal: 3
}, {
key: 'wednesday',
label: 'Wed',
ordinal: 4
}, {
key: 'thursday',
label: 'Thu',
ordinal: 5
}, {
key: 'friday',
label: 'Fri',
ordinal: 6
}, {
key: 'saturday',
label: 'Sat',
ordinal: 7
}
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="btn-group">
<button ng-repeat="day in ::$ctrl.DAYS_OF_WEEK"
type="button"
class="btn btn-default"
ng-click="$ctrl.updateModel(day)"
ng-class="{ active: $ctrl.daySelected(day.ordinal) }">{{ ::day.label }}</button>
</div>
<div class="button-controls">
<span class="btn btn-link" ng-click="$ctrl.all()">All</span>
<span class="btn btn-link" ng-click="$ctrl.none()">None</span>
<span class="btn btn-link" ng-click="$ctrl.weekdays()">Weekdays</span>
<span class="btn btn-link" ng-click="$ctrl.weekend()">Weekend</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const angular = require('angular');

import { DAYS_OF_WEEK } from './daysOfWeek';

class ExecutionWindowDayPickerController {

constructor() {
this.DAYS_OF_WEEK = DAYS_OF_WEEK;
}

daySelected(ordinal) {
const days = new Set(this.days);
return days.has(ordinal);
}

all() {
this.days = [1, 2, 3, 4, 5, 6, 7];
}

none() {
this.days = [];
}

weekdays() {
this.days = [2, 3, 4, 5, 6];
}

weekend() {
this.days = [1, 7];
}

updateModel(day) {

if (!this.days) {
this.days = []; // for pre-existing pipelines, the 'days' property will not exist
}

const days = new Set(this.days);
if (days.has(day.ordinal)) {
this.days = this.days.filter((_day) => _day !== day.ordinal);
}
else {
this.days.push(day.ordinal);
}
}
}

module.exports = angular.module('spinnaker.core.pipeline.stage.executionWindows.dayPicker', [])
.component('executionWindowDayPicker', {
bindings: {
days: '='
},
controller: ExecutionWindowDayPickerController,
templateUrl: require('./executionWindowDayPicker.component.html')
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,24 @@
</div>
</div>
<div ng-if="stage.restrictExecutionDuringTimeWindow">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h5>
<strong>Days of the Week</strong>
<small>(No days selected implies the stage will execute on any day if triggered)</small>
</h5>
<p class="execution-window-days-of-week">
<execution-window-day-picker days="stage.restrictedExecutionWindow.days"></execution-window-day-picker>
</p>
</div>
</div>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<p>
<strong>Time of Day</strong>
</p>
</div>
</div>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="execution-window-graph">
Expand Down Expand Up @@ -75,13 +93,11 @@
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-1">
<button class="btn btn-block btn-add-trigger add-new" ng-click="executionWindowsCtrl.addExecutionWindow()">
<span class="glyphicon glyphicon-plus-sign"></span> Add an execution window
</button>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-1">
<button class="btn btn-block btn-add-trigger add-new" ng-click="executionWindowsCtrl.addExecutionWindow()">
<span class="glyphicon glyphicon-plus-sign"></span> Add an execution window
</button>
</div>
</div>

</div>
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ execution-windows {
height: @graph_height;
border: 1px solid @mid_lighter_grey;
position: relative;
margin: 20px 0;
margin: 0 0 0 10px;

@label-height: 20px;
@divider-height: @graph_height - @label-height;

.execution-window {
height: @graph_height + 10;
height: @graph_height - 1;
background-color: @healthy_green;
position: absolute;
bottom: 0;
z-index: 3;
&:after {
content: '';
width: calc(~"100% + 2px");
width: calc(~"100% + 1px");
border: 1px solid darken(@mid_lighter_grey, 20%);
border-bottom-width: 0;
height: @graph_height - @label-height + 10;
height: @graph_height - @label-height - 1;
position: absolute;
top: 0;
left: -1px;
Expand Down Expand Up @@ -92,3 +92,11 @@ execution-windows {
margin-left: 20px;
}
}

p.execution-window-days-of-week {
margin-left: 10px;

div.button-controls {
display: inline-block;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

import { DAYS_OF_WEEK } from './daysOfWeek';

let angular = require('angular');

module.exports = angular.module('spinnaker.core.pipeline.stage.executionWindows.details.controller', [
Expand All @@ -13,9 +15,28 @@ module.exports = angular.module('spinnaker.core.pipeline.stage.executionWindows.

$scope.configSections = ['windowConfig', 'taskStatus'];

// yes, this is ugly - when we replace the execution window w/ an ng2 component, this will go away. i promise
function replaceDays(days) {
const daySet = new Set(days);
return DAYS_OF_WEEK.filter(day => daySet.has(day.ordinal)).map(day => day.label);
}

// ditto
function getDayText() {
let dayText = 'Everyday';
const days = $scope.stage.context.restrictedExecutionWindow.days;
if (days && (days.length > 0)) {
const daysAsText = replaceDays(days);
dayText = daysAsText.join(', ');
}

return dayText;
}

function initialize() {
executionDetailsSectionService.synchronizeSection($scope.configSections);
$scope.detailsSection = $stateParams.details;
$scope.dayText = getDayText();
}

initialize();
Expand All @@ -27,7 +48,7 @@ module.exports = angular.module('spinnaker.core.pipeline.stage.executionWindows.
return match.status !== 'RUNNING';
};

let data = { skipRemainingWait: true };
let data = {skipRemainingWait: true};
confirmationModalService.confirm({
header: 'Really skip execution window?',
buttonText: 'Skip',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ <h5>Execution Windows Configuration</h5>
<strong>&nbsp;<system-timezone></system-timezone></strong>
</dd>
</div>
<dt>On</dt>
<dd>{{ ::dayText }}</dd>
</dl>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = angular.module('spinnaker.core.pipeline.stage.executionWindows'
require('./executionWindowsStage.js'),
require('./executionWindows.transformer.js'),
require('./executionWindows.directive.js'),
require('./executionWindowDayPicker.component'),
require('./executionWindowsDetails.controller'),
require('../stage.module.js'),
require('../core/stage.core.module.js'),
Expand Down

0 comments on commit 74fc68c

Please sign in to comment.