@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
276 lines (271 loc) • 19.6 kB
JavaScript
import * as i0 from '@angular/core';
import { forwardRef, Input, Component, NgModule } from '@angular/core';
import * as i1 from '@angular/forms';
import { Validators, NG_VALUE_ACCESSOR, NG_VALIDATORS, ReactiveFormsModule } from '@angular/forms';
import * as i2 from '@c8y/ngx-components';
import { gettext, CoreModule } from '@c8y/ngx-components';
import * as i3 from 'ngx-bootstrap/datepicker';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import * as i4 from 'ngx-bootstrap/timepicker';
import { TimepickerModule } from 'ngx-bootstrap/timepicker';
import { isEmpty } from 'lodash-es';
import { throttleTime } from 'rxjs/operators';
class OperationSchedulerComponent {
set _minutesAhead(minutes) {
if (minutes && minutes > this.MINUTES_AHEAD_DEFAULT) {
this.minutesAhead = minutes;
}
}
constructor(formBuilder, options, dateFormatService) {
this.formBuilder = formBuilder;
this.options = options;
this.dateFormatService = dateFormatService;
this.placeholder = gettext('Start date');
this.delayErrors = null;
this.pickerErrors = null;
this.DELAY_SECONDS_DEFAULT = 1;
this.MIN_DELAY_SECONDS_DEFAULT = 0.001;
this.MAX_DELAY_SECONDS_DEFAULT = 3600;
this.MINUTES_AHEAD_DEFAULT = 5;
this.isDelayInSeconds = true;
this.minutesAhead = this.MINUTES_AHEAD_DEFAULT;
this.DELAY_KEY_CATEGORY = 'device-control';
this.MAX_DELAY_KEY_NAME = 'bulkoperation.maxcreationramp';
this.MIN_DELAY_KEY_NAME = 'bulkoperation.creationramp';
this.currentUnit = 'seconds';
}
ngOnInit() {
this.minDate = new Date();
this.initialDate = new Date(this.minDate.setMinutes(this.minDate.getMinutes() + this.minutesAhead));
this.fgOperationScheduler = this.formBuilder.group({
picker: ['', [Validators.required, this.dateValidation]],
time: ['', [Validators.required, this.timeValidation]],
delay: ['', [Validators.required]],
unit: ['seconds']
});
this.fgOperationScheduler.patchValue({
picker: this.initialDate,
time: this.initialDate,
delay: this.DELAY_SECONDS_DEFAULT
});
// Due to the validation of picker and time it could be possible that value changes
// are emitted more than once. Therefore we throttle the emits.
const valueChanges$ = this.fgOperationScheduler.valueChanges.pipe(throttleTime(100));
this.subscription = valueChanges$.subscribe(data => {
this.delayErrors = this.fgOperationScheduler.controls.delay.errors;
this.pickerErrors = this.fgOperationScheduler.controls.picker.errors;
this.convertDelayHandler(data.unit);
this.emitData(data);
});
this.updateDelayValidation();
this.dateInputFormat = this.dateFormatService.getDateFormat();
}
ngOnDestroy() {
if (this.subscription && !this.subscription.closed) {
this.subscription.unsubscribe();
}
}
writeValue(value) {
if (value) {
this.fgOperationScheduler.patchValue({
picker: value.scheduledDate,
time: value.scheduledDate,
delay: value.delayInSeconds > 1 ? value.delayInSeconds : value.delayInSeconds * 1000,
unit: value.delayInSeconds > 1 ? 'seconds' : 'milliseconds'
});
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
if (this.fgOperationScheduler?.disabled === isDisabled) {
return;
}
isDisabled ? this.fgOperationScheduler.disable() : this.fgOperationScheduler.enable();
}
validate() {
if (this.fgOperationScheduler.invalid) {
return {
...this.fgOperationScheduler.controls.picker.errors,
...this.fgOperationScheduler.controls.time.errors,
...this.fgOperationScheduler.controls.delay.errors
};
}
}
registerOnValidatorChange(fn) {
this.onValidatorChanged = fn;
}
markAsTouched() {
if (this.onTouched) {
this.onTouched();
}
}
convertDelayHandler(unit) {
if (this.currentUnit === unit) {
return;
}
this.currentUnit = unit;
this.convertDelay(this.currentUnit);
// update validator on delay control to make sure that
// switching from minutes to seconds or vice versa does not harm validation.
this.fgOperationScheduler.controls.delay.setValidators([
Validators.required,
Validators.min(this.minDelay),
Validators.max(this.maxDelay)
]);
this.fgOperationScheduler.controls.delay.updateValueAndValidity();
}
emitData(data) {
if (this.onValidatorChanged) {
this.onValidatorChanged();
}
if (data.picker && data.time) {
data.picker = this.combineDateAndTime(data.picker, data.time);
}
this.convertDelay(this.currentUnit);
data.delayInSeconds = this.delayInSeconds;
if (this.onChange) {
this.onChange({
delayInSeconds: data.delayInSeconds,
scheduledDate: data.picker
});
}
}
async updateDelayValidation() {
const minSystem = await this.options.getSystemOption(this.DELAY_KEY_CATEGORY, this.MIN_DELAY_KEY_NAME);
const maxSystem = await this.options.getSystemOption(this.DELAY_KEY_CATEGORY, this.MAX_DELAY_KEY_NAME);
this.maxDelay = maxSystem ? Number(maxSystem) : this.MAX_DELAY_SECONDS_DEFAULT;
this.minDelay = minSystem ? Number(minSystem) : this.MIN_DELAY_SECONDS_DEFAULT;
this.fgOperationScheduler
.get('delay')
.setValidators([
Validators.required,
Validators.min(this.minDelay),
Validators.max(this.maxDelay)
]);
this.fgOperationScheduler.updateValueAndValidity();
}
convertDelay(unit) {
this.delayInSeconds = this.fgOperationScheduler.controls.delay.value;
if (unit === 'seconds' && !this.isDelayInSeconds) {
this.maxDelay = this.maxDelay / 1000;
this.minDelay = this.minDelay / 1000;
this.isDelayInSeconds = true;
}
if (unit === 'milliseconds') {
this.delayInSeconds = this.fgOperationScheduler.controls.delay.value / 1000;
if (this.isDelayInSeconds) {
this.maxDelay = this.maxDelay * 1000;
this.minDelay = this.minDelay * 1000;
this.isDelayInSeconds = false;
}
}
}
combineDateAndTime(date, time) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
}
dateValidation(fControl) {
if (fControl.value) {
const date = fControl.value;
fControl.parent.get('time').setValue(date);
return date >= new Date()
? null
: {
dateValidation: true
};
}
return { dateValidation: true };
}
timeValidation(fControl) {
if (fControl.value) {
const date = fControl.value;
const result = date >= new Date()
? null
: {
dateValidation: true
};
const picker = fControl.parent.get('picker');
if (result) {
picker.setErrors(result);
picker.markAsTouched();
return result;
}
if (picker && picker.errors && picker.errors.dateValidation) {
delete picker.errors.dateValidation;
if (isEmpty(picker.errors)) {
picker.setErrors(null);
return result;
}
picker.setErrors(picker.errors);
}
return result;
}
return { dateValidation: true };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OperationSchedulerComponent, deps: [{ token: i1.FormBuilder }, { token: i2.OptionsService }, { token: i2.DateFormatService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: OperationSchedulerComponent, isStandalone: false, selector: "c8y-operation-scheduler", inputs: { _minutesAhead: ["minutesAhead", "_minutesAhead"] }, providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
}
], ngImport: i0, template: "<div [formGroup]=\"fgOperationScheduler\">\n <div class=\"form-group\">\n <label translate>Start date</label>\n <div class=\"datetime-picker\">\n <c8y-form-group class=\"datepicker\">\n <input\n class=\"form-control\"\n placeholder=\"{{ placeholder | translate }}\"\n required\n formControlName=\"picker\"\n [bsConfig]=\"{ customTodayClass: 'today', dateInputFormat: dateInputFormat }\"\n [minDate]=\"minDate\"\n bsDatepicker\n (blur)=\"markAsTouched()\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'dateValidation'\"\n [text]=\"'Select time in the future.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <timepicker\n class=\"form-group\"\n [showSpinners]=\"false\"\n [showMeridian]=\"false\"\n formControlName=\"time\"\n (blur)=\"markAsTouched()\"\n ></timepicker>\n </div>\n </div>\n <div class=\"form-group\">\n <c8y-form-group [hasError]=\"delayErrors\">\n <label translate>Delay</label>\n <div class=\"input-group\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 15\"\n type=\"number\"\n required\n formControlName=\"delay\"\n (blur)=\"markAsTouched()\"\n />\n <div class=\"input-group-btn\">\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control m-r-sm-32 m-r-xs-56\"\n [attr.aria-label]=\"'Delay units' | translate\"\n formControlName=\"unit\"\n (blur)=\"markAsTouched()\"\n >\n <option\n value=\"seconds\"\n translate\n >\n Seconds\n </option>\n <option\n value=\"milliseconds\"\n translate\n >\n Milliseconds\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n </c8y-form-group>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.BsDatepickerDirective, selector: "[bsDatepicker]", inputs: ["placement", "triggers", "outsideClick", "container", "outsideEsc", "isDisabled", "minDate", "maxDate", "ignoreMinMaxErrors", "minMode", "daysDisabled", "datesDisabled", "datesEnabled", "dateCustomClasses", "dateTooltipTexts", "isOpen", "bsValue", "bsConfig"], outputs: ["onShown", "onHidden", "bsValueChange"], exportAs: ["bsDatepicker"] }, { kind: "directive", type: i3.BsDatepickerInputDirective, selector: "input[bsDatepicker]" }, { kind: "component", type: i4.TimepickerComponent, selector: "timepicker", inputs: ["hourStep", "minuteStep", "secondsStep", "readonlyInput", "disabled", "mousewheel", "arrowkeys", "showSpinners", "showMeridian", "showMinutes", "showSeconds", "meridians", "min", "max", "hoursPlaceholder", "minutesPlaceholder", "secondsPlaceholder"], outputs: ["isValid", "meridianChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OperationSchedulerComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-operation-scheduler', providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
}
], standalone: false, template: "<div [formGroup]=\"fgOperationScheduler\">\n <div class=\"form-group\">\n <label translate>Start date</label>\n <div class=\"datetime-picker\">\n <c8y-form-group class=\"datepicker\">\n <input\n class=\"form-control\"\n placeholder=\"{{ placeholder | translate }}\"\n required\n formControlName=\"picker\"\n [bsConfig]=\"{ customTodayClass: 'today', dateInputFormat: dateInputFormat }\"\n [minDate]=\"minDate\"\n bsDatepicker\n (blur)=\"markAsTouched()\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'dateValidation'\"\n [text]=\"'Select time in the future.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <timepicker\n class=\"form-group\"\n [showSpinners]=\"false\"\n [showMeridian]=\"false\"\n formControlName=\"time\"\n (blur)=\"markAsTouched()\"\n ></timepicker>\n </div>\n </div>\n <div class=\"form-group\">\n <c8y-form-group [hasError]=\"delayErrors\">\n <label translate>Delay</label>\n <div class=\"input-group\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 15\"\n type=\"number\"\n required\n formControlName=\"delay\"\n (blur)=\"markAsTouched()\"\n />\n <div class=\"input-group-btn\">\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control m-r-sm-32 m-r-xs-56\"\n [attr.aria-label]=\"'Delay units' | translate\"\n formControlName=\"unit\"\n (blur)=\"markAsTouched()\"\n >\n <option\n value=\"seconds\"\n translate\n >\n Seconds\n </option>\n <option\n value=\"milliseconds\"\n translate\n >\n Milliseconds\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n </c8y-form-group>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.OptionsService }, { type: i2.DateFormatService }], propDecorators: { _minutesAhead: [{
type: Input,
args: ['minutesAhead']
}] } });
/**
* This module provides components for scheduling bulk operations.
*/
class BulkOperationSchedulerModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationSchedulerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationSchedulerModule, declarations: [OperationSchedulerComponent], imports: [CoreModule,
ReactiveFormsModule, i3.BsDatepickerModule, i4.TimepickerModule], exports: [OperationSchedulerComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationSchedulerModule, imports: [CoreModule,
ReactiveFormsModule,
BsDatepickerModule.forRoot(),
TimepickerModule.forRoot()] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BulkOperationSchedulerModule, decorators: [{
type: NgModule,
args: [{
imports: [
CoreModule,
ReactiveFormsModule,
BsDatepickerModule.forRoot(),
TimepickerModule.forRoot()
],
providers: [],
declarations: [OperationSchedulerComponent],
exports: [OperationSchedulerComponent]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { BulkOperationSchedulerModule, OperationSchedulerComponent };
//# sourceMappingURL=c8y-ngx-components-operations-bulk-operation-scheduler.mjs.map