src/app/tasks/task-schedule-create/task-schedule-create.component.ts
Component handling a creation of a task schedule.
encapsulation | ViewEncapsulation.None |
selector | app-task-schedule-create |
styleUrls | styles.scss |
templateUrl | ./task-schedule-create.component.html |
Properties |
|
Methods |
constructor(routingStateService: RoutingStateService, tasksService: TasksService, router: Router, groupRouteService: GroupRouteService, blockerService: BlockerService, notificationService: NotificationService, route: ActivatedRoute)
|
||||||||||||||||||||||||||||||||
Constructor
Parameters :
|
buildForm | ||||||||
buildForm(schedule: )
|
||||||||
Build the form
Parameters :
Returns :
void
|
cancel |
cancel()
|
Cancel
Returns :
void
|
detailsTask | ||||||||
detailsTask(taskName: string)
|
||||||||
Navigate to the task page
Parameters :
Returns :
void
|
ngOnInit |
ngOnInit()
|
On Init
Returns :
void
|
submit | ||||||||
submit(schedule: )
|
||||||||
Create a schedule
Parameters :
Returns :
void
|
form |
form:
|
Type : FormGroup
|
Form Group |
kvValidators |
kvValidators:
|
Validators args / props component |
Private ngUnsubscribe$ |
ngUnsubscribe$:
|
Type : Subject<any>
|
Unsubscribe |
schedule$ |
schedule$:
|
Type : Observable<any>
|
Schedule Object |
submitted |
submitted:
|
Default value : false
|
Form Submitted |
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { RoutingStateService } from '../../shared/services/routing-state.service';
import { Observable, EMPTY, Subject, of, throwError } from 'rxjs';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { catchError, finalize, map, mergeMap, takeUntil } from 'rxjs/operators';
import { TasksService } from '../tasks.service';
import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
import { TaskScheduleCreateValidator } from './task-schedule-create.validator';
import { GroupRouteService } from '../../shared/services/group-route.service';
import { NotificationService } from '../../shared/services/notification.service';
import { TaskLaunchValidator } from '../task-launch/task-launch.validator';
import { TaskSchedule } from '../model/task-schedule';
import { Page } from '../../shared/model/page';
import { AppError } from '../../shared/model/error.model';
import { KvRichTextValidator } from '../../shared/components/kv-rich-text/kv-rich-text.validator';
import { BlockerService } from '../../shared/components/blocker/blocker.service';
/**
* Component handling a creation of a task schedule.
*
* @author Damien Vitrac
*/
@Component({
selector: 'app-task-schedule-create',
templateUrl: './task-schedule-create.component.html',
styleUrls: ['styles.scss'],
encapsulation: ViewEncapsulation.None
})
export class TaskScheduleCreateComponent implements OnInit {
/**
* Unsubscribe
*/
private ngUnsubscribe$: Subject<any> = new Subject();
/**
* Schedule Object
*/
schedule$: Observable<any>;
/**
* Form Group
*/
form: FormGroup;
/**
* Form Submitted
*/
submitted = false;
/**
* Validators args / props component
*/
kvValidators = {
args: {
key: [Validators.required],
value: []
},
props: {
key: [Validators.required, TaskLaunchValidator.key],
value: []
}
};
/**
* Constructor
*
* @param {RoutingStateService} routingStateService
* @param {TasksService} tasksService
* @param {Router} router
* @param {GroupRouteService} groupRouteService
* @param {BlockerService} blockerService
* @param {NotificationService} notificationService
* @param {ActivatedRoute} route
*/
constructor(private routingStateService: RoutingStateService,
private tasksService: TasksService,
private router: Router,
private groupRouteService: GroupRouteService,
private blockerService: BlockerService,
private notificationService: NotificationService,
private route: ActivatedRoute) {
}
/**
* On Init
*/
ngOnInit() {
this.schedule$ = this.route.params
.pipe(
mergeMap(
(params: Params) => {
let result: Observable<any>;
if (this.groupRouteService.isSimilar(params.id)) {
if (this.groupRouteService.group(params.id)) {
result = of(this.groupRouteService.group(params.id));
} else {
return throwError(`Group selection not found.`);
}
} else {
result = this.tasksService.getDefinition(params.id);
}
return result.pipe(map((data) => {
if (this.groupRouteService.isSimilar(params.id)) {
return {
params: params,
taskDefinitions: data
};
} else {
return {
params: params,
taskDefinitions: [data.name]
};
}
}));
}
),
mergeMap(
(schedule) => this.tasksService.getSchedules({ q: '', page: 0, size: 10000, sort: null, order: null })
.pipe(map((schedules: Page<TaskSchedule>) => {
return {
params: schedule.params,
taskDefinitions: schedule.taskDefinitions,
schedules: schedules.items.map((item) => item.name.toLowerCase())
};
})),
),
map((schedule) => {
this.buildForm(schedule);
return schedule;
}),
catchError((error) => {
this.notificationService.error(error.toString());
this.cancel();
return EMPTY;
})
);
}
/**
* Build the form
*/
buildForm(schedule) {
const names = new FormArray(schedule.taskDefinitions.map(() => {
return new FormControl('', [
Validators.required, ((control: FormControl) => {
return TaskScheduleCreateValidator.existName(control, schedule.schedules);
})
]);
}), [TaskScheduleCreateValidator.uniqueName]);
this.form = new FormGroup({
'cron': new FormControl('', [Validators.required, TaskScheduleCreateValidator.cron]),
'names': names,
'args': new FormControl('', KvRichTextValidator.validateKvRichText(this.kvValidators.args)),
'props': new FormControl('', KvRichTextValidator.validateKvRichText(this.kvValidators.props))
});
}
/**
* Create a schedule
*/
submit(schedule) {
this.submitted = true;
if (!this.form.valid) {
this.notificationService.error('Some field(s) are missing or invalid.');
} else {
const getClean = (val: string): Array<string> => val.split('\n')
.filter((a) => a !== '');
const taskArguments = getClean(this.form.get('args').value);
const taskProperties = getClean(this.form.get('props').value);
const cronExpression = this.form.get('cron').value;
const scheduleParams = schedule.taskDefinitions
.map((taskName: string, index: number) => ({
args: taskArguments.join(','),
props: taskProperties.join(','),
cronExpression: cronExpression,
task: taskName,
schedulerName: (this.form.get('names') as FormArray).controls
.map((control: FormControl) => control.value)[index]
})
);
this.blockerService.lock();
this.tasksService.createSchedules(scheduleParams)
.pipe(takeUntil(this.ngUnsubscribe$), finalize(() => this.blockerService.unlock()))
.subscribe(
data => {
if (scheduleParams.length === 1) {
this.notificationService.success(`Successfully schedule creation "${scheduleParams[0].schedulerName}"`);
} else {
this.notificationService.success(`Successfully ${scheduleParams.length} schedules creation`);
}
this.cancel();
},
error => {
this.notificationService.error(AppError.is(error) ? error.getMessage() : error);
}
);
}
}
/**
* Navigate to the task page
* @param {string} taskName
*/
detailsTask(taskName: string) {
this.router.navigate([`/tasks/definitions/${taskName}`]);
}
/**
* Cancel
*/
cancel() {
this.routingStateService.back('/tasks/definitions');
}
}
<app-page *ngIf="schedule$ | async as schedule; else loading">
<app-page-head>
<app-page-head-back [defaultUrl]="'/tasks/definitions'"></app-page-head-back>
<app-page-head-title>Create <strong>schedule(s)</strong></app-page-head-title>
</app-page-head>
<div dataflowLayoutType type="large">
<div class="dataflow-alert dataflow-alert-info">
Create a schedule for a task, simply provide a <strong>name</strong> and a <strong>CRON expression</strong>.
<br>Optionally, you can add <strong>properties</strong> and <strong>arguments</strong>.
</div>
<form class="schedule-form task-create" [formGroup]="form" name="form" (submit)="submit(schedule)">
<div>
<h2>Setup the schedule</h2>
<div *ngIf="schedule.taskDefinitions.length == 1">
<div class="row" style="margin-bottom: 12px">
<div class="col-xs-4">
<label>Task Name:</label>
</div>
<div class="col-xs-20">
<a style="cursor: pointer" (click)="detailsTask(schedule.taskDefinitions[0])">
{{ schedule.taskDefinitions[0] }}</a>
</div>
</div>
<div class="row form-group" [class.has-error]="submitted && form.get('names').controls[0].invalid">
<div class="col-xs-4">
<label class="control-label" for="name">Schedule name:</label>
</div>
<div class="col-xs-10">
<div formArrayName="names">
<input id="name" name="name" [formControl]="form.get('names').controls[0]"
class="form-control input-sm"/>
<div class="errors-name" *ngIf="submitted && form.get('names.0').invalid">
<div *ngIf="form.get('names.0').errors?.required" class="help-block">The name is required.</div>
<div *ngIf="form.get('names.0').errors?.exist" class="help-block">The name already exists.</div>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="schedule.taskDefinitions.length > 1">
<div class="row form-group">
<div class="col-xs-4">
<label class="control-label">Tasks:</label>
</div>
<div class="col-xs-10">
<div class="alert alert-danger" style="max-width: 700px"
*ngIf="submitted && form.get('names').errors?.notUnique">
Duplicate schedule name on the form.
</div>
<table class="table table-form table-form-stripped" style="max-width: 700px">
<thead>
<tr>
<th style="padding-top: 4px" width="50%">Task</th>
<th style="padding-top: 4px" width="50%">Schedule name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of schedule.taskDefinitions; index as i">
<td class="td-label"><a style="cursor: pointer" (click)="detailsTask(item)">{{ item }}</a></td>
<td>
<div [class.has-error]="submitted && form.get('names.' + i).invalid">
<input [formControl]="form.get('names').controls[i]" type="text" class="form-control input-sm"/>
<div *ngIf="submitted && form.get('names.' + i).invalid">
<div *ngIf="form.get('names.' + i).errors?.required" class="help-block">The name is required.
</div>
<div *ngIf="form.get('names.' + i).errors?.exist" class="help-block">The name already exists.
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row form-group" [class.has-error]="submitted && form.get('cron').invalid">
<div class="col-xs-4">
<label class="control-label" for="cron">Cron Expression:</label>
</div>
<div class="col-xs-20">
<div style="max-width: 260px">
<input id="cron" name="cron" formControlName="cron" class="form-control input-sm"/>
<div class="errors-cron" *ngIf="submitted && form.get('cron').invalid">
<span class="help-block"
*ngIf="form.get('cron').errors?.required">The cron expression is required.</span>
<span class="help-block"
*ngIf="submitted && form.get('cron').errors?.formatError">The cron expression is not valid.</span>
</div>
</div>
</div>
</div>
<h2>Task Arguments and Properties</h2>
<div class="row form-group" [class.has-error]="form.get('args').invalid && submitted">
<div class="col-xs-4">
<label class="control-label">Arguments:</label>
</div>
<div class="col-xs-10">
<app-kv-rich-text [validators]="kvValidators.args" [formControl]="form.get('args')"
placeholder="--myarg=myvalue"></app-kv-rich-text>
<span class="help-block" *ngIf="form.get('args').invalid && submitted">
One or more arguments are invalid.<br/>Example: <code>myarg=myvalue</code>.
</span>
</div>
</div>
<div class="row form-group" [class.has-error]="form.get('props').invalid && submitted">
<div class="col-xs-4">
<label class="control-label">Parameters:</label>
</div>
<div class="col-xs-10">
<app-kv-rich-text [validators]="kvValidators.props" [formControl]="form.get('props')"
placeholder="app.myparam=myvalue"></app-kv-rich-text>
<span class="help-block" *ngIf="form.get('props').invalid && submitted">
One or more parameters are invalid.<br/>Example: <code>app.myarg=myvalue</code>.
</span>
</div>
</div>
<!--
<div class="builder">
<div class="row">
<div class="col-md-12">
<div class="col-1-layout" formArrayName="args">
<h3>Task Arguments</h3>
<p>You can add optional task arguments before launching the task.</p>
<table class="table table-actions table-form">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr *ngFor="let f of form.get('args').controls;let i = index"
[formGroupName]="i">
<td>
<div [class.has-error]="submitted && form.get('args.' + i).invalid">
<input formControlName="key" type="text" class="form-control input-sm"/>
<div *ngIf="submitted && form.get('args.' + i + '.key').invalid"
class="help-block">Invalid key
</div>
<div *ngIf="submitted && form.get('args.' + i).invalid" class="help-block">
Invalid key
</div>
</div>
</td>
<td>
<div [class.has-error]="submitted && form.get('args.' + i).invalid">
<input formControlName="val" type="text" class="form-control input-sm"/>
<div *ngIf="submitted && form.get('args.' + i + '.val').invalid"
class="help-block">Invalid value
</div>
</div>
</td>
<td class="table-actions" width="10px" nowrap="">
<div class="actions-btn" role="group">
<button [disabled]="form.get('args').controls.length == (i+1)" type="button"
class="btn btn-danger"
(click)="form.get('args').removeAt(i)">
<span class="fa fa-times" style="margin-top: 2px"></span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-12">
<div class="col-2-layout" formArrayName="params">
<h3>Task Properties</h3>
<p>You can add optional task properties before launching the task.</p>
<table class="table table-actions table-form">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr *ngFor="let f of form.get('params').controls;let i = index"
[formGroupName]="i">
<td>
<div [class.has-error]="submitted && form.get('params.' + i).invalid">
<input formControlName="key" type="text" class="form-control input-sm"/>
<div *ngIf="submitted && form.get('params.' + i + '.key').invalid" class="help-block">
The key should start with `app.` or `deployer.` or `scheduler.`.
</div>
<div class="help-block"
*ngIf="submitted && form.get('params.' + i).invalid && !form.get('params.' + i + '.key').invalid">
Invalid key
</div>
</div>
</td>
<td>
<div [class.has-error]="form.get('params.' + i).invalid">
<input formControlName="val" type="text" class="form-control input-sm"/>
<div *ngIf="submitted && form.get('params.' + i + '.val').invalid" class="help-block">Invalid
value
</div>
</div>
</td>
<td class="table-actions" width="10px" nowrap="">
<div class="actions-btn" role="group">
<button [disabled]="form.get('params').controls.length == (i + 1)" type="button"
class="btn btn-danger" (click)="form.get('params').removeAt(i)">
<span class="fa fa-times" style="margin-top: 2px"></span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
-->
</div>
<app-page-actions>
<button (click)="cancel()" type="button" class="btn btn-default">Cancel</button>
<button id="btn-submit" type="submit" class="btn btn-primary">Schedule the task</button>
</app-page-actions>
</form>
</div>
</app-page>
<ng-template #loading>
<app-loader></app-loader>
</ng-template>