[BP-841] Add cyclic reporting form component
Signed-off-by: Christopher Keim <keim@develop-group.de>
diff --git a/src/app/cyclic-reporting/components/form/cyclic-report-form.component.html b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.html
new file mode 100644
index 0000000..f0fd69b
--- /dev/null
+++ b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.html
@@ -0,0 +1,135 @@
+<!--
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+-->
+
+<div class="container-fluid">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
+ <h1 class="h2" id="overviewHeader">
+ Zyklischen Report verwalten
+ </h1>
+ <div class="btn-toolbar mb-2 mb-md-0">
+ <div class="btn-group mr-2">
+ <button class="btn btn-primary mr-1" routerLink=".." >
+ Zurück
+ </button>
+ <ng-container *ngIf="report">
+ <button *ngIf="report?.id != null"
+ [disabled]="form?.disabled"
+ (click)="delete()"
+ class="btn btn-danger mr-1">
+ Löschen
+ </button>
+ <button class="btn btn-success mr-1"
+ [disabled]="form?.disabled"
+ (click)="submit()">
+ Speichern
+ </button>
+ </ng-container>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row" *ngIf="report == null">
+ <div class="col-md-12">
+ Daten konnten nicht geladen werden. Bitte kehren Sie zur Übersicht zurück oder betreten Sie die Seite erneut.
+ </div>
+ </div>
+
+ <div class="row" *ngIf="report != null">
+ <div class="col-md-12 cyclic-report-form">
+
+ <div class="cyclic-report-form-column">
+ <ok-cyclic-report-form-input [form]="form" [key]="'name'">
+ <span class="cyclic-report-form-label">Name:</span>
+ </ok-cyclic-report-form-input>
+
+ <div></div>
+
+ <ok-cyclic-report-form-select [form]="form" [key]="'reportName'" [options]="reportNameOptions">
+ <span class="cyclic-report-form-label">Planart:</span>
+ </ok-cyclic-report-form-select>
+
+ <ok-cyclic-report-form-select [form]="form" [key]="'standByListId'"
+ [options]="standByListOptions">
+ <span class="cyclic-report-form-label">Liste:</span>
+ </ok-cyclic-report-form-select>
+
+ <ok-cyclic-report-form-select [form]="form" [key]="'statusId'" [options]="planStatusOptions">
+ <span class="cyclic-report-form-label">Ebene:</span>
+ </ok-cyclic-report-form-select>
+
+ <ok-cyclic-report-form-select [form]="form" [key]="'printFormat'" [options]="printFormats">
+ <span class="cyclic-report-form-label">Format:</span>
+ </ok-cyclic-report-form-select>
+
+ <div></div>
+
+ <ng-container *ngFor="let entry of toFormArray?.controls; let i = index; let first = first;">
+ <ok-cyclic-report-form-input [form]="toFormArray" [key]="i"
+ [displayAddButton]="first" [displayCancelButton]="!first"
+ (add)="addEmailControl()" (cancel)="removeEmailControlAt(i)">
+ <span class="cyclic-report-form-label">
+ <ng-container *ngIf="first">Empfänger:</ng-container>
+ </span>
+ </ok-cyclic-report-form-input>
+ </ng-container>
+
+ <ok-cyclic-report-form-input [form]="form" [key]="'subject'">
+ <span class="cyclic-report-form-label">Betreff:</span>
+ </ok-cyclic-report-form-input>
+
+ <ok-cyclic-report-form-textarea [form]="form" [key]="'emailText'" class="cyclic-report-form-textarea">
+ <span class="cyclic-report-form-label">Emailtext:</span>
+ </ok-cyclic-report-form-textarea>
+
+ <ok-cyclic-report-form-input [form]="form" [key]="'fileNamePattern'">
+ <span class="cyclic-report-form-label">Dateiname:</span>
+ </ok-cyclic-report-form-input>
+
+ </div>
+
+ <div class="cyclic-report-form-column">
+
+ <ok-cyclic-report-form-date-controls [form]="form"
+ [options]="weekDayOptions"
+ [triggerMinuteStep]="triggerMinuteStep"
+ [key]="'trigger'">
+ <span>Auslöse­zeitpunkt:</span>
+ </ok-cyclic-report-form-date-controls>
+
+ <ok-cyclic-report-form-date-controls [form]="form"
+ [key]="'validFrom'" [forDayOffset]="true">
+ <span>Gültig­keit von:</span>
+ </ok-cyclic-report-form-date-controls>
+
+ <ok-cyclic-report-form-date-controls [form]="form" [key]="'validTo'"
+ [forDayOffset]="true">
+ <span>Gültig­keit bis:</span>
+ </ok-cyclic-report-form-date-controls>
+
+ <ok-error class="cyclic-report-form-error" [control]="form"></ok-error>
+
+ <ok-cyclic-report-form-info
+ [data]="form?.value"
+ [dateReplacementTokens]="dateTokens"
+ class="cyclic-report-form-info">
+ </ok-cyclic-report-form-info>
+
+ </div>
+
+ </div>
+ </div>
+
+</div>
diff --git a/src/app/cyclic-reporting/components/form/cyclic-report-form.component.scss b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.scss
new file mode 100644
index 0000000..973cd15
--- /dev/null
+++ b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.scss
@@ -0,0 +1,52 @@
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+
+.cyclic-report-form {
+ display: flex;
+ flex-flow: row wrap;
+ justify-content: space-around;
+ padding: 0;
+ width: 100%;
+}
+
+.cyclic-report-form-column {
+ flex: 1 1 25em;
+ width: 25em;
+ margin: 0 15px;
+
+ display: flex;
+ flex-flow: column;
+
+ & > * {
+ margin-bottom: 0.75em;
+ }
+}
+
+.cyclic-report-form-error {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.cyclic-report-form-label {
+ display: inline-block;
+ padding: calc(.375rem + 1px) 1rem calc(.375rem + 1px) 0;
+ line-height: 1.5;
+ margin: 0;
+ min-width: 10rem;
+}
+
+.cyclic-report-form-textarea {
+ min-height: calc(5 * 1.5em + 1em);
+}
+
+.cyclic-report-form-info {
+ padding: 0 1em 0 1em;
+}
diff --git a/src/app/cyclic-reporting/components/form/cyclic-report-form.component.spec.ts b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.spec.ts
new file mode 100644
index 0000000..f675a09
--- /dev/null
+++ b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.spec.ts
@@ -0,0 +1,270 @@
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+import {CommonModule} from '@angular/common';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {ActivatedRoute, Router} from '@angular/router';
+import {RouterTestingModule} from '@angular/router/testing';
+import {SharedModule} from '@shared/shared.module';
+import {CyclicReportObject} from '@shared/model/CyclicReportObject';
+import {ReportObject} from '@shared/model/ReportObject';
+import {StandbylistObject} from '@shared/model/StandbylistObject';
+import {FormUtil} from '@shared/utils/form.util';
+import {MessageService} from 'primeng/api';
+import {defer, of, throwError} from 'rxjs';
+import {CyclicReportFormDateControlsComponent} from '../form-date-controls/cyclic-report-form-date-controls.component';
+import {CyclicReportFormInfoComponent} from '../form-info/cyclic-report-form-info.component';
+import {CyclicReportFormInputComponent} from '../form-input/cyclic-report-form-input.component';
+import {CyclicReportFormSelectComponent} from '../form-select/cyclic-report-form-select.component';
+import {CyclicReportFormComponent} from './cyclic-report-form.component';
+import {CyclicReportFormTextareaComponent} from '@cyclic-reporting/components/form-textarea/cyclic-report-form-textarea.component';
+
+function createMockData<T extends object>(data: Partial<T>): T {
+ return (data == null ? {} : data) as T;
+}
+
+describe('CyclicReportFormComponent', () => {
+
+ let component: CyclicReportFormComponent;
+ let fixture: ComponentFixture<CyclicReportFormComponent>;
+ let idParam: number | 'new';
+ let report: CyclicReportObject;
+ let router: Router;
+ let activatedRoute: ActivatedRoute;
+
+ const standByListData: StandbylistObject[] = Array(42).fill(0)
+ .map((_, id) => createMockData<StandbylistObject>({ id: id, title: 'QVL ' + id }));
+
+ const reportObjects: ReportObject[] = Array(42).fill(0)
+ .map((_, id) => createMockData<ReportObject>({ reportName: 'ReportName' + id }));
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ CyclicReportFormComponent,
+ CyclicReportFormDateControlsComponent,
+ CyclicReportFormInfoComponent,
+ CyclicReportFormInputComponent,
+ CyclicReportFormSelectComponent,
+ CyclicReportFormTextareaComponent
+ ],
+ imports: [
+ CommonModule,
+ SharedModule,
+ RouterTestingModule,
+ HttpClientTestingModule
+ ],
+ providers: [
+ MessageService,
+ {
+ provide: ActivatedRoute,
+ useValue: { params: defer(() => of({id: idParam == null ? undefined : '' + idParam}))}
+ }
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CyclicReportFormComponent);
+ component = fixture.componentInstance;
+ component.excludedReportNames = reportObjects.slice(-1).map((reportObject) => reportObject.reportName);
+ router = TestBed.get(Router);
+ activatedRoute = TestBed.get(ActivatedRoute);
+ idParam = 19;
+ report = null;
+ spyOn(component.reportingService, 'getReportData')
+ .and.returnValue(defer(() => of(reportObjects)));
+ spyOn(component.masterdataService, 'getStandbyListSelection')
+ .and.returnValue(defer(() => of(standByListData)));
+ spyOn(component.cyclicReportingService, 'getCyclicReports')
+ .and.returnValue(defer(() => of(report == null ? [] : [report])));
+ });
+
+ describe('should create', () => {
+ it('for new reports', () => {
+ idParam = 'new';
+ fixture.detectChanges();
+ expect(component).toBeDefined();
+ });
+
+ it('for non-existing reports', () => {
+ idParam = -19;
+ fixture.detectChanges();
+ expect(component).toBeDefined();
+ });
+
+ it('for existing report', () => {
+ idParam = 19;
+ report = createMockData<CyclicReportObject>({ id: 19, to: [ 'a@b.c', 'x@y.z' ], standByListId: 19 });
+ fixture.detectChanges();
+ expect(component).toBeDefined();
+ });
+ });
+
+ it('should add and remove email controls', () => {
+ idParam = 'new';
+ fixture.detectChanges();
+ expect(component.form.value.to).toEqual(['']);
+ component.addEmailControl();
+ expect(component.form.value.to).toEqual(['', '']);
+ component.removeEmailControlAt(1);
+ expect(component.form.value.to).toEqual(['']);
+ });
+
+ describe('should submit', () => {
+
+ it('for new reports', () => {
+ const validateSpy = spyOn(FormUtil, 'validate').and.returnValue(true);
+ const putFormSpy = spyOn(component.cyclicReportingService, 'putCyclicReport').and.returnValue(of(report));
+ const navigateSpy = spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
+
+ report = {
+ id: null,
+ name: 'Name',
+ fileNamePattern: '{Date}_{Time}_{Week}',
+ subject: 'Test Subject',
+ to: ['test@tld.org'],
+ emailText: '',
+ reportName: reportObjects[0].reportName,
+ printFormat: 'pdf',
+ standByListId: standByListData[0].id,
+ statusId: 2,
+ triggerWeekDay: 1,
+ triggerHour: 8,
+ triggerMinute: 0,
+ validFromDayOffset: 0,
+ validFromHour: 8,
+ validFromMinute: 0,
+ validToDayOffset: 1,
+ validToHour: 8,
+ validToMinute: 0
+ };
+ idParam = 'new';
+ fixture.detectChanges();
+
+ component.form.patchValue(report);
+ component.submit();
+ expect(validateSpy).toHaveBeenCalled();
+ expect(putFormSpy).toHaveBeenCalledWith(report);
+ expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: activatedRoute });
+ });
+
+ it('for existing reports', () => {
+ const validateSpy = spyOn(FormUtil, 'validate').and.returnValue(true);
+ const postFormSpy = spyOn(component.cyclicReportingService, 'postCyclicReport').and.returnValue(of(report));
+ const navigateSpy = spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
+
+ report = {
+ id: 19,
+ name: 'Name',
+ fileNamePattern: '{Date}_{Time}_{Week}',
+ subject: 'Test Subject',
+ to: ['test@tld.org'],
+ emailText: '',
+ reportName: reportObjects[0].reportName,
+ printFormat: 'pdf',
+ standByListId: standByListData[0].id,
+ statusId: 2,
+ triggerWeekDay: 1,
+ triggerHour: 8,
+ triggerMinute: 0,
+ validFromDayOffset: 0,
+ validFromHour: 8,
+ validFromMinute: 0,
+ validToDayOffset: 1,
+ validToHour: 8,
+ validToMinute: 0
+ };
+ idParam = 19;
+ fixture.detectChanges();
+
+ component.addEmailControl();
+ component.submit();
+ expect(validateSpy).toHaveBeenCalled();
+ expect(postFormSpy).toHaveBeenCalledWith(report);
+ expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: activatedRoute });
+ });
+
+ it('and handle errors correctly', () => {
+ const validateSpy = spyOn(FormUtil, 'validate').and.returnValue(false);
+ const postFormSpy = spyOn(component.cyclicReportingService, 'postCyclicReport').and.returnValue(of(report));
+ const navigateSpy = spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
+
+ report = {
+ id: 19,
+ name: 'Name',
+ fileNamePattern: '{Date}_{Time}_{Week}',
+ subject: 'Test Subject',
+ to: ['test@tld.org'],
+ emailText: '',
+ reportName: reportObjects[0].reportName,
+ printFormat: 'pdf',
+ standByListId: standByListData[0].id,
+ statusId: 2,
+ triggerWeekDay: 1,
+ triggerHour: 8,
+ triggerMinute: 0,
+ validFromDayOffset: 0,
+ validFromHour: 8,
+ validFromMinute: 0,
+ validToDayOffset: 1,
+ validToHour: 8,
+ validToMinute: 0
+ };
+ idParam = 19;
+ fixture.detectChanges();
+
+ component.submit();
+ expect(validateSpy).toHaveBeenCalled();
+ expect(postFormSpy).not.toHaveBeenCalled();
+
+ validateSpy.and.returnValue(true);
+ postFormSpy.and.returnValue(throwError('TestError'));
+ component.submit();
+ expect(validateSpy).toHaveBeenCalled();
+ expect(postFormSpy).toHaveBeenCalledWith(report);
+ expect(navigateSpy).not.toHaveBeenCalled();
+ expect(component.form.enabled).toBe(true);
+ });
+ });
+
+ describe('should delete', () => {
+ it('existing reports', () => {
+ const deleteSpy = spyOn(component.cyclicReportingService, 'deleteCyclicReport')
+ .and.returnValue(of(null));
+ const navigateSpy = spyOn(router, 'navigate').and.returnValue(Promise.resolve(true));
+
+ idParam = 19;
+ report = createMockData<CyclicReportObject>({ id: 19 });
+ fixture.detectChanges();
+
+ component.delete();
+ expect(deleteSpy).toHaveBeenCalledWith(19);
+ expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: activatedRoute });
+ });
+
+ it('and handle errors correctly', () => {
+ const deleteSpy = spyOn(component.cyclicReportingService, 'deleteCyclicReport')
+ .and.returnValue(throwError('TestError'));
+ const navigateSpy = spyOn(router, 'navigate');
+
+ idParam = 19;
+ report = createMockData<CyclicReportObject>({ id: 19 });
+ fixture.detectChanges();
+
+ component.delete();
+ expect(deleteSpy).toHaveBeenCalledWith(19);
+ expect(navigateSpy).not.toHaveBeenCalled();
+ expect(component.form.disabled).toBe(false);
+ });
+ });
+
+});
diff --git a/src/app/cyclic-reporting/components/form/cyclic-report-form.component.ts b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.ts
new file mode 100644
index 0000000..0b54c5b
--- /dev/null
+++ b/src/app/cyclic-reporting/components/form/cyclic-report-form.component.ts
@@ -0,0 +1,241 @@
+/********************************************************************************
+ * Copyright © 2020 Basys GmbH.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+
+import {Component, Injector, OnDestroy, OnInit} from '@angular/core';
+import {FormArray, FormControl, Validators} from '@angular/forms';
+import {UtilService} from '@core/services/util.service';
+import {MasterdataService} from '@masterdata/services/masterdata.service';
+import {ReportingService} from '@reporting/services/reporting.service';
+import {AbstractFormComponent} from '@shared/abstract/abstract-form/abstract-form.component';
+import {CyclicReportObject} from '@shared/model/CyclicReportObject';
+import {SelectOptionObject} from '@shared/model/SelectOptionObject';
+import {FormUtil} from '@shared/utils/form.util';
+import {combineLatest, defer, EMPTY, Observable, of, Subscription} from 'rxjs';
+import {catchError, map, switchMap, tap} from 'rxjs/operators';
+import {CyclicReportingService} from '../../services/cyclic-reporting.service';
+import {CyclicReportingUtilService} from '../../services/cyclic-reporting-util.service';
+import {CyclicReportValidators} from '../../validators/cyclic-report.validators';
+
+@Component({
+ selector: 'ok-cyclic-report-form',
+ styleUrls: ['cyclic-report-form.component.scss'],
+ templateUrl: 'cyclic-report-form.component.html'
+})
+export class CyclicReportFormComponent extends AbstractFormComponent implements OnInit, OnDestroy {
+
+ public dateTokens = this.cyclicReportingUtilService.dateReplacementTokens;
+
+ public defaultValue: CyclicReportObject = {
+ id: undefined,
+ name: '',
+ fileNamePattern: '{Date}_{Time}_{Week}',
+ subject: '',
+ to: [],
+ emailText: '',
+ reportName: '',
+ printFormat: this.cyclicReportingUtilService.printFormatOptions[0].value,
+ standByListId: Number.NEGATIVE_INFINITY,
+ statusId: this.cyclicReportingUtilService.planStatusOptions[0].value,
+ triggerWeekDay: 1,
+ triggerHour: 8,
+ triggerMinute: 0,
+ validFromDayOffset: 0,
+ validFromHour: 8,
+ validFromMinute: 0,
+ validToDayOffset: 1,
+ validToHour: 8,
+ validToMinute: 0
+ };
+
+ public excludedReportNames: string[] = this.cyclicReportingUtilService.excludedReportNames;
+
+ public planStatusOptions = this.cyclicReportingUtilService.planStatusOptions;
+
+ public printFormats = this.cyclicReportingUtilService.printFormatOptions;
+
+ public report: CyclicReportObject;
+
+ public reportNameOptions: SelectOptionObject[] = [];
+
+ public standByListOptions: SelectOptionObject[] = [];
+
+ public toFormArray: FormArray;
+
+ public triggerMinuteStep = 5;
+
+ public weekDayOptions = this.cyclicReportingUtilService.weekDayOptions;
+
+ private subscriptions: Subscription[] = [];
+
+ public constructor(
+ injector: Injector,
+ public utilService: UtilService,
+ public masterdataService: MasterdataService,
+ public reportingService: ReportingService,
+ public cyclicReportingService: CyclicReportingService,
+ public cyclicReportingUtilService: CyclicReportingUtilService
+ ) {
+ super(injector);
+ }
+
+ public ngOnInit() {
+ this.subscriptions.push(this.initializeForm().subscribe());
+ }
+
+ public ngOnDestroy() {
+ this.subscriptions.forEach((subscription) => subscription.unsubscribe());
+ }
+
+ public submit() {
+ this.form.markAsTouched();
+ if (!FormUtil.validate(this.form)) {
+ return;
+ }
+
+ this.subscriptions.push(...[
+ of(this.form.value).pipe(
+ switchMap((value) => {
+ this.form.disable();
+ value = {
+ ...value,
+ to: value.to.filter((_) => _ !== '')
+ };
+ return value.id == null ?
+ this.cyclicReportingService.putCyclicReport(value)
+ : this.cyclicReportingService.postCyclicReport(value);
+ }),
+ switchMap(() => this.navigateToOverview()),
+ catchError(() => {
+ this.form.enable();
+ return EMPTY;
+ })
+ ).subscribe()
+ ]);
+ }
+
+ public delete() {
+ this.form.disable();
+ this.subscriptions.push(...[
+ this.cyclicReportingService.deleteCyclicReport(this.report.id).pipe(
+ switchMap(() => this.navigateToOverview()),
+ catchError(() => {
+ this.form.enable();
+ return EMPTY;
+ })
+ ).subscribe()
+ ]);
+ }
+
+ public addEmailControl() {
+ this.toFormArray.push(this.createEmailControl(''));
+ }
+
+ public removeEmailControlAt(index: number) {
+ this.toFormArray.removeAt(index);
+ }
+
+ public navigateToOverview() {
+ return this.router.navigate(['..'], { relativeTo: this.route });
+ }
+
+ private initializeForm() {
+ return defer(() => {
+ this.createForm({...this.defaultValue});
+ this.form.disable();
+ return combineLatest(this.fetchReport(), this.fetchReportNameOptions(), this.fetchStandByListOptions());
+ }).pipe(
+ tap(([report, reportNameOptions, standByListOptions]) => {
+ this.reportNameOptions = reportNameOptions.filter((option) => !this.excludedReportNames.includes(option.value));
+ this.standByListOptions = standByListOptions;
+ this.form.enable();
+ this.createForm({
+ ...this.defaultValue,
+ ...report,
+ standByListId: extractValueFromOption(
+ report == null ? this.standByListOptions[0] : findInOptions(report.standByListId, this.standByListOptions)
+ ),
+ reportName: extractValueFromOption(
+ report == null ? this.reportNameOptions[0] : findInOptions(report.reportName, this.reportNameOptions)
+ )
+ });
+ }),
+ catchError(() => {
+ this.report = undefined;
+ return EMPTY;
+ })
+ );
+ }
+
+ private fetchReport(): Observable<CyclicReportObject> {
+ return this.route.params.pipe(
+ map((params) => params.id),
+ switchMap((id) => {
+ return id === 'new' ? of(null) : this.cyclicReportingService.getCyclicReports().pipe(
+ map((reports) => {
+ id = parseInt(id, 10);
+ const result = reports.find((entry) => entry.id === id);
+ if (result == null) {
+ throw new Error('Entry not found');
+ }
+ return result;
+ }));
+ })
+ );
+ }
+
+ private fetchReportNameOptions(): Observable<SelectOptionObject<string>[]> {
+ return this.reportingService.getReportData().pipe(
+ map((data) => data.map((reportObject) => ({
+ ...reportObject,
+ value: reportObject.reportName,
+ label: reportObject.reportName
+ })))
+ );
+ }
+
+ private fetchStandByListOptions(): Observable<SelectOptionObject<number>[]> {
+ return this.masterdataService.getStandbyListSelection().pipe(
+ map((data) => data.map((reportObject) => ({
+ ...reportObject,
+ value: reportObject.id,
+ label: reportObject.title
+ })))
+ );
+ }
+
+ private createForm(report: CyclicReportObject) {
+ this.report = report;
+ const to = Array.isArray(report.to) && report.to.length > 0 ? report.to : [''];
+ this.toFormArray = this.fb.array(to.map((email) => this.createEmailControl(email)));
+ this.form = this.fb.group({...report, to: this.toFormArray});
+ Object.values(this.form.controls)
+ .forEach((control) => control.setValidators(Validators.required));
+ this.form.get('id').clearValidators();
+ this.form.get('emailText').clearValidators();
+ this.form.get('name').setValidators([Validators.required, Validators.maxLength(256)]);
+ this.form.get('fileNamePattern').setValidators([Validators.required, Validators.maxLength(128)]);
+ this.form.get('subject').setValidators([Validators.required, Validators.maxLength(128)]);
+ this.form.setValidators([CyclicReportValidators.validationDate]);
+ }
+
+ private createEmailControl(value: string): FormControl {
+ return this.fb.control(value, [Validators.email]);
+ }
+
+}
+
+function extractValueFromOption<T>(option: SelectOptionObject<T>) {
+ return option == null ? undefined : option.value;
+}
+
+function findInOptions<T>(value: T, options: SelectOptionObject<T>[]) {
+ const selected = options.find((option) => option.value === value);
+ return selected == null ? undefined : selected;
+}