From 081995e243cc855ded18cfec0421e3c60d625466 Mon Sep 17 00:00:00 2001 From: Kristan Ntavidi Date: Mon, 1 Mar 2021 11:28:27 +0200 Subject: [PATCH] Dataset Profile editor. Drag and drop navigation table of contents. --- ...rofile-editor-composite-field.component.ts | 52 ++- ...ataset-profile-editor-field.component.html | 10 +- .../dataset-profile-editor-field.component.ts | 7 +- .../dataset-profile-editor.component.html | 13 +- .../dataset-profile-editor.component.ts | 279 +++++++++--- .../table-of-contents-internal-section.html | 202 +++++---- .../table-of-contents-internal-section.ts | 36 ++ .../table-of-contents/table-of-contents.html | 7 +- .../table-of-contents/table-of-contents.ts | 409 +++++++++++++++++- dmp-frontend/src/styles.scss | 1 + 10 files changed, 860 insertions(+), 156 deletions(-) diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts index a644b4fa4..3b4b8439c 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; -import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { FormArray, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { FieldEditorModel } from '../../../admin/field-editor-model'; import { Guid } from '@common/types/guid'; import { RuleEditorModel } from '../../../admin/rule-editor-model'; @@ -184,6 +184,8 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh field.ordinal = (this.form.get('fields') as FormArray).length; const fieldForm = field.buildForm(); + fieldForm.setValidators(this.customFieldValidator()); + // fieldForm.get('viewStyle').get('renderStyle').setValidators(Validators.required); (this.form.get('fields')).push(fieldForm); this.setTargetField(fieldForm); @@ -329,6 +331,8 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh field.ordinal = (this.form.get('fields') as FormArray).length; const fieldForm = field.buildForm(); + fieldForm.setValidators(this.customFieldValidator()); + // fieldForm.get('viewStyle').get('renderStyle').setValidators(Validators.required); @@ -421,5 +425,51 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh } + private customFieldValidator(): ValidatorFn{ + return (control):ValidationErrors | null=>{ + DatasetProfileFieldViewStyle + switch(control.get('viewStyle').get('renderStyle').value){ + + case DatasetProfileFieldViewStyle.TextArea: + return null; + case DatasetProfileFieldViewStyle.BooleanDecision: + return null; + case DatasetProfileFieldViewStyle.ComboBox: + return null; + case DatasetProfileFieldViewStyle.CheckBox: + return null; + case DatasetProfileFieldViewStyle.FreeText: + return null; + case DatasetProfileFieldViewStyle.RadioBox: + return null; + case DatasetProfileFieldViewStyle.DatePicker: + return null; + case DatasetProfileFieldViewStyle.InternalDmpEntities: + return null; + case DatasetProfileFieldViewStyle.ExternalDatasets: + return null; + case DatasetProfileFieldViewStyle.DataRepositories: + return null; + case DatasetProfileFieldViewStyle.Registries: + return null; + case DatasetProfileFieldViewStyle.Services: + return null; + case DatasetProfileFieldViewStyle.Tags: + return null; + case DatasetProfileFieldViewStyle.Researchers: + return null; + case DatasetProfileFieldViewStyle.Organizations: + return null; + case DatasetProfileFieldViewStyle.DatasetIdentifier: + return null; + case DatasetProfileFieldViewStyle.Currency: + return null; + case DatasetProfileFieldViewStyle.Validation: + return null; + default: + return {inputTypeNotValid: true} + } + } + } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.html index 20de59793..62a5afe03 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.html @@ -68,9 +68,10 @@ --> - + required + > {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.TextArea)}} {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.FreeText)}} @@ -107,6 +108,8 @@ {{'GENERAL.VALIDATION.REQUIRED' | translate}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + @@ -209,4 +212,5 @@ - \ No newline at end of file + +{{form.touched|json}} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts index 728d835a0..c53c1f0c6 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.ts @@ -1,6 +1,6 @@  import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; -import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms'; import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; import { ValidationType } from '@app/core/common/enum/validation-type'; import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; @@ -34,7 +34,7 @@ import { AutoCompleteFieldDataEditorModel } from '../../../admin/field-data/auto import { DatasetsAutoCompleteFieldDataEditorModel } from '../../../admin/field-data/datasets-autocomplete-field-data-editor-mode'; import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; import { Guid } from '@common/types/guid'; -import { MatSlideToggleChange } from '@angular/material'; +import { ErrorStateMatcher, MatSlideToggleChange } from '@angular/material'; @Component({ selector: 'app-dataset-profile-editor-field-component', @@ -501,4 +501,5 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements onDelete(){ this.delete.emit(); } -} + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html index e957c285b..0baa664b4 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html @@ -46,7 +46,8 @@ - + + + diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts index 8ab289d6c..fe4092a17 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts @@ -2,7 +2,7 @@ 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 { AbstractControl, Form, FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { MatHorizontalStepper, MatStep } from '@angular/material/stepper'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; @@ -38,7 +38,7 @@ import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/vi 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'; - +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); @Component({ @@ -532,8 +532,6 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn if(this.selectedTocEntry){ this.selectedTocEntry = this._findTocEntryById(this.selectedTocEntry.id, this.toCEntries); } - - this.updateOrdinals(this.toCEntries); return this.toCEntries; } @@ -551,6 +549,22 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn }); } + //sort tocentries based on their ordinality + private _sortToCentries(entries: ToCEntry[]){ + if(!entries || !entries.length) return; + entries.sort(this._compareOrdinals); + entries.forEach(e=>{ + this._sortToCentries(e.subEntries) + }); + } + private _compareOrdinals(a, b){ + + const aValue = a.form.get('ordinal').value as number; + const bValue = b.form.get('ordinal').value as number; + + // if(!aValue || !bValue) return 0; + return aValue - bValue; + } toCEntries:ToCEntry[]; @@ -601,6 +615,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn pageToAdd.subEntries.push(item); }); + this._sortToCentries(result); return result; } @@ -678,9 +693,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn } } - if(tocEntryFound) return tocEntryFound; - - return null; + return tocEntryFound? tocEntryFound: null; } addNewEntry(tce: Foo) { @@ -688,81 +701,83 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn //define entry type switch (tce.childType) { - case ToCEntryType.Page: //CALLED FROM PAGE - //create section - // this.addPage(); - // this.displayItem(child); + case ToCEntryType.Page: - - //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()); + const pageForm = page.buildForm(); + // this.dataModel.pages.push(page); - - //make new entry selected const pagesArray = (this.form.get('pages') as FormArray); - const addedEntry = pagesArray.at(pagesArray.length-1) as FormGroup; + pagesArray.push(pageForm); - this.selectedTocEntry = this._findTocEntryById(addedEntry.get('id').value, this.getTocEntries()); + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries); break; - case ToCEntryType.Section: //adding a section + case ToCEntryType.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()); - + if (parent.type === ToCEntryType.Page) {//FIRST LEVEL SECTION sectionsArray = this.form.get('sections') as FormArray; - } else if( parent.type == ToCEntryType.Section) { //subsection + + section.page = parent.id; + section.ordinal = sectionsArray.length; + sectionsArray.push(section.buildForm()); + + } else if( parent.type == ToCEntryType.Section) { //SUBSECTION OF SECTION + sectionsArray = parent.form.get('sections') as FormArray; //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()); + section.ordinal = sectionsArray.length; + sectionsArray.push(section.buildForm()); // (child.form.parent as FormArray).push(section.buildForm()); - sectionsArray = parent.form.get('sections') as FormArray; }else{ - console.error('BUg found'); + console.error('Section can only bee child of a page or another section'); } const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup; - this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.getTocEntries()); + + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.toCEntries); break; case ToCEntryType.FieldSet: - const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); - + //create one field form fieldset - const field: FieldEditorModel = new FieldEditorModel(); //to ask + const field: FieldEditorModel = new FieldEditorModel(); field.id = Guid.create().toString(); field.ordinal = 0;//first filed in the fields list - fieldSet.fields.push(field); + const fieldForm = field.buildForm(); + fieldForm.setValidators(this.customFieldValidator()); + // fieldForm.get('viewStyle').get('renderStyle').setValidators(Validators.required); + + // fieldSet.fields.push(field); // field.ordinal = fieldSet.fields.length-1; - + + const fieldSetsArray = parent.form.get('fieldSets') as FormArray + //give fieldset id and ordinal - fieldSet.id = Guid.create().toString(); - fieldSet.ordinal = (parent.form.get('fieldSets') as FormArray).length; + const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); + const fieldSetId = Guid.create().toString(); + fieldSet.id = fieldSetId; + fieldSet.ordinal = fieldSetsArray.length; + const fieldsetForm = fieldSet.buildForm(); + - (parent.form.get('fieldSets')).push(fieldSet.buildForm()); - const parentArray = parent.form.get('fieldSets') as FormArray; - const addedFieldSet = parentArray.at(parentArray.length - 1); + (fieldsetForm.get('fields') as FormArray).push(fieldForm); + fieldSetsArray.push(fieldsetForm); - this.selectedTocEntry = this._findTocEntryById(addedFieldSet.get('id').value, this.getTocEntries()); + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(fieldSetId, this.toCEntries); break; @@ -770,10 +785,57 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn break; } - this.refreshToCEntries(); + // this.refreshToCEntries(); } + private customFieldValidator(): ValidatorFn{ + return (control):ValidationErrors | null=>{ + DatasetProfileFieldViewStyle + switch(control.get('viewStyle').get('renderStyle').value){ + + case DatasetProfileFieldViewStyle.TextArea: + return null; + case DatasetProfileFieldViewStyle.BooleanDecision: + return null; + case DatasetProfileFieldViewStyle.ComboBox: + return null; + case DatasetProfileFieldViewStyle.CheckBox: + return null; + case DatasetProfileFieldViewStyle.FreeText: + return null; + case DatasetProfileFieldViewStyle.RadioBox: + return null; + case DatasetProfileFieldViewStyle.DatePicker: + return null; + case DatasetProfileFieldViewStyle.InternalDmpEntities: + return null; + case DatasetProfileFieldViewStyle.ExternalDatasets: + return null; + case DatasetProfileFieldViewStyle.DataRepositories: + return null; + case DatasetProfileFieldViewStyle.Registries: + return null; + case DatasetProfileFieldViewStyle.Services: + return null; + case DatasetProfileFieldViewStyle.Tags: + return null; + case DatasetProfileFieldViewStyle.Researchers: + return null; + case DatasetProfileFieldViewStyle.Organizations: + return null; + case DatasetProfileFieldViewStyle.DatasetIdentifier: + return null; + case DatasetProfileFieldViewStyle.Currency: + return null; + case DatasetProfileFieldViewStyle.Validation: + return null; + default: + return {inputTypeNotValid: true}; + } + } + } + onRemoveEntry(tce: ToCEntry){ @@ -1282,7 +1344,6 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn } cloneFieldSet(fieldset: FormGroup){ - //TODO const values = fieldset.getRawValue(); const parentArray = fieldset.parent as FormArray; @@ -1332,4 +1393,124 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn this.checkFormValidation(); } } + + getFormValidationErrors() { + Object.keys(this.form.controls).forEach(key => { + + const controlErrors: ValidationErrors = this.form.get(key).errors; + if (controlErrors != null) { + Object.keys(controlErrors).forEach(keyError => { + console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]); + }); + } + }); + + if(this.form.invalid){ + console.log('this form is invalid!'); + console.log(this.form.errors); + } + } + + + + + printMyErrors(){ + // this._printToCentriesErrrors(this.toCEntries); + this._getErrors(this.form); + } + + + private _printToCentriesErrrors(entries: ToCEntry[]){ + + if(!entries || !entries.length) return; + + entries.forEach(e=>{ + + + // if(e.form instanceof FormGroup) console.log('is Formgroup'); + // if(e.form instanceof FormControl) console.log('is formcontrols'); + // if(e.form instanceof FormArray) console.log('isForm array'); + + + const form = e.form as FormGroup; + if(form.invalid){ + const controls = form.controls; + const keys = Object.keys(controls); + keys.forEach(key=>{ + const control = controls[key]; + + if(control.invalid){ + console.log('control ', key, 'is invalid'); + } + }) + + + // console.log('keys,', keys); + + + this._printToCentriesErrrors(e.subEntries); + } + }); + } + + + + + private _getErrors(aControl: AbstractControl){ + + if(aControl instanceof FormGroup) console.log('is Formgroup'); + if(aControl instanceof FormControl)console.log( aControl.errors); + if(aControl instanceof FormArray) console.log('isForm array'); + if(aControl.valid) return; + + let controlType = 'control'; + + if(aControl instanceof FormGroup) controlType="fg" + if(aControl instanceof FormControl) controlType="fc"; + if(aControl instanceof FormArray) controlType="fa"; + + + //invalid + switch (controlType){ + case 'fg': + + const controls = (aControl as FormGroup).controls; + const keys = Object.keys(controls); + keys.forEach(key=>{ + const control = controls[key]; + // if(control.invalid){ + this._getErrors(control); + // } + }); + + break; + case 'fc': + //form control print errors + console.log(aControl.errors); + break; + case 'fa': + const fa = (aControl as FormArray); + fa.controls.forEach(control=>{ + this._getErrors(control); + }); + break; + } + + + + + + // const controls = rootForm.controls; + // const keys = Object.keys(controls); + // keys.forEach(key=>{ + // const control = controls[key]; + + + // if(control.invalid){ + // console.log('control ', key, 'is invalid'); + // } + // }) + + } + } \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.html b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.html index 7ff54b063..d4b37a82f 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.html @@ -33,7 +33,7 @@
+ *ngIf="!(!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id ||isDragging)"> {{parentLink.subEntries?.length}} @@ -48,98 +48,108 @@ -
- + -
- + +
+ +
+ + + + + +