argos/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.comp...

1335 lines
41 KiB
TypeScript

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<BreadcrumbItem[]>;
@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 = <FormGroup>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) {
(<FormControl>this.form.get('multiplicity').get('min')).setValue(0);
(<FormControl>this.form.get('multiplicity').get('max')).setValue(0);
}
}
addSection() {
const section: SectionEditorModel = new SectionEditorModel();
this.dataModel.sections.push(section);
(<FormArray>this.form.get('sections')).push(section.buildForm());
}
addPage() {
const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length);
this.dataModel.pages.push(page);
(<FormArray>this.form.get('pages')).push(page.buildForm());
}
DeleteSection(index) {
this.dataModel.sections.splice(index, 1);
(<FormArray>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(<FormGroup>rootform.get(key));
} else if (rootform.get(key) instanceof FormArray) {
this.nestedIndex++;
this.nestedCount[this.nestedIndex] = 0;
for (let childForm of (<FormArray>rootform.get(key)).controls) {
this.nestedCount[this.nestedIndex]++;
this.printErrors(<any>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 = <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);
(<FormArray>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;
(<FormArray>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;
(<FormArray>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;
(<FormArray>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<pages.length; i++){
pages.at(i).get('ordinal').patchValue(i);
}
//update validity
this.form.controls.sections.updateValueAndValidity();
}
break;
case ToCEntryType.Section:
//FIRST LEVEL SECTION CASE
let index = -1;
const sections = (this.form.get('sections') as FormArray);
for (let i = 0; i < sections.length; i++) {
let section = sections.at(i);
let sectionId = section.get('id').value;
if (sectionId == tce.id) {
index = i;
break;
}
}
if (index >= 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<parentFormArray.length; i++){
parentFormArray.at(i).get('ordinal').patchValue(i);
}
}
}
break;
case ToCEntryType.FieldSet:
const parentFormArray = tce.form.parent as FormArray;
let idx = -1;
for(let i =0; i< parentFormArray.length; i++){
let inspectingField = parentFormArray.at(i);
if(inspectingField.get('id').value === tce.id){
//fieldset found
idx = i;
break;
}
}
if(idx>=0){//fieldset found
this._updateSelectedItem(tce);
parentFormArray.removeAt(idx);
//patching order
for(let i=0; i<parentFormArray.length;i++){
parentFormArray.at(i).get('ordinal').patchValue(i);
}
}
break;
default:
break;
}
//in case selectedtocentrhy is child of the removed element
this.refreshToCEntries();
}
private _updateSelectedItem(tce: ToCEntry){
if(this.selectedTocEntry ){
if(this.tocEntryIsChildOf(this.selectedTocEntry,tce)){
if(this.selectedTocEntry.type == ToCEntryType.Page){
this.selectedTocEntry = null;
}else{
//if first level section
const firstLevelSections = (this.form.get('sections') as FormArray);
let isFirstLevel: boolean = false;
firstLevelSections.controls.forEach(section=>{
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 (<FormArray>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<CdkStep>;
// 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<DatasetDescriptionSectionEditorModel> = [];
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;
// (<FormArray>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();
}
}
}