import { of as observableOf, Observable } from 'rxjs'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { AfterViewInit, Component, OnChanges, OnInit, QueryList, SimpleChanges, ViewChild } from '@angular/core'; import { Form, FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatHorizontalStepper, MatStep } from '@angular/material/stepper'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { map, takeUntil } from 'rxjs/operators'; import * as FileSaver from 'file-saver'; import { BaseComponent } from '@common/base/base.component'; import { DatasetProfileEditorModel } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor-model'; import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; import { LoggingService } from '@app/core/services/logging/logging-service'; import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; import { DatasetProfile } from '@app/core/model/admin/dataset-profile/dataset-profile'; import { DatasetProfileEnum } from '@app/core/common/enum/dataset-profile'; import { SectionEditorModel } from '@app/ui/admin/dataset-profile/admin/section-editor-model'; import { PageEditorModel } from '@app/ui/admin/dataset-profile/admin/page-editor-model'; import { DatasetStatus } from '@app/core/common/enum/dataset-status'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { LanguageInfo } from '@app/core/model/language-info'; import { LanguageInfoService } from '@app/core/services/culture/language-info-service'; import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { Link, LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { Foo, ToCEntry, ToCEntryType } from '../table-of-contents/table-of-contents-entry'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { FieldSetEditorModel } from '../admin/field-set-editor-model'; import { Guid } from '@common/types/guid'; import { FieldEditorModel } from '../admin/field-editor-model'; import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper'; import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionFormEditorModel, DatasetDescriptionPageEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { Rule } from '@app/core/model/dataset-profile-definition/rule'; const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); @Component({ selector: 'app-dataset-profile-editor-component', templateUrl: './dataset-profile-editor.component.html', styleUrls: ['./dataset-profile-editor.component.scss'] }) export class DatasetProfileEditorComponent extends BaseComponent implements OnInit { isNew = true; isNewVersion = false; isClone = false; isDeleted = false; dataModel: DatasetProfileEditorModel; form: FormGroup; previewerFormGroup: FormGroup; private datasetProfileId: string; newVersionId: string; dataWizardModel: DatasetWizardModel; breadCrumbs: Observable; @ViewChild('stepper', { static: false }) stepper: MatHorizontalStepper; viewOnly = false; nestedCount: number[] = []; nestedIndex: number = 0; errorMessages: string[] = []; tocEntryEnumValues = ToCEntryType; // sectionIdPreviewed:string = null; // currentSubForm:FormGroup = null; // currentSectionIndex: number = null; // currentSectionEditorModel: SectionEditorModel = null; constructor( private datasetProfileService: DatasetProfileService, private route: ActivatedRoute, private router: Router, private logger: LoggingService, private uiNotificationService: UiNotificationService, private language: TranslateService, private dialog: MatDialog, private languageInfoService: LanguageInfoService, private httpClient: HttpClient, private matomoService: MatomoService, private enumUtils: EnumUtils, private datasetWizardService: DatasetWizardService, private visibilityRulesService: VisibilityRulesService, private fb: FormBuilder ) { super(); // this.profileID = route.snapshot.params['id']; // this.cloneId = route.snapshot.params['cloneid']; } ngOnInit() { this.matomoService.trackPageView('Admin: Dataset Profile Edit'); this.route.paramMap.pipe(takeUntil(this._destroyed)).subscribe((paramMap: ParamMap) => { this.datasetProfileId = paramMap.get('id'); const cloneId = paramMap.get('cloneid'); this.newVersionId = paramMap.get('newversionid'); if (this.datasetProfileId != null) { this.isNew = false; this.datasetProfileService.getDatasetProfileById(this.datasetProfileId) .pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed)) .subscribe( data => { try { this.dataModel = new DatasetProfileEditorModel().fromModel(data); // this.isDeleted = this.masterItem.isActive === IsActive.Inactive; if (this.dataModel.status === DatasetProfileEnum.FINALIZED) { this.form = this.dataModel.buildForm(true, skipDisable); this.viewOnly = true; } else { this.form = this.dataModel.buildForm(); } this.prepareForm(); } catch (error) { this.logger.error('Could not parse MasterItem: ' + data); console.log(error) this.uiNotificationService.snackBarNotification(this.language.instant('NOTIFICATIONS.DEFAULT.ERROR'), SnackBarNotificationLevel.Error); } }, error => this.onCallbackError(error) ); this.breadCrumbs = observableOf([{ parentComponentName: 'DatasetProfileListingComponent', label: this.language.instant('NAV-BAR.TEMPLATE'), url: '/dataset-profiles/' + this.datasetProfileId }]); } else if (cloneId != null) { this.isClone = true; this.datasetProfileService.clone(cloneId) .pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed)) .subscribe( data => { try { this.dataModel = new DatasetProfileEditorModel().fromModel(data); // this.isDeleted = this.masterItem.isActive === IsActive.Inactive; this.dataModel.status = DatasetProfileEnum.SAVED; this.form = this.dataModel.buildForm(); this.prepareForm(); } catch { this.logger.error('Could not parse MasterItem: ' + data); this.uiNotificationService.snackBarNotification(this.language.instant('NOTIFICATIONS.DEFAULT.ERROR'), SnackBarNotificationLevel.Error); } }, error => this.onCallbackError(error) ); } else if (this.newVersionId != null) { this.isNewVersion = true; this.datasetProfileService.getDatasetProfileById(this.newVersionId) .pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed)) .subscribe( data => { try { this.dataModel = new DatasetProfileEditorModel().fromModel(data); // this.isDeleted = this.masterItem.isActive === IsActive.Inactive; this.form = this.dataModel.buildForm(); this.form.get('version').setValue(this.form.get('version').value + 1); this.form.controls['label'].disable(); this.form.controls['description'].disable(); this.form.controls['language'].disable(); this.prepareForm(); } catch { this.logger.error('Could not parse MasterItem: ' + data); this.uiNotificationService.snackBarNotification(this.language.instant('NOTIFICATIONS.DEFAULT.ERROR'), SnackBarNotificationLevel.Error); } }, error => this.onCallbackError(error) ); } else { this.dataModel = new DatasetProfileEditorModel(); this.form = this.dataModel.buildForm(); if (this.dataModel.status === DatasetProfileEnum.FINALIZED) { this.form.disable(); this.viewOnly = true; } // this.addSection(); // this.addPage(); this.visibilityRulesService.buildVisibilityRules([],this.form); setTimeout(() => { this.steps = this.stepper.steps; }); this.refreshToCEntries(); } }); } prepareForm() { this.visibilityRulesService.buildVisibilityRules([],this.form); this.form.valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(change => { // this.datasetProfileService.preview(this.form.value) // .pipe(takeUntil(this._destroyed)) // .subscribe(dataset => { // const datasetModel = new DatasetWizardModel(); // datasetModel.datasetProfileDefinition = JsonSerializer.fromJSONObject(dataset, DatasetProfileDefinitionModel); // this.dataWizardModel = datasetModel; // this.previewerFormGroup = this.dataWizardModel.buildForm().get('datasetProfileDefinition'); // }); }); this.form.updateValueAndValidity(); setTimeout(() => { this.steps = this.stepper.steps; }); //SHOW THE FIRST PAGE const tocentries = this.refreshToCEntries(); if(tocentries && tocentries.length){ this.selectedTocEntry = tocentries[0]; } //this.getPreview(); } onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) { if (!isMultiplicityEnabled) { (this.form.get('multiplicity').get('min')).setValue(0); (this.form.get('multiplicity').get('max')).setValue(0); } } addSection() { const section: SectionEditorModel = new SectionEditorModel(); this.dataModel.sections.push(section); (this.form.get('sections')).push(section.buildForm()); } addPage() { const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length); this.dataModel.pages.push(page); (this.form.get('pages')).push(page.buildForm()); } DeleteSection(index) { this.dataModel.sections.splice(index, 1); (this.form.get('sections')).removeAt(index); } onSubmit() { let data = this.form.value; if (this.datasetProfileId) { this.datasetProfileService.updateForm(this.datasetProfileId, data) .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); }); } else if (this.newVersionId) { data.label = this.form.get('label').value; data.description = this.form.get('description').value; this.datasetProfileService.newVersion(this.newVersionId, data) .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); }, error => this.onCallbackErrorNewVersion(error) ); } else { this.form.get('status').setValue(DatasetStatus.Draft); data = this.form.value; this.datasetProfileService.createForm(data) .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); }); } } finalize() { //const data = this.form.value; this.form.get('status').setValue(DatasetProfileEnum.FINALIZED); this.onSubmit(); } updateFinalized() { this.datasetProfileService.updateForm(this.datasetProfileId, this.form.getRawValue()) .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); }); } showUpdateButton() { return !this.isNew && this.dataModel.status === DatasetProfileEnum.FINALIZED; } isStepActive(step: number) { return this.stepper && this.stepper.selectedIndex === step; } onCallbackSuccess(): void { this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); this.router.navigate(['/master-items']); } onCallbackErrorNewVersion(errorResponse: HttpErrorResponse) { this.uiNotificationService.snackBarNotification(errorResponse.error.message, SnackBarNotificationLevel.Error); } onCallbackError(errorResponse: HttpErrorResponse) { // const error: HttpError = this.httpErrorHandlingService.getError(errorResponse); // if (error.statusCode === 400) { // this.masterItem.validationErrorModel.fromJSONObject(errorResponse.error); // this.formService.validateAllFormFields(this.formGroup); // } else { this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning); // } } // DELETE Function public delete(): void { if (this.datasetProfileId && !this.isNew) { const dialogRef = this.dialog.open(ConfirmationDialogComponent, { restoreFocus: false, data: { message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), isDeleteConfirmation: true } }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result) { //this.form.get('status').setValue(DatasetProfileEnum.DELETED); this.datasetProfileService.delete(this.datasetProfileId, this.form.value) .pipe(takeUntil(this._destroyed)) .subscribe( complete => { this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success); this.router.navigate(['/dataset-profiles']); }, error => { this.onCallbackError(error); if (error.error.statusCode == 674) { this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Error); } else { this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); } } ); } }); } } downloadXML(): void { this.datasetProfileService.downloadXML(this.datasetProfileId) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'application/xml' }); const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); FileSaver.saveAs(blob, filename); }); } getFilenameFromContentDispositionHeader(header: string): string { const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); const matches = header.match(regex); let filename: string; for (let i = 0; i < matches.length; i++) { const match = matches[i]; if (match.includes('filename="')) { filename = match.substring(10, match.length - 1); break; } else if (match.includes('filename=')) { filename = match.substring(9); break; } } return filename; } getLanguageInfos(): LanguageInfo[] { return this.languageInfoService.getLanguageInfoValues(); } checkFormValidation() { if (!this.form.valid) { this.nestedIndex = -1; this.form.markAllAsTouched(); this.printErrors(this.form); this.showValidationErrorsDialog(); this.nestedCount = []; this.nestedIndex = 0; this.errorMessages = []; } } printErrors(rootform: FormGroup) { if (!rootform.valid) { Object.keys(rootform.controls).forEach(key => { const errors = rootform.get(key).errors; if (errors !== null) { let numbering: string = ''; for (let j = 0; j < this.nestedCount.length; j++) { numbering += this.nestedCount[j]; if (j < this.nestedIndex) { numbering += '.'; } else { break; } } Object.keys(errors).forEach(keyError => { if (typeof errors[keyError] === 'boolean') { this.errorMessages.push(numbering + ' ' + key + ' is ' + keyError); } else { this.errorMessages.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError])); } }); } else { if (rootform.get(key) instanceof FormGroup) { this.printErrors(rootform.get(key)); } else if (rootform.get(key) instanceof FormArray) { this.nestedIndex++; this.nestedCount[this.nestedIndex] = 0; for (let childForm of (rootform.get(key)).controls) { this.nestedCount[this.nestedIndex]++; this.printErrors(childForm); } this.nestedCount[this.nestedIndex] = 0; this.nestedIndex--; } } }); } } private showValidationErrorsDialog(projectOnly?: boolean) { const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { disableClose: true, autoFocus: false, restoreFocus: false, data: { errorMessages: this.errorMessages, projectOnly: projectOnly }, }); } links: Link[] = []; getLinks(currentLinks: Link[]) { this.links = currentLinks; } linkToScroll: LinkToScroll; onStepFound(linkToScroll: LinkToScroll) { this.linkToScroll = linkToScroll; } datasetWizardModel: DatasetWizardEditorModel; formGroup: FormGroup; getPreview() { let data = this.form.value; this.datasetProfileService.preview(data).subscribe(x => { this.datasetWizardModel = new DatasetWizardEditorModel().fromModel({ datasetProfileDefinition: x }); this.formGroup = this.datasetWizardModel.buildForm().get('datasetProfileDefinition'); }); //this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); //this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; // if (this.datasetWizardModel.status === DatasetStatus.Finalized) { // this.formGroup.disable(); // this.viewOnly = true; // } //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. // this.registerFormListeners(); // this.dmpValueChanged(null); // this.breadCrumbs = observableOf([ // { // parentComponentName: null, // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), // url: '/datasets/new/' // }]); // this.datasetWizardService.updateDatasetProfile(this.profileUpdateId) // .pipe(takeUntil(this._destroyed)) // .subscribe(data => { // this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); // this.needsUpdate(); // this.breadCrumbs = observableOf([ // { // parentComponentName: null, // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), // url: '/datasets', // notFoundResolver: [ // // { // // parentComponentName: null, // // label: this.datasetWizardModel.dmp.grant.label, // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id // // }, // { // parentComponentName: null, // label: this.datasetWizardModel.dmp.label, // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, // }, // ] // }]); // this.formGroup = this.datasetWizardModel.buildForm(); // this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; // if (this.datasetWizardModel.status === DatasetStatus.Finalized) { // this.formGroup.disable(); // this.viewOnly = true; // } // // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. // this.loadDatasetProfiles(); // }); } private refreshToCEntries(): ToCEntry[]{ this.toCEntries = this.getTocEntries(); //update selected tocentry if(this.selectedTocEntry){ this.selectedTocEntry = this._findTocEntryById(this.selectedTocEntry.id, this.toCEntries); } this.updateOrdinals(this.toCEntries); return this.toCEntries; } private updateOrdinals(tocentries: ToCEntry[]){ if(!tocentries || !tocentries.length) return; tocentries.forEach((e,idx)=>{ const ordinalControl = e.form.get('ordinal'); if(ordinalControl){ ordinalControl.setValue(idx); ordinalControl.updateValueAndValidity(); } this.updateOrdinals(e.subEntries); }); } toCEntries:ToCEntry[]; getTocEntries(): ToCEntry[] { if (this.form == null) { return []; } const result: ToCEntry[] = []; //build parent pages (this.form.get('pages') as FormArray).controls.forEach((pageElement, i) => { result.push({ id: pageElement.get('id').value, label: pageElement.get('title').value, type: ToCEntryType.Page, form: pageElement, numbering: (i + 1).toString(), subEntriesType: ToCEntryType.Section } as ToCEntry) }); // build first level sections (this.form.get('sections') as FormArray).controls.forEach((sectionElement, i) => { const currentSectionPageId = sectionElement.get('page').value; const pageToAdd = result.filter(x => x.id == currentSectionPageId)[0]; if (pageToAdd.subEntries == null) pageToAdd.subEntries = []; const item = { id: sectionElement.get('id').value, label: sectionElement.get('title').value, type: ToCEntryType.Section, form: sectionElement, numbering: pageToAdd.numbering + '.' + (pageToAdd.subEntries.length +1) } as ToCEntry; const sectionItems = this.populateSections(sectionElement.get('sections') as FormArray, item.numbering); const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as FormArray, item.numbering); if (sectionItems != null) { item.subEntries = sectionItems; item.subEntriesType = ToCEntryType.Section; } if (fieldSetItems != null) { if (item.subEntries == null) { item.subEntries = fieldSetItems; } else { item.subEntries.push(...fieldSetItems); } item.subEntriesType = ToCEntryType.FieldSet; } pageToAdd.subEntries.push(item); }); return result; } private populateSections(sections: FormArray, existingNumbering: string): ToCEntry[] { if (sections == null || sections.controls == null || sections.controls.length == 0) { return null; } const result: ToCEntry[] = []; sections.controls.forEach((sectionElement, i) => { const item = { id: sectionElement.get('id').value, label: sectionElement.get('title').value, type: ToCEntryType.Section, form: sectionElement, numbering: existingNumbering + '.' + (i + 1) } as ToCEntry; const sectionItems = this.populateSections(sectionElement.get('sections') as FormArray, item.numbering); const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as FormArray, item.numbering); if (sectionItems != null) { item.subEntries = sectionItems; item.subEntriesType = ToCEntryType.Section; } if (fieldSetItems != null) { if (item.subEntries == null) { item.subEntries = fieldSetItems; } else { item.subEntries.push(...fieldSetItems); } item.subEntriesType = ToCEntryType.FieldSet; } result.push(item); }); return result; } private populateFieldSets(fieldSets: FormArray, existingNumbering: string): ToCEntry[] { if (fieldSets == null || fieldSets.controls == null || fieldSets.controls.length == 0) { return null; } const result: ToCEntry[] = []; fieldSets.controls.forEach((fieldSetElement, i) => { result.push({ id: fieldSetElement.get('id').value, label: fieldSetElement.get('title').value, type: ToCEntryType.FieldSet, //subEntries: this.populateSections((fieldSetElement.get('fieldSets') as FormArray), existingNumbering + '.' + i), form: fieldSetElement, numbering: existingNumbering + '.' + (i + 1) } as ToCEntry) }); return result; } private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry{ if(!tocentries){ return null; } let tocEntryFound = tocentries.find(entry=>entry.id === id); if(tocEntryFound){ return tocEntryFound; } for(let entry of tocentries){ const result = this._findTocEntryById(id, entry.subEntries); if(result){ tocEntryFound = result; break; } } if(tocEntryFound) return tocEntryFound; return null; } addNewEntry(tce: Foo) { const parent = tce.parent; //define entry type switch (tce.childType) { case ToCEntryType.Page: //CALLED FROM PAGE //create section // this.addPage(); // this.displayItem(child); //ceate page editor model and give ordinal const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length); this.dataModel.pages.push(page); (this.form.get('pages')).push(page.buildForm()); //make new entry selected const pagesArray = (this.form.get('pages') as FormArray); const addedEntry = pagesArray.at(pagesArray.length-1) as FormGroup; this.selectedTocEntry = this._findTocEntryById(addedEntry.get('id').value, this.getTocEntries()); break; case ToCEntryType.Section: //adding a section const section: SectionEditorModel = new SectionEditorModel(); //give id section.id = Guid.create().toString(); let sectionsArray:FormArray; //TODO CHECK FOR FORM.ROOT ERROR if (parent.type === ToCEntryType.Page) { //FIRST LEVEL SECTION //give ordinal and link to parent section.page = parent.id; section.ordinal = (this.form.get('sections') as FormArray).length; (this.form.get('sections')).push(section.buildForm()); sectionsArray = this.form.get('sections') as FormArray; } else if( parent.type == ToCEntryType.Section) { //subsection //adding page parent MAYBE NOT NEEDED section.page = parent.form.get('page').value; //MAYBE NOT NEEDED section.ordinal = (parent.form.get('sections') as FormArray).length; (parent.form.get('sections')).push(section.buildForm()); // (child.form.parent as FormArray).push(section.buildForm()); sectionsArray = parent.form.get('sections') as FormArray; }else{ console.error('BUg found'); } const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup; this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.getTocEntries()); break; case ToCEntryType.FieldSet: const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); //create one field form fieldset const field: FieldEditorModel = new FieldEditorModel(); //to ask field.id = Guid.create().toString(); field.ordinal = 0;//first filed in the fields list fieldSet.fields.push(field); // field.ordinal = fieldSet.fields.length-1; //give fieldset id and ordinal fieldSet.id = Guid.create().toString(); fieldSet.ordinal = (parent.form.get('fieldSets') as FormArray).length; (parent.form.get('fieldSets')).push(fieldSet.buildForm()); const parentArray = parent.form.get('fieldSets') as FormArray; const addedFieldSet = parentArray.at(parentArray.length - 1); this.selectedTocEntry = this._findTocEntryById(addedFieldSet.get('id').value, this.getTocEntries()); break; default: break; } this.refreshToCEntries(); } onRemoveEntry(tce: ToCEntry){ const dialogRef = this.dialog.open(ConfirmationDialogComponent, { restoreFocus: false, data: { message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), isDeleteConfirmation: true } }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result) { this._deleteEntry(tce); } }); } private _deleteEntry(tce: ToCEntry) { //define entry type switch (tce.type) { case ToCEntryType.Page: const pages = this.form.get('pages') as FormArray; let pageIndex = -1; //get the index for (let i = 0; i < pages.length; i++) { let page = pages.at(i) as FormGroup; if (page.controls.id.value === tce.id) { pageIndex = i; break; } } if (pageIndex >= 0) { //remove page this._updateSelectedItem(tce); pages.removeAt(pageIndex); //clean up sections of removed page const sections = (this.form.get('sections') as FormArray).controls; const updatedSections = new FormArray([]); for (let i = 0; i < sections.length; i++) { let section = sections[i]; if (section.get('page').value != tce.id) { updatedSections.push(section); } } //replace sections value this.form.controls.sections = updatedSections; //update page orders for(let i=0; i= 0) { //section found const sections = (this.form.get('sections') as FormArray); //remove section this._updateSelectedItem(tce); sections.removeAt(index); //update ordinal for(let i=0; i< sections.length; i++){ sections.at(i).get('ordinal').patchValue(i); } } else {//NOT FOUND IN FIRST LEVEL CASE //LOOK FOR SUBSECTION CASE let parentFormArray = tce.form.parent as FormArray; for (let i = 0; i < parentFormArray.length; i++) { let section = parentFormArray.at(i); if (section.get('id').value == tce.id) { index = i; break; } } if (index >= 0) { this._updateSelectedItem(tce); parentFormArray.removeAt(index); //update odrinal for(let i=0; i=0){//fieldset found this._updateSelectedItem(tce); parentFormArray.removeAt(idx); //patching order for(let i=0; i{ if(section.get('id').value === tce.id){ isFirstLevel = true; } }); let parentId = null; if(isFirstLevel){ parentId = tce.form.get('page').value; }else{ parentId = tce.form.parent.parent.get('id').value } // const parentId = tce.form.parent.parent.get('id').value; if(parentId){ const tocentries = this.getTocEntries(); const parent = this._findTocEntryById(parentId, tocentries); if(parent){ this.selectedTocEntry = parent; }else{ this.selectedTocEntry = null; } }else{ this.selectedTocEntry = null; } } } } } tocEntryIsChildOf(testingChild: ToCEntry,parent: ToCEntry): boolean{ if(!testingChild || !parent) return false; if(testingChild.id == parent.id){return true;} if(parent.subEntries){ let childFound:boolean = false; parent.subEntries.forEach(subEntry=>{ if(this.tocEntryIsChildOf(testingChild, subEntry)){ childFound = true; return true; } }) return childFound; } return false; } selectedTocEntry: ToCEntry displayItem(entry: ToCEntry): void { this.selectedTocEntry = entry; } get numOfPages(){ return (this.form.get('pages')).length; } // getSectionIndex(): number{ // // if(this.sectionIdPreviewed == null) return; // const valuesArray = this.form.get('sections').value; // let currentVal = this.sectionIdPreviewed; // let indexArray:string[] = valuesArray.map(element=> element.page); // let index = indexArray.indexOf(currentVal); // console.log(index); // return index ? index :-1; // } // getCurrentEditorModel(): SectionEditorModel{ // let currentEditor = this.dataModel.sections.filter(section=> section.page == this.sectionIdPreviewed)[0]; // return currentEditor; // } // subForm(){ // const valuesArray = this.form.get('sections').value; // let currentVal = this.sectionIdPreviewed; // let indexArray:string[] = valuesArray.map(element=> element.page); // let index = indexArray.indexOf(currentVal); // let subForm = (this.form.get('sections') as FormArray).controls[index]; // console.log(subForm); // return subForm; // } getFieldTile(formGroup: FormGroup, index: number) { if (formGroup.get('title') && formGroup.get('title').value && formGroup.get('title').value.length > 0) { return formGroup.get('title').value; } return "Field " + (index + 1); } deleteFieldSet(formArray: FormArray, index: number) { formArray.removeAt(index); } printForm(){ console.log(this.form.value); } get barPercentage(){ if(!this.stepper || !this.steps){ return -110; } const selectedIndex = this.stepper.selectedIndex + 1; return (selectedIndex / this.stepper.steps.length) * 110- 110; } get progressStyle(){ return {'transform': 'translateX('+this.barPercentage+'%) skewX(-25deg)'} } steps:QueryList; // get steps(){ // if(!this.stepper){ // return []; // } // return this.stepper.steps; // } generatePreviewForm(){ const model = new DatasetDescriptionFormEditorModel(); const toCentries = this.getTocEntries(); //first level is always pages model.pages = toCentries.map((entry,idx)=>{ if( !(entry.type == ToCEntryType.Page)){ return null; } const pageModel = new DatasetDescriptionPageEditorModel(); pageModel.ordinal = entry.form.get('ordinal').value; pageModel.title = entry.label; if(entry.subEntries){ pageModel.sections = entry.subEntries.map(section=>{ const sectionModel = new DatasetDescriptionSectionEditorModel(); sectionModel.id = section.id; sectionModel.ordinal = section.form.get('ordinal').value; sectionModel.description = section.form.get('description').value; sectionModel.page = entry.form.get('ordinal').value; sectionModel.title = section.label; sectionModel.numbering = (idx+1).toString(); if(section.subEntriesType == ToCEntryType.Section){ sectionModel.sections = this._buildSectionsRecursively(section.subEntries, sectionModel.numbering); }else{ sectionModel.compositeFields = this._buildFormFields(section.subEntries, sectionModel.numbering) } return sectionModel; }); }; return pageModel; }); //populate rules const rules:Rule[] =[]; const fieldSets = this._getFieldSets(toCentries); fieldSets.forEach(fs=>{ const fields = fs.form.get('fields') as FormArray; if(fields){ fields.controls.forEach(field=>{ const rulesArray = field.get('visible').get('rules').value; if(rulesArray){ rulesArray.forEach(ruleElement => { const rule: Rule = new Rule(); rule.targetField = ruleElement.target; rule.sourceField = field.get('id').value; rule.requiredValue = ruleElement.value; rules.push(rule); }); } }); } }); model.rules = rules; this.visibilityRules = rules; this.previewForm = model.buildForm(); } visibilityRules:Rule[]; private _buildSectionsRecursively( tocentries: ToCEntry[], parentNumbering:string): DatasetDescriptionSectionEditorModel[]{ if(!tocentries) return null; const result: Array = []; tocentries.forEach((tocentry, idx)=>{ const sectionModel = new DatasetDescriptionSectionEditorModel(); sectionModel.id = tocentry.id; sectionModel.ordinal = tocentry.form.get('ordinal').value; sectionModel.description = tocentry.form.get('description').value; // sectionModel.page = entry.form.get('ordinal').value; sectionModel.title = tocentry.label; // sectionModel.numbering = tocentry.numbering; sectionModel.numbering = parentNumbering+"."+(idx+1);; if(tocentry.subEntriesType == ToCEntryType.Section){ sectionModel.sections = this._buildSectionsRecursively(tocentry.subEntries, sectionModel.numbering); }else{ sectionModel.compositeFields = this._buildFormFields(tocentry.subEntries, sectionModel.numbering); } result.push(sectionModel); }) return result; } private _buildFormFields(tocentries: ToCEntry[], parentNumbering: string):DatasetDescriptionCompositeFieldEditorModel[]{ if(!tocentries) return null; const fieldsets:DatasetDescriptionCompositeFieldEditorModel[] = []; tocentries.forEach((fs, idx)=>{ const fieldset = new DatasetDescriptionCompositeFieldEditorModel(); fieldset.description = fs.form.get('description').value; fieldset.extendedDescription = fs.form.get('extendedDescription').value; fieldset.id = fs.form.get('id').value; fieldset.multiplicity = fs.form.get('multiplicity').value; fieldset.additionalInformation = fs.form.get('additionalInformation').value; fieldset.ordinal = fs.form.get('ordinal').value; // fieldset.numbering = fs.numbering; fieldset.numbering = parentNumbering+"."+(idx+1); fieldset.hasCommentField = fs.form.get('hasCommentField').value; fieldset.title = fs.label; // fieldset.fields = (fs.form.get('fields') as FormArray).getRawValue(); fieldset.fields = (fs.form.get('fields') as FormArray).controls.map(field=>{ const fieldModel = new DatasetDescriptionFieldEditorModel(); fieldModel.data = (field.get('data') as FormGroup).getRawValue(); fieldModel.id = field.get('id').value; fieldModel.viewStyle = (field.get('viewStyle') as FormGroup).getRawValue(); // fieldModel.defaultValue = (field.get('defaultValue') as FormGroup).getRawValue(); fieldModel.value = (field.get('defaultValue') as FormGroup).get('value').value; fieldModel.defaultValue = fieldModel.value; fieldModel.page = field.get('page').value; fieldModel.validations = field.get('validations').value; return fieldModel; }); fieldsets.push(fieldset); }); return fieldsets; } private _getFieldSets(tocentries: ToCEntry[]):ToCEntry[]{ const fieldsets:ToCEntry[] = []; if(!tocentries) return fieldsets; tocentries.forEach(entry=>{ if(entry.type == ToCEntryType.FieldSet){ fieldsets.push(entry); }else{ fieldsets.push(...this._getFieldSets(entry.subEntries)); } }); return fieldsets; } get basicInfo(){ const label = this.form.get('label'); const description = this.form.get('description'); const language = this.form.get('language'); const fg = new FormGroup({ label: label, description: description, language: language }) return fg; } onMatStepperSelectionChange(event: StepperSelectionEvent){ if(event.selectedIndex === 2){//preview selected this.generatePreviewForm();//TODO LAZY LOADING IN THE TEMPLATE }else{ this.previewForm = null; } } previewForm:FormGroup; onDataNeedsRefresh(){ this.refreshToCEntries(); } cloneFieldSet(fieldset: FormGroup){ //TODO const values = fieldset.getRawValue(); const parentArray = fieldset.parent as FormArray; values.id = Guid.create().toString(); values.ordinal = parentArray.length; values.fields.forEach(element => { element.id = Guid.create().toString() }); const clonedModel = new FieldSetEditorModel().fromModel(values); const clonedForm = clonedModel.buildForm(); parentArray.push(clonedForm); //update tocentries and make selected tocentry the cloedn let entries = this.refreshToCEntries(); const entryfound = this._findTocEntryById(clonedForm.get('id').value, entries); if(entryfound){ this.selectedTocEntry = entryfound; } // //create one field form fieldset // const field: FieldEditorModel = new FieldEditorModel(); //to ask // field.id = Guid.create().toString(); // field.ordinal = 0;//first filed in the fields list // fieldSet.fields.push(field); // // field.ordinal = fieldSet.fields.length-1; // //give fieldset id and ordinal // fieldSet.id = Guid.create().toString(); // fieldSet.ordinal = (parent.form.get('fieldSets') as FormArray).length; // (parent.form.get('fieldSets')).push(fieldSet.buildForm()); // // const parentArray = parent.form.get('fieldSets') as FormArray; // const addedFieldSet = parentArray.at(parentArray.length - 1); } validateStep(step: CdkStep){ if(step.hasError){ this.checkFormValidation(); } } }