Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #46: Override notification settings #345

Merged
merged 11 commits into from
Oct 13, 2017
Merged
2 changes: 2 additions & 0 deletions saas/axops/src/ui/src/app/common/components.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { CommitPanelComponent } from './commit-panel/commit-panel.component';
import { CommitAuthorComponent } from './commit-author/commit-author.component';
import { CommitDescriptionComponent } from './commit-description/commit-description.component';
import { MultipleServiceLaunchPanelComponent } from './multiple-service-launch-panel/multiple-service-launch-panel.component';
import { SetupJobNotificationsComponent } from './multiple-service-launch-panel/setup-job-notifications/setup-job-notifications.component';
import { LaunchPanelService } from './multiple-service-launch-panel/launch-panel.service';
import { BranchesPanelComponent } from './branches-panel/branches-panel.component';
import { BranchSelectorPanelComponent } from './branch-selector-panel/branch-selector-panel.component';
Expand Down Expand Up @@ -87,6 +88,7 @@ let components: any[] = [
CommitAuthorComponent,
CommitDescriptionComponent,
MultipleServiceLaunchPanelComponent,
SetupJobNotificationsComponent,
BranchesPanelComponent,
BranchSelectorPanelComponent,
CommitSelectorPanelComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import * as _ from 'lodash';
import { Component, Output, EventEmitter } from '@angular/core';
import { Component, Output, EventEmitter, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Observable';

import {Artifact, Commit, Template, Task, Project, ProjectAction, Branch } from '../../model';
import { Artifact, Commit, Template, Task, Project, ProjectAction, Branch } from '../../model';
import { TemplateService, TaskService, CommitsService } from '../../services';
import { NotificationsService } from 'argo-ui-lib/src/components';
import { Session, HtmlForm, MULTIPLE_SERVICE_LAUNCH_PANEL_TABS } from './multiple-service-launch-panel.view-models';
import { SetupJobNotificationsComponent } from './setup-job-notifications/setup-job-notifications.component';

@Component({
selector: 'ax-multiple-service-launch-panel',
Expand All @@ -18,14 +19,17 @@ import { Session, HtmlForm, MULTIPLE_SERVICE_LAUNCH_PANEL_TABS } from './multipl
export class MultipleServiceLaunchPanelComponent {
@Output() submitted: EventEmitter<any> = new EventEmitter();

@ViewChild(SetupJobNotificationsComponent)
private setupJobNotifications: SetupJobNotificationsComponent;

public templates: Template[] = [];
public templatesToSubmit: Template[] = [];
public allSelected: boolean = false;
public selectedItems: number = 0;
public templateLoader: boolean = false;
public commit: Commit = new Commit();
public isVisibleSelectServiceTemplatesPanel: boolean = false;
public selectingScreen: boolean = true;
public stepNumber: 1 | 2 | 3 = 1;
public activeElementId: number = 0;
public isSubmitClicked: boolean = false;
public summaryErrorMessage: boolean = false;
Expand Down Expand Up @@ -82,7 +86,7 @@ export class MultipleServiceLaunchPanelComponent {
this.task = null;
this.projectInfo = null;
this.resubmit = resubmit;
this.selectingScreen = true;
this.stepNumber = 1;

this.withCommitOnly = withCommitOnly;
if (options) {
Expand All @@ -95,11 +99,11 @@ export class MultipleServiceLaunchPanelComponent {
this.isVisibleSelectServiceTemplatesPanel = true;
this.next();
}
this.selectingScreen = false;
this.stepNumber = 2;
} else {
this.task = null;
this.projectInfo = null;
this.selectingScreen = true;
this.stepNumber = 1;
}

if (commit) {
Expand Down Expand Up @@ -133,7 +137,7 @@ export class MultipleServiceLaunchPanelComponent {
this.session = new Session();
this.templates = [];
this.templatesToSubmit = [];
this.selectingScreen = true;
this.stepNumber = 1;
this.activeElementId = 0;
this.allSelected = false;
this.allForms.reset();
Expand Down Expand Up @@ -250,18 +254,23 @@ export class MultipleServiceLaunchPanelComponent {
}) !== undefined;
}

goToNextStep() {
this.stepNumber += 1;
this.next();
}

next() {
this.selectingScreen = false;
this.templatesToSubmit = this.templates.filter(item => item.selected);

this.prepareForms(this.templatesToSubmit);
}

submit() {
let notifications = this.setupJobNotifications.getNotifications();
this.isSubmitClicked = true;
this.summaryErrorMessage = this.allForms.invalid;

if (this.allForms.valid) {
if (this.allForms.valid && notifications) {
if (this.resubmit) {
this.resubmitTask(this.task, this.resubmit);
} else {
Expand All @@ -271,6 +280,7 @@ export class MultipleServiceLaunchPanelComponent {
observableList.push(this.taskService.launchTask({
template_id: this.templatesToSubmit[index].id,
arguments: this.listParameters(this.allForms.controls[index.toString()]['controls']),
notifications: notifications
}));
});

Expand Down Expand Up @@ -323,7 +333,6 @@ export class MultipleServiceLaunchPanelComponent {
this.getTemplates(branch.repo);
}


private prepareForms(templates: Template[], resubmitFailedParameters?: any) {
templates.forEach((template, index) => {
let newForm = new FormGroup({});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<ax-sliding-panel [show]="isVisibleSelectServiceTemplatesPanel" [hasCloseButton]="false" [hasNoPadding]="true" (closePanel)="closePanel()">
<sliding-panel-header>
<button *ngIf="selectingScreen" class="ax-button ax-button--base" [ngClass]="{'disabled': !isAnyTemplateSelected()}"
type="button" (click)="next()" [disabled]="!isAnyTemplateSelected()" axButtonWave>Next</button>
<button *ngIf="!selectingScreen" class="ax-button ax-button--base" [ngClass]="{'disabled': summaryErrorMessage}"
<button *ngIf="stepNumber === 1" class="ax-button ax-button--base" [ngClass]="{'disabled': !isAnyTemplateSelected()}"
type="button" (click)="goToNextStep()" [disabled]="!isAnyTemplateSelected()" axButtonWave>Next</button>
<button *ngIf="stepNumber === 2" class="ax-button ax-button--base"
type="button" (click)="goToNextStep()" [disabled]="false" axButtonWave>Next</button>
<button *ngIf="stepNumber === 3" class="ax-button ax-button--base" [ngClass]="{'disabled': summaryErrorMessage}"
type="button" (click)="submit()" [disabled]="summaryErrorMessage || templateLoader"
axButtonWave>SUBMIT<span *ngIf="templatesToSubmit?.length > 1"> ALL</span></button>
<button class="ax-button" type="button" (click)="closePanel()" axButtonWave>Cancel</button>
Expand All @@ -14,7 +16,7 @@
</ul>
</sliding-panel-header>
<sliding-panel-body>
<div class="panel-box" *ngIf="selectingScreen">
<div class="panel-box" *ngIf="stepNumber === 1">
<div class="panel-box__content">
<div class="panel-box__title">
Select templates to create jobs
Expand Down Expand Up @@ -105,7 +107,7 @@ <h3>Templates</h3>
</div>
</div>

<div class="panel-box" *ngIf="!selectingScreen">
<div class="panel-box" *ngIf="stepNumber === 2">
<div class="panel-box__summary-error" *ngIf="summaryErrorMessage">
Please enter the required parameters and submit again.
</div>
Expand Down Expand Up @@ -195,6 +197,9 @@ <h3 *ngIf="!templateLoader && isActiveFormEmpty">
</div>
</div>
</div>
<div class="panel-box" *ngIf="stepNumber === 3">
<ax-setup-job-notifications></ax-setup-job-notifications>
</div>
</sliding-panel-body>
</ax-sliding-panel>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import * as _ from 'lodash';
import { Component, OnInit } from '@angular/core';

import { FilterMultiSelect } from 'argo-ui-lib/src/components';

import { PolicyNotification } from '../../../model';
import { CustomRegex } from '../../customValidators/CustomRegex';
import { AuthenticationService } from '../../../services';

interface NotificationObject {
jobEvents: FilterMultiSelect;
isArgoUsersAndGroupsVisible: boolean;
isSlackChannelsVisible: boolean;
isEmailVisible: boolean;
rules: PolicyNotification;
outsideUsers: string[];
filteredOutsideUsers: string[];
validationMessages: any;
}

@Component({
selector: 'ax-setup-job-notifications',
templateUrl: './setup-job-notifications.html',
styles: [ require('./setup-job-notifications.scss') ],
})
export class SetupJobNotificationsComponent implements OnInit {

public notification: NotificationObject = {
jobEvents: {
items: [
{name: 'on_change', value: 'on_change', checked: false},
{name: 'on_cron', value: 'on_cron', checked: false},
{name: 'on_failure', value: 'on_failure', checked: false},
{name: 'on_pull_request', value: 'on_pull_request', checked: false},
{name: 'on_pull_request_merge', value: 'on_pull_request_merge', checked: false},
{name: 'on_push', value: 'on_push', checked: false},
{name: 'on_start', value: 'on_start', checked: false},
{name: 'on_success', value: 'on_success', checked: false},
],
selectedItems: [],
messages: {
name: 'JOB EVENTS',
},
isVisible: false,
isStaticList: true,
isDisplayedInline: true,
},

isArgoUsersAndGroupsVisible: false,
isSlackChannelsVisible: false,
isEmailVisible: false,
rules: {
whom: [],
when: []
},
outsideUsers: [],
filteredOutsideUsers: [],
validationMessages: {
jobEvents: { show: false, text: 'You have to choose at least one Job Event' },
wrongFormatRecipients: { show: false, text: 'Recipients have to be an email format' },
missingRecipients: { show: false, text: 'You have to choose at least one recipient from any of the groups' },
}
};

public rules: PolicyNotification[] = [];
public notificationsList: any[] = [];
public isVisibleUserSelectorPanel: boolean = false;
public isVisibleSlackPanel: boolean = false;
public selectedId: number = 0;

constructor(private authenticationService: AuthenticationService) {
}

ngOnInit() {
if (!this.rules.length) {
this.addDefaultNotificationRule();
}
}

public onRuleChange(when: string[], index) {
this.notificationsList[index].rules.when = when;
this.notificationsList[index].validationMessages.jobEvents.show = false;
}

public addNotificationRule() {
this.notificationsList.push(JSON.parse(JSON.stringify(this.notification)));
}

public removeNotificationRule(index) {
this.notificationsList.splice(index, 1);
}

public openUserSelectorPanel(index) {
this.isVisibleUserSelectorPanel = true;
this.selectedId = index;
this.notificationsList[index].validationMessages.missingRecipients.show = false;
}

public closeUserSelectorPanel() {
this.isVisibleUserSelectorPanel = false;
}

public openSlackChannelPanel(index) {
this.isVisibleSlackPanel = true;
this.selectedId = index;
this.notificationsList[index].validationMessages.missingRecipients.show = false;
}

public closeSlackChannelPalen() {
this.isVisibleSlackPanel = false;
}

public getOutsideUsers(index) {
this.notificationsList[index].filteredOutsideUsers =
this.notificationsList[index].rules.whom.recipients.filter(recipient => recipient.indexOf('@user') !== -1).sort();
this.notificationsList[index].outsideUsers = this.notificationsList[index].filteredOutsideUsers.map(user => user.substring(0, user.indexOf('@user')));
return this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@user') !== -1).sort();
}

public getOnlyUsersAndGroups(index) {
return this.notificationsList.length ?
this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@slack') === -1 && recipient.indexOf('@user') === -1).sort() : [];
}

public getOnlySlackChannels(index) {
return this.notificationsList.length ?
this.notificationsList[index].rules.whom.filter(recipient => recipient.indexOf('@slack') !== -1).sort() : [];
}

public updateOnlyUsersAndGroupsList(users: string[]) {
this.notificationsList[this.selectedId].rules.whom =
this.notificationsList[this.selectedId].rules.whom.filter(recipient => (recipient.indexOf('@slack') !== -1 || recipient.indexOf('@user') !== -1)).sort();
this.updateNotificationWhomList(users);
}

public updateSlackChannelsList(channels: string[]) {
this.notificationsList[this.selectedId].rules.whom =
this.notificationsList[this.selectedId].rules.whom.filter(recipient => (recipient.indexOf('@slack') === -1)).sort();
let axSlackChannelsList = channels.map(channel => `${channel}@slack`);
this.updateNotificationWhomList(axSlackChannelsList);
}

public updateNotificationWhomList(list: string[]) {
this.notificationsList[this.selectedId].rules.whom =
this.notificationsList[this.selectedId].rules.whom.concat(list).filter((value, index, self) => self.indexOf(value) === index );
}

public updateOutsideUsers(users: string, index) {
this.selectedId = index;
this.notificationsList[index].outsideUsers = users.split(',');
this.notificationsList[index].filteredOutsideUsers =
this.notificationsList[index].outsideUsers.filter(user => CustomRegex.emailPattern.test(user.trim())).map(user => `${user}@user`);
this.notificationsList[index].validationMessages.wrongFormatRecipients.show = false;
this.notificationsList[index].validationMessages.missingRecipients.show = false;
}

public argoUsersAndGroupsCheckboxChange(notification, index) {
notification.isArgoUsersAndGroupsVisible = !notification.isArgoUsersAndGroupsVisible;
if (!notification.isArgoUsersAndGroupsVisible) {
notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@slack') !== -1 || recipient.indexOf('@user') !== -1)).sort();
} else {
this.openUserSelectorPanel(index);
}
}

public emailCheckboxChange(notification) {
notification.isEmailVisible = !notification.isEmailVisible;
if (!notification.isEmailVisible) {
notification.outsideUsers = [];
notification.filteredOutsideUsers = [];
notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@user') === -1)).sort();
}
}

public slackChannelsCheckboxChange(notification, index) {
notification.isSlackChannelsVisible = !notification.isSlackChannelsVisible;
if (!notification.isSlackChannelsVisible) {
notification.rules.whom = notification.rules.whom.filter(recipient => (recipient.indexOf('@slack') === -1)).sort();
} else {
this.openSlackChannelPanel(index);
}
}

public getNotifications(): PolicyNotification[] {
let isAnyError = false;
this.notificationsList.forEach(notification => {
if (!notification.rules.when.length) {
notification.validationMessages.jobEvents.show = true;
isAnyError = true;
}

if (notification.outsideUsers.length !== notification.filteredOutsideUsers.length && notification.outsideUsers.toString().length) {
notification.validationMessages.wrongFormatRecipients.show = true;
isAnyError = true;
} else {
// remove all '@user' elements from rules.whom
notification.rules.whom = notification.rules.whom.filter(item => item.indexOf('@user') === -1);
this.updateNotificationWhomList(notification.filteredOutsideUsers);
}

if (!notification.rules.whom.length) {
notification.validationMessages.missingRecipients.show = true;
isAnyError = true;
}
});

// if there is error in any notification rule, don't allow to submit
if (isAnyError) {
return;
}

this.rules = this.notificationsList.map(notification => {
return notification.rules;
});

return _.uniqBy(this.rules, v => [v.whom, v.when].join());
}

private addDefaultNotificationRule() {
let notification = JSON.parse(JSON.stringify(this.notification));
notification.rules = {
whom: [this.authenticationService.getUsername()],
when: ['on_failure', 'on_success']
};
notification.isArgoUsersAndGroupsVisible = true;

this.notificationsList.push(notification);
}
}
Loading