UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

290 lines (285 loc) 20.4 kB
import * as i0 from '@angular/core'; import { forwardRef, Input, Component, NgModule } from '@angular/core'; import * as i1 from '@angular/forms'; import { Validators, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; import * as i2 from '@c8y/ngx-components'; import { C8yTranslateDirective, FormGroupComponent, RequiredInputPlaceholderDirective, MessagesComponent, MessageDirective, C8yTranslatePipe, CoreModule } from '@c8y/ngx-components'; import * as i1$1 from 'ngx-bootstrap/datepicker'; import { BsDatepickerInputDirective, BsDatepickerDirective, BsDatepickerModule } from 'ngx-bootstrap/datepicker'; import * as i2$1 from 'ngx-bootstrap/timepicker'; import { TimepickerComponent, TimepickerModule } from 'ngx-bootstrap/timepicker'; import { gettext } from '@c8y/ngx-components/gettext'; 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: "20.3.25", 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: "20.3.25", type: OperationSchedulerComponent, isStandalone: true, 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: "ngmodule", type: FormsModule }, { 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: "ngmodule", type: ReactiveFormsModule }, { 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: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: BsDatepickerInputDirective, selector: "input[bsDatepicker]" }, { kind: "directive", type: 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: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: 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: C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", 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) } ], imports: [ FormsModule, ReactiveFormsModule, C8yTranslateDirective, FormGroupComponent, RequiredInputPlaceholderDirective, BsDatepickerInputDirective, BsDatepickerDirective, MessagesComponent, MessageDirective, TimepickerComponent, C8yTranslatePipe ], 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: "20.3.25", ngImport: i0, type: BulkOperationSchedulerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: BulkOperationSchedulerModule, imports: [CoreModule, ReactiveFormsModule, i1$1.BsDatepickerModule, i2$1.TimepickerModule, OperationSchedulerComponent], exports: [OperationSchedulerComponent] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BulkOperationSchedulerModule, imports: [CoreModule, ReactiveFormsModule, BsDatepickerModule.forRoot(), TimepickerModule.forRoot(), OperationSchedulerComponent] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: BulkOperationSchedulerModule, decorators: [{ type: NgModule, args: [{ imports: [ CoreModule, ReactiveFormsModule, BsDatepickerModule.forRoot(), TimepickerModule.forRoot(), OperationSchedulerComponent ], providers: [], exports: [OperationSchedulerComponent] }] }] }); /** * Generated bundle index. Do not edit. */ export { BulkOperationSchedulerModule, OperationSchedulerComponent }; //# sourceMappingURL=c8y-ngx-components-operations-bulk-operation-scheduler.mjs.map