blob: 8b31445137ec360bcb5aad14ed37b8188a9de261 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Component, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation, ChangeDetectorRef, Inject } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
import * as _moment from 'moment';
import 'moment-timezone';
import { SchedulerService } from '../../core/services';
import { SchedulerModel, WeekdaysModel } from './scheduler.model';
import { SchedulerCalculations } from './scheduler.calculations';
import { HTTP_STATUS_CODES, CheckUtils } from '../../core/util';
import { ScheduleSchema } from './scheduler.model';
import { map } from 'rxjs/operators';
@Component({
selector: 'dlab-scheduler',
templateUrl: './scheduler.component.html',
styleUrls: ['./scheduler.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class SchedulerComponent implements OnInit {
readonly CheckUtils = CheckUtils;
public model: SchedulerModel;
public selectedStartWeekDays: WeekdaysModel = WeekdaysModel.setDefault();
public selectedStopWeekDays: WeekdaysModel = WeekdaysModel.setDefault();
public notebook: any;
public infoMessage: boolean = false;
public timeReqiered: boolean = false;
public terminateDataReqiered: boolean = false;
public inherit: boolean = false;
public allowInheritView: boolean = false;
public parentInherit: boolean = false;
public enableSchedule: boolean = false;
public enableIdleTime: boolean = false;
public enableIdleTimeView: boolean = false;
public considerInactivity: boolean = false;
public date_format: string = 'YYYY-MM-DD';
public timeFormat: string = 'HH:mm';
public weekdays: string[] = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
public schedulerForm: FormGroup;
public destination: any;
public zones: {};
public tzOffset: string = _moment().format('Z');
public startTime = { hour: 9, minute: 0, meridiem: 'AM' };
public endTime = { hour: 8, minute: 0, meridiem: 'PM' };
public terminateTime = null;
public inactivityLimits = { min: 120, max: 10080 };
public integerRegex: string = '^[0-9]*$';
@ViewChild('resourceSelect', { static: false }) resource_select;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
public toastr: ToastrService,
public dialogRef: MatDialogRef<SchedulerComponent>,
private formBuilder: FormBuilder,
private schedulerService: SchedulerService,
private changeDetector: ChangeDetectorRef
) { }
ngOnInit() {
this.open(this.data.notebook, this.data.type, this.data.resource);
}
public open(notebook, type, resource?): void {
this.notebook = notebook;
this.zones = _moment.tz.names()
.map(item => [_moment.tz(item).format('Z'), item])
.sort()
.reduce((memo, item) => {
memo[item[0]] ? memo[item[0]] += `, ${item[1]}` : memo[item[0]] = item[1];
return memo;
}, {});
this.model = new SchedulerModel(
response => {
if (response.status === HTTP_STATUS_CODES.OK) {
this.toastr.success('Schedule data were successfully saved', 'Success!');
this.dialogRef.close();
}
},
error => this.toastr.error(error.message || 'Scheduler configuration failed!', 'Oops!'),
() => {
this.formInit();
this.changeDetector.detectChanges();
this.destination = (type === 'EXPLORATORY') ? this.notebook : resource;
this.destination.type = type;
this.selectedStartWeekDays.reset();
this.selectedStopWeekDays.reset();
this.allowInheritView = false;
if (this.destination.type === 'СOMPUTATIONAL') {
this.allowInheritView = true;
this.getExploratorySchedule(this.notebook.project, this.notebook.name, this.destination.computational_name);
this.checkParentInherit();
} else if (this.destination.type === 'EXPLORATORY') {
this.allowInheritView = this.checkIsActiveSpark();
this.getExploratorySchedule(this.notebook.project, this.notebook.name);
}
},
this.schedulerService
);
}
public onDaySelect($event, day, action) {
if (action === 'start') {
this.selectedStartWeekDays[day.toLowerCase()] = $event.source.checked;
} else if (action === 'stop') {
this.selectedStopWeekDays[day.toLowerCase()] = $event.source.checked;
}
}
public toggleInherit($event) {
this.inherit = $event.checked;
if (this.destination.type === 'СOMPUTATIONAL' && this.inherit) {
this.getExploratorySchedule(this.notebook.project, this.notebook.name);
this.schedulerForm.get('startDate').disable();
} else {
this.schedulerForm.get('startDate').enable();
}
}
public toggleSchedule($event) {
this.enableSchedule = $event.checked;
this.timeReqiered = false;
this.allowInheritView = this.destination.type === 'СOMPUTATIONAL' || this.checkIsActiveSpark();
this.enableSchedule && this.enableIdleTime && this.toggleIdleTimes({ checked: false });
(this.enableSchedule && !(this.destination.type === 'СOMPUTATIONAL' && this.inherit))
? this.schedulerForm.get('startDate').enable()
: this.schedulerForm.get('startDate').disable();
this.enableSchedule ? this.schedulerForm.get('finishDate').enable() : this.schedulerForm.get('finishDate').disable();
this.enableSchedule ? this.schedulerForm.get('terminateDate').enable() : this.schedulerForm.get('terminateDate').disable();
if (this.enableSchedule && $event.source) this.enableIdleTimeView = false;
}
public toggleIdleTimes($event) {
const control = this.schedulerForm.controls.inactivityTime;
this.enableIdleTime = $event.checked;
this.enableIdleTime && this.enableSchedule && this.toggleSchedule({ checked: false });
this.allowInheritView = false;
if (!this.enableIdleTime) {
this.allowInheritView = this.destination.type === 'СOMPUTATIONAL' || this.checkIsActiveSpark();
control.setValue('');
} else {
!control.value && control.setValue(this.inactivityLimits.min);
this.enableIdleTimeView = true;
}
}
public setInactivity(...params) {
this.model.setInactivityTime(params).subscribe((response: any) => {
if (response.status === HTTP_STATUS_CODES.OK) {
this.toastr.success('Schedule data were successfully saved', 'Success!');
this.dialogRef.close();
}
},
error => this.toastr.error(error.message || 'Scheduler configuration failed!', 'Oops!'));
}
public inactivityCounter($event, action: string): void {
$event.preventDefault();
const value = this.schedulerForm.controls.inactivityTime.value;
const newValue = (action === 'increment' ? Number(value) + 10 : Number(value) - 10);
this.schedulerForm.controls.inactivityTime.setValue(newValue);
}
public scheduleInstance_btnClick() {
if (this.enableIdleTimeView) {
this.enableIdleTime ? this.setScheduleByInactivity() : this.resetScheduler();
} else {
this.enableSchedule ? this.setScheduleByTime() : this.resetScheduler();
}
}
private resetScheduler() {
const resource = this.destination.type === 'СOMPUTATIONAL' ? this.destination.computational_name : null;
this.model.resetSchedule(this.notebook.name, resource)
.subscribe(() => {
this.resetDialog();
this.toastr.success('Schedule data were successfully deleted', 'Success!');
this.dialogRef.close();
});
}
private setScheduleByTime() {
const data = {
startDate: this.schedulerForm.controls.startDate.value,
finishDate: this.schedulerForm.controls.finishDate.value,
terminateDate: this.schedulerForm.controls.terminateDate.value
};
const terminateDateTime = (data.terminateDate && this.terminateTime)
? `${_moment(data.terminateDate).format(this.date_format)} ${SchedulerCalculations.convertTimeFormat(this.terminateTime)}`
: null;
if (!this.startTime && !this.endTime && !this.terminateTime && this.enableSchedule) {
this.timeReqiered = true;
return false;
}
if ((data.terminateDate && !this.terminateTime) || (!data.terminateDate && this.terminateTime)) {
this.terminateDataReqiered = true;
return false;
}
const selectedDays = Object.keys(this.selectedStartWeekDays);
const parameters: ScheduleSchema = {
begin_date: data.startDate ? _moment(data.startDate).format(this.date_format) : null,
finish_date: data.finishDate ? _moment(data.finishDate).format(this.date_format) : null,
start_time: this.startTime ? SchedulerCalculations.convertTimeFormat(this.startTime) : null,
end_time: this.endTime ? SchedulerCalculations.convertTimeFormat(this.endTime) : null,
start_days_repeat: selectedDays.filter(el => Boolean(this.selectedStartWeekDays[el])).map(day => day.toUpperCase()),
stop_days_repeat: selectedDays.filter(el => Boolean(this.selectedStopWeekDays[el])).map(day => day.toUpperCase()),
timezone_offset: this.tzOffset,
sync_start_required: this.inherit,
check_inactivity_required: this.enableIdleTime,
terminate_datetime: terminateDateTime
};
if (this.destination.type === 'СOMPUTATIONAL') {
this.model.confirmAction(this.notebook.project, this.notebook.name, parameters, this.destination.computational_name);
} else {
parameters['consider_inactivity'] = this.considerInactivity;
this.model.confirmAction(this.notebook.project, this.notebook.name, parameters);
}
}
private setScheduleByInactivity() {
const data = {
sync_start_required: this.parentInherit,
check_inactivity_required: this.enableIdleTime,
max_inactivity: this.schedulerForm.controls.inactivityTime.value
};
(this.destination.type === 'СOMPUTATIONAL')
? this.setInactivity(this.notebook.project, this.notebook.name, data, this.destination.computational_name)
: this.setInactivity(this.notebook.project, this.notebook.name, { ...data, consider_inactivity: this.considerInactivity });
}
private formInit(start?: string, end?: string, terminate?: string) {
this.schedulerForm = this.formBuilder.group({
startDate: { disabled: this.inherit, value: start ? _moment(start).format() : null },
finishDate: { disabled: false, value: end ? _moment(end).format() : null },
terminateDate: { disabled: false, value: terminate ? _moment(terminate).format() : null },
inactivityTime: [this.inactivityLimits.min,
[Validators.compose([Validators.pattern(this.integerRegex), this.validInactivityRange.bind(this)])]]
});
}
private getExploratorySchedule(project, resource, resource2?) {
this.schedulerService.getExploratorySchedule(project, resource, resource2).subscribe(
(params: ScheduleSchema) => {
if (params) {
params.start_days_repeat.filter(key => (this.selectedStartWeekDays[key.toLowerCase()] = true));
params.stop_days_repeat.filter(key => (this.selectedStopWeekDays[key.toLowerCase()] = true));
this.inherit = params.sync_start_required;
this.tzOffset = params.timezone_offset;
this.startTime = params.start_time ? SchedulerCalculations.convertTimeFormat(params.start_time) : null;
this.endTime = params.end_time ? SchedulerCalculations.convertTimeFormat(params.end_time) : null;
this.formInit(params.begin_date, params.finish_date, params.terminate_datetime);
this.schedulerForm.controls.inactivityTime.setValue(params.max_inactivity || this.inactivityLimits.min);
this.enableIdleTime = params.check_inactivity_required;
this.considerInactivity = params.consider_inactivity || false;
if (params.terminate_datetime) {
const terminate_datetime = params.terminate_datetime.split(' ');
this.schedulerForm.controls.terminateDate.setValue(terminate_datetime[0]);
this.terminateTime = SchedulerCalculations.convertTimeFormat(terminate_datetime[1]);
}
(this.enableIdleTime && params.max_inactivity)
? this.toggleIdleTimes({ checked: true })
: this.toggleSchedule({ checked: true });
}
},
error => this.resetDialog());
}
private checkParentInherit() {
this.schedulerService.getExploratorySchedule(this.notebook.project, this.notebook.name)
.subscribe((res: any) => this.parentInherit = res.sync_start_required);
}
private validInactivityRange(control) {
if (control)
return this.enableIdleTime
? (control.value
&& control.value >= this.inactivityLimits.min
&& control.value <= this.inactivityLimits.max ? null : { valid: false })
: control.value;
}
private checkIsActiveSpark() {
return this.notebook.resources.length > 0 && this.notebook.resources.some(el => el.image === 'docker.dlab-dataengine'
&& (el.status !== 'terminated' && el.status !== 'terminating' && el.status !== 'failed'));
}
private resetDialog() {
this.infoMessage = false;
this.timeReqiered = false;
this.terminateDataReqiered = false;
this.inherit = false;
this.enableSchedule = false;
this.considerInactivity = false;
this.enableIdleTime = false;
this.tzOffset = _moment().format('Z');
this.startTime = SchedulerCalculations.convertTimeFormat('09:00');
this.endTime = SchedulerCalculations.convertTimeFormat('20:00');
this.terminateTime = null;
this.schedulerForm.get('startDate').disable();
this.schedulerForm.get('finishDate').disable();
this.schedulerForm.get('terminateDate').disable();
}
}