diff --git a/dmp-frontend/package.json b/dmp-frontend/package.json index 2f48fb926..ed4ad77f2 100644 --- a/dmp-frontend/package.json +++ b/dmp-frontend/package.json @@ -31,6 +31,7 @@ "moment": "^2.24.0", "moment-timezone": "^0.5.26", "ng-dialog-animation": "^9.0.3", + "ng2-dragula": "^2.1.1", "ngx-cookie-service": "^2.2.0", "ngx-cookieconsent": "^2.2.3", "ngx-dropzone": "^2.2.2", diff --git a/dmp-frontend/src/app/app.component.ts b/dmp-frontend/src/app/app.component.ts index fb6133528..1d17cb1ae 100644 --- a/dmp-frontend/src/app/app.component.ts +++ b/dmp-frontend/src/app/app.component.ts @@ -2,7 +2,7 @@ import { of as observableOf, Subscription } from 'rxjs'; import { switchMap, filter, map, takeUntil } from 'rxjs/operators'; -import { Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { environment } from '../environments/environment'; @@ -18,6 +18,8 @@ import { ConfigurationService } from './core/services/configuration/configuratio import { Location } from '@angular/common'; import { MatomoInjector } from 'ngx-matomo'; import { MatomoService } from './core/services/matomo/matomo-service'; +import { SideNavService } from './core/services/sidenav/side-nav.sevice'; +import { MatSidenav } from '@angular/material'; declare const gapi: any; @@ -28,14 +30,17 @@ declare var $: any; templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent implements OnInit { +export class AppComponent implements OnInit, AfterViewInit { hasBreadCrumb = observableOf(false); - sideNavOpen = false; + // sideNavOpen = false; + private sideNavSubscription: Subscription; helpContentEnabled: boolean; private statusChangeSubscription: Subscription; onlySplash = true; + @ViewChild('sidenav', {static:false}) sidenav:MatSidenav; + constructor( private router: Router, private route: ActivatedRoute, @@ -49,12 +54,47 @@ export class AppComponent implements OnInit { private language: LanguageService, private configurationService: ConfigurationService, private location: Location, - private matomoService: MatomoService + private matomoService: MatomoService, + private sidenavService: SideNavService ) { this.initializeServices(); this.matomoService.init(); this.helpContentEnabled = configurationService.helpService.enabled; } + ngAfterViewInit(): void { + setTimeout(() => { + this.sideNavSubscription = this.sidenavService.status().subscribe(isopen=>{ + const hamburger = document.getElementById('hamburger'); + if(isopen){ + //update value of hamburfer + if(!hamburger){//try later + setTimeout(() => { + const hamburger = document.getElementById('hamburger'); + if(hamburger){ + hamburger.classList.add('change'); + } + }, 300); + }else{ + hamburger.classList.add('change'); + } + this.sidenav.open() + }else{//closed + if(!hamburger){//try later + setTimeout(() => { + const hamburger = document.getElementById('hamburger'); + if(hamburger){ + hamburger.classList.remove('change'); + } + }, 300); + }else{ + hamburger.classList.remove('change'); + } + this.sidenav.close(); + + } + }); + }); + } onActivate(event: any) { this.breadCrumbResolverService.push(event); @@ -79,7 +119,9 @@ export class AppComponent implements OnInit { this.onlySplash = false; } if (!this.cookieService.check("cookiesConsent")) { - this.cookieService.set("cookiesConsent", "false", 356); + // this.cookieService.set("cookiesConsent", "false", 356); + this.cookieService.set("cookiesConsent", "false", 356,null,null,false, 'Lax'); + } this.hasBreadCrumb = this.router.events.pipe( @@ -112,7 +154,8 @@ export class AppComponent implements OnInit { this.statusChangeSubscription = this.ccService.statusChange$.subscribe((event: NgcStatusChangeEvent) => { if (event.status == "dismiss") { - this.cookieService.set("cookiesConsent", "true", 365); + // this.cookieService.set("cookiesConsent", "true", 365); + this.cookieService.set("cookiesConsent", "true", 356,null,null,false, 'Lax'); } }); @@ -134,7 +177,7 @@ export class AppComponent implements OnInit { } this.ccService.destroy(); this.ccService.init(this.ccService.getConfig()); - }) + }); } translateTitle(ttl: string) { @@ -153,6 +196,9 @@ export class AppComponent implements OnInit { ngOnDestroy() { this.statusChangeSubscription.unsubscribe(); + if(this.sideNavSubscription){ + this.sideNavSubscription.unsubscribe(); + } } login() { diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index 3582aa783..d5ad06c43 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -32,6 +32,7 @@ import { TranslateServerLoader } from './core/services/language/server.loader'; import { MatomoService } from './core/services/matomo/matomo-service'; import { GuidedTourModule } from './library/guided-tour/guided-tour.module'; import { Oauth2DialogModule } from './ui/misc/oauth2-dialog/oauth2-dialog.module'; +import { DragulaModule } from 'ng2-dragula'; // AoT requires an exported function for factories export function HttpLoaderFactory(http: HttpClient, appConfig: ConfigurationService) { @@ -107,7 +108,8 @@ const appearance: MatFormFieldDefaultOptions = { SidebarModule, NgcCookieConsentModule.forRoot(cookieConfig), Oauth2DialogModule, - GuidedTourModule.forRoot() + GuidedTourModule.forRoot(), + DragulaModule.forRoot() ], declarations: [ AppComponent, diff --git a/dmp-frontend/src/app/core/model/dataset-profile-definition/field-data/field-data.ts b/dmp-frontend/src/app/core/model/dataset-profile-definition/field-data/field-data.ts index 2a2e953f8..47adf26c8 100644 --- a/dmp-frontend/src/app/core/model/dataset-profile-definition/field-data/field-data.ts +++ b/dmp-frontend/src/app/core/model/dataset-profile-definition/field-data/field-data.ts @@ -94,7 +94,7 @@ export interface ResearchersFieldData extends FieldData { } -export interface OrganizationsFieldData extends FieldData { +export interface OrganizationsFieldData extends AutoCompleteFieldData { } diff --git a/dmp-frontend/src/app/core/model/dataset/dataset-id.model.ts b/dmp-frontend/src/app/core/model/dataset/dataset-id.model.ts index 5020bbbcb..1063a3cbf 100644 --- a/dmp-frontend/src/app/core/model/dataset/dataset-id.model.ts +++ b/dmp-frontend/src/app/core/model/dataset/dataset-id.model.ts @@ -6,11 +6,16 @@ export class DatasetIdModel { type: string; constructor(data: any) { + try{ const parsed = JSON.parse(data); if (!isNullOrUndefined(parsed)) { this.identifier = parsed.identifier; this.type = parsed.type; } + } + catch(error){ + console.warn('Could not parse DatasetIdModel'); + } } buildForm(): FormGroup { diff --git a/dmp-frontend/src/app/core/query/dataset/daatset-external-autocomplete-criteria.ts b/dmp-frontend/src/app/core/query/dataset/daatset-external-autocomplete-criteria.ts index 9351b8ed1..d511e9432 100644 --- a/dmp-frontend/src/app/core/query/dataset/daatset-external-autocomplete-criteria.ts +++ b/dmp-frontend/src/app/core/query/dataset/daatset-external-autocomplete-criteria.ts @@ -1,6 +1,8 @@ +import { AutoCompleteSingleData } from "@app/core/model/dataset-profile-definition/field-data/field-data"; import { BaseCriteria } from "../base-criteria"; export class DatasetExternalAutocompleteCriteria extends BaseCriteria { public profileID: String; public fieldID: String; + public autocompleteOptions: AutoCompleteSingleData; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/services/auth/auth.service.ts b/dmp-frontend/src/app/core/services/auth/auth.service.ts index 4217d66e5..e3fb7875e 100644 --- a/dmp-frontend/src/app/core/services/auth/auth.service.ts +++ b/dmp-frontend/src/app/core/services/auth/auth.service.ts @@ -81,7 +81,8 @@ export class AuthService extends BaseService { return this.http.post(url, loginInfo, { headers: this.headers }).pipe( map((res: any) => { const principal = this.current(res.payload); - this.cookieService.set('cookiesConsent', 'true', 356); + // this.cookieService.set('cookiesConsent', 'true', 356); + this.cookieService.set("cookiesConsent", "true", 356,null,null,false, 'Lax'); //this.loginContextSubject.next(true); return principal; }), @@ -105,7 +106,8 @@ export class AuthService extends BaseService { return this.http.post(url, credentials, { headers: this.headers }).pipe( map((res: any) => { const principal = this.current(res.payload); - this.cookieService.set('cookiesConsent', 'true', 356); + // this.cookieService.set('cookiesConsent', 'true', 356); + this.cookieService.set("cookiesConsent", "true", 356,null,null,false, 'Lax'); //this.loginContextSubject.next(true); return principal; }), diff --git a/dmp-frontend/src/app/core/services/dataset/dataset-external-autocomplete.service.ts b/dmp-frontend/src/app/core/services/dataset/dataset-external-autocomplete.service.ts index 35ee12a6f..bcbfd2630 100644 --- a/dmp-frontend/src/app/core/services/dataset/dataset-external-autocomplete.service.ts +++ b/dmp-frontend/src/app/core/services/dataset/dataset-external-autocomplete.service.ts @@ -1,11 +1,12 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { environment } from '../../../../environments/environment'; import { DatasetExternalAutocompleteCriteria } from '../../query/dataset/daatset-external-autocomplete-criteria'; import { RequestItem } from '../../query/request-item'; import { DatasetProfileService } from '../dataset-profile/dataset-profile.service'; import { ConfigurationService } from '../configuration/configuration.service'; +import { map } from 'rxjs/operators'; @Injectable() export class DatasetExternalAutocompleteService { @@ -27,4 +28,14 @@ export class DatasetExternalAutocompleteService { return this.httpClient.post(this.configurationService.server + 'search/autocomplete', lookUpItem); } -} + queryApi(requestItem: RequestItem):Observable{ //TODO + + return of([ + { + label:'Preview not supported yet', + source:'' + } + ]); + } + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/services/sidenav/side-nav.sevice.ts b/dmp-frontend/src/app/core/services/sidenav/side-nav.sevice.ts new file mode 100644 index 000000000..4fe163777 --- /dev/null +++ b/dmp-frontend/src/app/core/services/sidenav/side-nav.sevice.ts @@ -0,0 +1,24 @@ +import { Injectable } from "@angular/core"; +import { Observable } from "rxjs"; +import { BehaviorSubject } from "rxjs"; + +@Injectable({ + providedIn:'root' +}) +export class SideNavService { + + private sidebar$:BehaviorSubject = new BehaviorSubject(true); + + public status():Observable{ + return this.sidebar$.asObservable(); + } + + public setStatus(isOpen: boolean){ + this.sidebar$.next(isOpen); + } + + public toggle(){ + this.sidebar$.next(!this.sidebar$.getValue()); + } + +} diff --git a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts index ddf120849..7edcb5100 100644 --- a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts +++ b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts @@ -12,6 +12,7 @@ import { DatasetProfileInternalDmpEntitiesType } from '../../common/enum/dataset import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; import { Role } from '@app/core/common/enum/role'; import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type'; +import { ViewStyleType } from '@app/ui/admin/dataset-profile/editor/components/field/view-style-enum'; @Injectable() export class EnumUtils { @@ -90,6 +91,30 @@ export class EnumUtils { case DatasetProfileFieldViewStyle.Validation: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.VALIDATION'); } } + toDatasetProfileViewTypeString(status: ViewStyleType) :string{ + switch (status) { + case ViewStyleType.BooleanDecision: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.BOOLEAN-DECISION'); + case ViewStyleType.CheckBox: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.CHECKBOX'); + case ViewStyleType.Select: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.SELECT'); + case ViewStyleType.InternalDmpEntities: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.INTERNAL-DMP-ENTITIES'); + case ViewStyleType.FreeText: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.FREE-TEXT'); + case ViewStyleType.RadioBox: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.RADIO-BOX'); + case ViewStyleType.TextArea: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.TEXT-AREA'); + case ViewStyleType.DatePicker: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.DATE-PICKER'); + case ViewStyleType.ExternalDatasets: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.EXTERNAL-DATASETS'); + case ViewStyleType.DataRepositories: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.DATA-REPOSITORIES'); + case ViewStyleType.Registries: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.REGISTRIES'); + case ViewStyleType.Services: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.SERVICES'); + case ViewStyleType.Tags: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.TAGS'); + case ViewStyleType.Researchers: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.RESEARCHERS'); + case ViewStyleType.Organizations: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.ORGANIZATIONS'); + case ViewStyleType.DatasetIdentifier: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.DATASET-IDENTIFIER'); + case ViewStyleType.Currency: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.CURRENCY'); + case ViewStyleType.Validation: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.VALIDATION'); + case ViewStyleType.Other: return this.language.instant('TYPES.DATASET-PROFILE-FIELD-VIEW-STYLE.OTHER'); + } + + } toDatasetProfileComboBoxTypeString(status: DatasetProfileComboBoxType): string { switch (status) { diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index 83b01d997..3c89cd3ff 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -10,7 +10,7 @@ - + arrow_drop_down diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss index 1230c73a7..76cfcb18e 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.scss @@ -44,3 +44,24 @@ max-height: 4.8em !important; overflow: auto !important; } +.hide-placeholder{ + &::-webkit-input-placeholder { + /* WebKit browsers */ + color: transparent; + } + &:-moz-placeholder { + /* Mozilla Firefox 4 to 18 */ + color: transparent; + } + &::-moz-placeholder { + /* Mozilla Firefox 19+ */ + color: transparent; + } + &:-ms-input-placeholder { + /* Internet Explorer 10+ */ + color: transparent; + } + &::placeholder { + color: transparent; + } + } \ No newline at end of file diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index 89470bca2..fd9854690 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -66,6 +66,7 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp get shouldLabelFloat() { return this.focused || !this.empty; } + @Input() hidePlaceholder: boolean = false; @Input() get placeholder() { return this._placeholder; } set placeholder(placeholder) { diff --git a/dmp-frontend/src/app/library/guided-tour/guided-tour.component.ts b/dmp-frontend/src/app/library/guided-tour/guided-tour.component.ts index 913ab6d1b..e093b543b 100644 --- a/dmp-frontend/src/app/library/guided-tour/guided-tour.component.ts +++ b/dmp-frontend/src/app/library/guided-tour/guided-tour.component.ts @@ -388,7 +388,10 @@ export class GuidedTourComponent implements AfterViewInit, OnDestroy { } const scrollAdjustment = this.currentTourStep.scrollAdjustment ? this.currentTourStep.scrollAdjustment : 0; - const tourStepHeight = typeof this.tourStep.nativeElement.getBoundingClientRect === 'function' ? this.tourStep.nativeElement.getBoundingClientRect().height : 0; + let tourStepHeight = 0; + if (this.tourStep != null && this.tourStep.nativeElement != null && typeof this.tourStep.nativeElement.getBoundingClientRect === 'function') { + tourStepHeight = this.tourStep.nativeElement.getBoundingClientRect().height; + } const elementHeight = this.selectedElementRect.height + scrollAdjustment + tourStepHeight; if ((this.windowRef.nativeWindow.innerHeight - this.topOfPageAdjustment) < elementHeight) { diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/auto-complete-single-data.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/auto-complete-single-data.ts index 929edc891..3bffd86d1 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/auto-complete-single-data.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/auto-complete-single-data.ts @@ -1,7 +1,7 @@ import { FieldDataEditorModel } from './field-data-editor-model'; import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; import { FieldDataOptionEditorModel } from './field-data-option-editor-model'; -import { FormGroup } from '@angular/forms'; +import { FormGroup, Validators } from '@angular/forms'; import { AutoCompleteFieldData, AutoCompleteSingleData } from '@app/core/model/dataset-profile-definition/field-data/field-data'; export class AutoCompleteSingleDataEditorModel extends FieldDataEditorModel { @@ -16,8 +16,8 @@ export class AutoCompleteSingleDataEditorModel extends FieldDataEditorModel = []): FormGroup { const formGroup = this.formBuilder.group({ label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.label')) }], - url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.url')) }], - optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.optionsRoot')) }], + url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.url')) },[Validators.required]], + optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.optionsRoot')) }, [Validators.required]], autoCompleteType: [{ value: this.autoCompleteType, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.autoCompleteType')) }] }); formGroup.addControl('autoCompleteOptions', this.autoCompleteOptions.buildForm(disabled, skipDisable)); diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/field-data-option-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/field-data-option-editor-model.ts index 5b0067954..d13491cd1 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/field-data-option-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/field-data-option-editor-model.ts @@ -1,4 +1,4 @@ -import { FormBuilder, FormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FieldDataOption } from '../../../../../core/model/dataset-profile-definition/field-data/field-data'; import { FieldDataEditorModel } from './field-data-editor-model'; @@ -9,8 +9,8 @@ export class FieldDataOptionEditorModel extends FieldDataEditorModel = []): FormGroup { return new FormBuilder().group({ - label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('FieldDataOptionEditorModel.label')) }], - value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('FieldDataOptionEditorModel.value')) }], + label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('FieldDataOptionEditorModel.label')) },[Validators.required]], + value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('FieldDataOptionEditorModel.value')) },[Validators.required]], source: [{ value: this.source, disabled: (disabled && !skipDisable.includes('FieldDataOptionEditorModel.source')) }] }); } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/organizations-data-editor-models.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/organizations-data-editor-models.ts index 975abbe0b..92090f3fd 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/organizations-data-editor-models.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-data/organizations-data-editor-models.ts @@ -4,16 +4,19 @@ import { OrganizationsFieldData } from '../../../../../core/model/dataset-profil export class OrganizationsDataEditorModel extends FieldDataEditorModel { public label: string; + public multiAutoComplete: boolean = false; buildForm(disabled: boolean = false, skipDisable: Array = []): FormGroup { const formGroup = this.formBuilder.group({ - label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('OrganizationsDataEditorModel.label')) }] + label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('OrganizationsDataEditorModel.label')) }], + multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('OrganizationsDataEditorModel.multiAutoComplete')) }] }); return formGroup; } fromModel(item: OrganizationsFieldData): OrganizationsDataEditorModel { this.label = item.label; + this.multiAutoComplete = item.multiAutoComplete; return this; } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-editor-model.ts index fcaf00324..66dd8928d 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-editor-model.ts @@ -27,6 +27,9 @@ import { ResearchersDataEditorModel } from './field-data/researchers-data-editor import { OrganizationsDataEditorModel } from './field-data/organizations-data-editor-models'; import { DatasetIdentifierDataEditorModel } from './field-data/dataset-identifier-data-editor-models'; import { CurrencyDataEditorModel } from './field-data/currency-data-editor-models'; +import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; +import { EditorCustomValidators } from '../editor/custom-validators/editor-custom-validators'; +import { ValidationDataEditorModel } from './field-data/validation-data-editor-models'; export class FieldEditorModel extends BaseFormModel { @@ -68,13 +71,14 @@ export class FieldEditorModel extends BaseFormModel { if (this.viewStyle.renderStyle === 'datePicker') { this.data = new DatePickerDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'externalDatasets') { this.data = new ExternalDatasetsDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'dataRepositories') { this.data = new DataRepositoriesDataEditorModel().fromModel(item.data); } - if (this.viewStyle.renderStyle === 'registeries') { this.data = new RegistriesDataEditorModel().fromModel(item.data); } + if (this.viewStyle.renderStyle === 'registries') { this.data = new RegistriesDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'services') { this.data = new ServicesDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'tags') { this.data = new TagsDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'researchers') { this.data = new ResearchersDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'organizations') { this.data = new OrganizationsDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'datasetIdentifier') { this.data = new DatasetIdentifierDataEditorModel().fromModel(item.data); } if (this.viewStyle.renderStyle === 'currency') { this.data = new CurrencyDataEditorModel().fromModel(item.data); } + if (this.viewStyle.renderStyle === 'validation') { this.data = new ValidationDataEditorModel().fromModel(item.data); } } } return this; @@ -96,6 +100,57 @@ export class FieldEditorModel extends BaseFormModel { if (this.data) { formGroup.addControl('data', this.data.buildForm(disabled, skipDisable)); } else { formGroup.addControl('data', new WordListFieldDataEditorModel().buildForm(disabled, skipDisable)); } + + // //append validators + + this._appendCustomValidators(formGroup); + + + // //setting up listeners + // formGroup.get('viewStyle').valueChanges.subscribe(changes=>{ + // // const viewStyleChanges:{cssClass:string, renderStyle: string} = changes; + + // this._removeCustomValidators(formGroup); + // this._appendCustomValidators(formGroup); + + // }) + return formGroup; } + + + private _appendCustomValidators(formGroup: FormGroup){ + const renderStyleValue = formGroup.get('viewStyle').get('renderStyle').value; + if(renderStyleValue === 'checkBox'){ + formGroup.get('defaultValue').get('value').setValidators(Validators.required); + formGroup.get('defaultValue').get('value').updateValueAndValidity(); + }else if(renderStyleValue === 'combobox'){ + try{ + const comboType = formGroup.get('data').get('type').value; + if(comboType === DatasetProfileComboBoxType.Autocomplete){//As 'Other' in UI + formGroup.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList')); + }else if(comboType === DatasetProfileComboBoxType.WordList){ + formGroup.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + } + }catch(e){ + console.error('Error setting validators.'); + console.error(e); + } + }else if(renderStyleValue === 'radiobox'){ + formGroup.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + } + formGroup.get('data').updateValueAndValidity(); + } + + // private _removeCustomValidators(formGroup:FormGroup){ + // const renderStyleValue = formGroup.get('viewStyle').get('renderStyle').value; + // if(renderStyleValue != 'checkBox'){ + // formGroup.get('defaultValue').get('value').clearValidators(); + // }else if(renderStyleValue === 'combobox'){ + // formGroup.get('data').clearValidators(); + // } + // } + // private _buildData(formGroup: FormGroup){ + + // } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-set-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-set-editor-model.ts index 37e9f1fe4..052bd353b 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-set-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/field-set-editor-model.ts @@ -35,7 +35,7 @@ export class FieldSetEditorModel extends BaseFormModel { const formGroup = this.formBuilder.group({ id: [{ value: this.id, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.id')) }, [Validators.required, Validators.pattern('^[^<_>]+$')]], ordinal: [{ value: this.ordinal, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.ordinal')) }], - title: [{ value: this.title, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.title')) }], + title: [{ value: this.title, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.title')) }, [Validators.required]], description: [{ value: this.description, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.description')) }], extendedDescription: [{ value: this.extendedDescription, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.extendedDescription')) }], additionalInformation: [{ value: this.additionalInformation, disabled: (disabled && !skipDisable.includes('FieldSetEditorModel.additionalInformation')) }], diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/rule-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/rule-editor-model.ts index 6d029f80e..6e878666c 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/rule-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/rule-editor-model.ts @@ -1,4 +1,4 @@ -import { FormGroup } from "@angular/forms"; +import { FormGroup, Validators } from "@angular/forms"; import { Rule } from "../../../../core/model/admin/dataset-profile/dataset-profile"; import { BaseFormModel } from "../../../../core/model/base-form-model"; @@ -21,9 +21,9 @@ export class RuleEditorModel extends BaseFormModel { buildForm(disabled: boolean = false, skipDisable: Array = []): FormGroup { const formGroup = this.formBuilder.group({ // sourceField: [this.sourceField], - target: [{ value: this.target, disabled: (disabled && !skipDisable.includes('RuleEditorModel.target')) }], + target: [{ value: this.target, disabled: (disabled && !skipDisable.includes('RuleEditorModel.target')) }, [Validators.required]], ruleStyle: [{ value: this.ruleStyle, disabled: (disabled && !skipDisable.includes('RuleEditorModel.ruleStyle')) }], - value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('RuleEditorModel.value')) }], + value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('RuleEditorModel.value')) }, [Validators.required]], ruleType: [{ value: this.ruleType, disabled: (disabled && !skipDisable.includes('RuleEditorModel.ruleType')) }], valueType: [{ value: this.valueType, disabled: (disabled && !skipDisable.includes('RuleEditorModel.valueType')) }] }); diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/section-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/section-editor-model.ts index 8edc81899..9d7c7825b 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/section-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/section-editor-model.ts @@ -1,6 +1,7 @@ import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Section } from '../../../../core/model/admin/dataset-profile/dataset-profile'; import { BaseFormModel } from '../../../../core/model/base-form-model'; +import { EditorCustomValidators } from '../editor/custom-validators/editor-custom-validators'; import { FieldSetEditorModel } from './field-set-editor-model'; export class SectionEditorModel extends BaseFormModel { @@ -29,7 +30,7 @@ export class SectionEditorModel extends BaseFormModel { const formGroup: FormGroup = new FormBuilder().group({ id: [{ value: this.id, disabled: (disabled && !skipDisable.includes('SectionEditorModel.id')) }, [Validators.required, Validators.pattern('^[^<_>]+$')]], page: [{ value: this.page, disabled: (disabled && !skipDisable.includes('SectionEditorModel.page')) }, [Validators.required]], - title: [{ value: this.title, disabled: (disabled && !skipDisable.includes('SectionEditorModel.title')) }], + title: [{ value: this.title, disabled: (disabled && !skipDisable.includes('SectionEditorModel.title')) } , [Validators.required]], description: [{ value: this.description, disabled: (disabled && !skipDisable.includes('SectionEditorModel.description')) }], ordinal: [{ value: this.ordinal, disabled: (disabled && !skipDisable.includes('SectionEditorModel.ordinal')) }, [Validators.required]], defaultVisibility: [{ value: this.defaultVisibility, disabled: (disabled && !skipDisable.includes('SectionEditorModel.defaultVisibility')) }] @@ -53,6 +54,8 @@ export class SectionEditorModel extends BaseFormModel { if (!formGroup.controls['defaultVisibility'].value) { formGroup.controls['defaultVisibility'].setValue(true); } + formGroup.setValidators(EditorCustomValidators.sectionHasAtLeastOneChildOf('fieldSets','sections')); + formGroup.updateValueAndValidity(); return formGroup; } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/view-style-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/view-style-editor-model.ts index de61824a9..586d603f8 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/view-style-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/view-style-editor-model.ts @@ -1,4 +1,4 @@ -import { FormGroup } from "@angular/forms"; +import { FormGroup, Validators } from "@angular/forms"; import { ViewStyle } from "../../../../core/model/admin/dataset-profile/dataset-profile"; import { BaseFormModel } from "../../../../core/model/base-form-model"; @@ -15,7 +15,7 @@ export class ViewStyleEditorModel extends BaseFormModel { buildForm(disabled: boolean = false, skipDisable: Array = []): FormGroup { const formGroup = this.formBuilder.group({ cssClass: [{ value: this.cssClass, disabled: (disabled && !skipDisable.includes('ViewStyleEditorModel.cssClass')) }], - renderStyle: [{ value: this.renderStyle, disabled: (disabled && !skipDisable.includes('ViewStyleEditorModel.renderStyle')) }] + renderStyle: [{ value: this.renderStyle, disabled: (disabled && !skipDisable.includes('ViewStyleEditorModel.renderStyle')) }, Validators.required] }); return formGroup; } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts index e79d5176d..6a20faad6 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/dataset-profile.module.ts @@ -1,6 +1,5 @@ import { NgModule } from '@angular/core'; import { FormattingModule } from '@app/core/formatting.module'; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { DatasetProfileRoutingModule } from '@app/ui/admin/dataset-profile/dataset-profile.routing'; import { DatasetProfileEditorCompositeFieldComponent } from '@app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component'; import { DatasetProfileEditorDefaultValueComponent } from '@app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component'; @@ -23,21 +22,38 @@ import { DatasetProfileEditorRuleComponent } from '@app/ui/admin/dataset-profile import { DatasetProfileEditorSectionComponent } from '@app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component'; import { DatasetProfileEditorComponent } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor.component'; import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component'; -import { DialodConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { DialogConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; import { DatasetProfileListingComponent } from '@app/ui/admin/dataset-profile/listing/dataset-profile-listing.component'; +import { DatasetModule } from '@app/ui/dataset/dataset.module'; +import { FormProgressIndicationModule } from '@app/ui/misc/dataset-description-form/components/form-progress-indication/form-progress-indication.module'; +import { TableOfContentsModule } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { CommonUiModule } from '@common/ui/common-ui.module'; -import { ParseStatus } from './listing/pipe/parse-status.pipe'; -import { DatasetProfileEditorExternalDatasetsFieldComponent } from './editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component'; +import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; +import { DatasetProfileEditorCurrencyFieldComponent } from './editor/components/field-type/currency/dataset-profile-editor-currency-field.component'; import { DatasetProfileEditorDataRepositoriesFieldComponent } from './editor/components/field-type/data-repositories/dataset-profile-editor-data-repositories-field.component'; +import { DatasetProfileEditorDatasetIdentifierFieldComponent } from './editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component'; +import { DatasetProfileEditorExternalDatasetsFieldComponent } from './editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component'; +import { DatasetProfileEditorOrganizationsFieldComponent } from './editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component'; import { DatasetProfileEditorRegistriesFieldComponent } from './editor/components/field-type/registries/dataset-profile-editor-registries-field.component'; +import { DatasetProfileEditorResearchersFieldComponent } from './editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component'; import { DatasetProfileEditorServicesFieldComponent } from './editor/components/field-type/services/dataset-profile-editor-services-field.component'; import { DatasetProfileEditorTagsFieldComponent } from './editor/components/field-type/tags/dataset-profile-editor-tags-field.component'; -import { DatasetProfileEditorResearchersFieldComponent } from './editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component'; -import { DatasetProfileEditorOrganizationsFieldComponent } from './editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component'; -import { DatasetProfileEditorDatasetIdentifierFieldComponent } from './editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component'; -import { DatasetProfileEditorCurrencyFieldComponent } from './editor/components/field-type/currency/dataset-profile-editor-currency-field.component'; import { DatasetProfileEditorValidatorFieldComponent } from './editor/components/field-type/validator/dataset-profile-editor-validator-field.component'; +import { NgxDropzoneModule } from 'ngx-dropzone'; +import { ParseStatus } from './listing/pipe/parse-status.pipe'; +import { DatasetProfileTableOfContents } from './table-of-contents/table-of-contents'; +import { DatasetProfileTableOfContentsInternalSection } from './table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section'; +import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; +import {DragDropModule} from '@angular/cdk/drag-drop'; +import {DragulaModule} from 'ng2-dragula'; + + +//matrial +import {MatBadgeModule} from '@angular/material/badge'; +import { DatasetProfileEditorSectionFieldSetComponent } from './editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component'; +import { FinalPreviewComponent } from './editor/components/final-preview/final-preview.component'; @NgModule({ imports: [ @@ -45,7 +61,14 @@ import { DatasetProfileEditorValidatorFieldComponent } from './editor/components CommonFormsModule, FormattingModule, DatasetProfileRoutingModule, - ConfirmationDialogModule + ConfirmationDialogModule, + NgxDropzoneModule, + FormProgressIndicationModule, + DatasetModule, + AngularStickyThingsModule, + DragDropModule, + MatBadgeModule, + DragulaModule ], declarations: [ DatasetProfileListingComponent, @@ -66,7 +89,7 @@ import { DatasetProfileEditorValidatorFieldComponent } from './editor/components DatasetProfileEditorDatePickerFieldComponent, DatasetProfileEditorWordListFieldComponent, DatasetProfileEditorDefaultValueComponent, - DialodConfirmationUploadDatasetProfiles, + DialogConfirmationUploadDatasetProfiles, DatasetProfileEditorInternalDmpEntitiesFieldComponent, DatasetProfileEditorResearchersAutoCompleteFieldComponent, DatasetProfileEditorDatasetsAutoCompleteFieldComponent, @@ -81,10 +104,14 @@ import { DatasetProfileEditorValidatorFieldComponent } from './editor/components DatasetProfileEditorOrganizationsFieldComponent, DatasetProfileEditorDatasetIdentifierFieldComponent, DatasetProfileEditorCurrencyFieldComponent, - DatasetProfileEditorValidatorFieldComponent + DatasetProfileEditorValidatorFieldComponent, + DatasetProfileTableOfContents, + DatasetProfileTableOfContentsInternalSection, + DatasetProfileEditorSectionFieldSetComponent, + FinalPreviewComponent ], entryComponents: [ - DialodConfirmationUploadDatasetProfiles + DialogConfirmationUploadDatasetProfiles ] }) export class DatasetProfileModule { } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/animations/animations.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/animations/animations.ts new file mode 100644 index 000000000..c62b30393 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/animations/animations.ts @@ -0,0 +1,64 @@ +import { animate, keyframes, state, style, transition, trigger } from "@angular/animations"; + +export const STEPPER_ANIMATIONS = [ + trigger('previous_btn',[ + transition(':enter',[ + style({'transform': 'translateX(100%)', 'z-index':'9999', 'opacity':0.4}), + animate('600ms ease-out', style({ + 'transform': 'translateX(0)', + 'opacity':1 + })) + ]), + transition(':leave',[ + style({ + 'transform': 'translateX(0)', + 'opacity':'1', + 'z-index':'9999' + }), + animate('800ms ease-out', keyframes([ + style({'transform': 'translateX(120%)', offset:0.8}), + style({'opacity': '0.2', offset:0.96}) + ])) + ]) + ]), + trigger('next_btn', [ + transition(':leave',[ + style({opacity:1, position:'absolute', 'z-index':'9999'}), + animate('700ms ease-out', keyframes( [ + style({ transform:'translateX(-100%)', offset:0.6}), + style({ opacity:'0.2', offset:0.87}) + ])) + ]), + transition(':enter',[ + style({opacity:0.3, 'z-index':'9999', transform:'translateX(-100%)'}), + animate('600ms ease-out', style({ opacity:'1', transform:'translateX(0)' })) + ]) + ]), + trigger('finalize_btn',[ + transition(':enter',[ + style({opacity:0.3}), + animate('400ms ease-in', style({opacity:1})) + ]), + transition(':leave',[ + style({opacity:1, position:'absolute'}), + animate('600ms ease-in', style({opacity:0.3})) + ]) + ]) +]; +export const GENERAL_ANIMATIONS = [ + trigger('enterIn',[ + transition(':enter',[ + style({ + transform:'scale(0)', + 'transform-origin':'50% 0', + opacity:0 + }), + animate('800ms ease', style({transform:'scale(1)', opacity:1})) + ]) + ]), + trigger('fadeElement',[ + state('updated',style({opacity:0})), + transition("*=>updated", + animate('2s 1s ease-out')) + ]) +] \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html index 6de806122..687a3b1ad 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html @@ -1,11 +1,17 @@ -
+ + + + + + + + + + + + + + + + +
+
- - - {{i + 1}}. {{getFieldTile(field, i)}} -
- +
+ + + + + + + + +
+
+
+ + + + +
+ + +
- +
+ + + +
+
+ + + +
+ +
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+ + + +
-
- + + + +
+ + +
+ +
+ +
+ + + + + + + + +
+
+
+ + +
+
+ + + +
+
+ {{'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.PREVIEW' | translate}} + + + Preview updated! + + + ... caculating preview + + +
+
+
+ + +
+
+ +
+ + {{'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.NOT-INITIALIZED' | translate}} + +
+ +
+
+ + + +
+
+
    + + + + +
  • + Add Input icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + + + +
  • + {{'DATASET-PROFILE-EDITOR.ACTIONS.FIELDSET.COMMENT-FIELD' | translate}} +
  • +
  • + + {{'DATASET-PROFILE-EDITOR.ACTIONS.FIELDSET.MULTIPLICITY' | translate}} + +
  • +
  • + + more_vert + + + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.DESCRIPTION' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.EXTENDED-DESCRIPTION' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.ADDITIONAL-INFORMATION' | translate}} + +
  • +
+
+
+
+ +
+ + + + + + + diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.scss index 046126ff9..94cebbcc9 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.scss @@ -8,4 +8,106 @@ .titleStile{ font-weight: bold; -} \ No newline at end of file +} + +//REFACTOR SECTION + + +//Palete + +$blue-color : #129D99; +$blue-color-light: #5cf7f2; + +.actions-list{ + border-radius: 7px; + box-shadow: 0 1px 0.8em $blue-color; + padding: 1em 0em; + font-size: small; +} + +.field-container{ + box-shadow: 0px 1px 2px rgb(173, 173, 173) ; + padding: 3em; + border-radius: .3em; + // border-left: 0.3em solid yellow; + padding-bottom: 2em; + margin-bottom: 2em; + +} +.field-container-active{ + box-shadow: 0px 1px 2px rgb(173, 173, 173) ; + padding: 3em; + border-radius: .3em; + border-left: 0.3em solid $blue-color; + padding-bottom: 2em; + margin-bottom: 2em; + +} +.field-id-container{ + background-color: $blue-color-light; + position: absolute; + right: 0; + top: 0; + padding: .6em 1.2em; + overflow: visible; + .field-id-container-icon{ + position: absolute; + top: -50%; + + } +} + +.main-content-page{ + padding: 0em 1.5em; +} + +.fielset-header{ + font-size: 1.5em; + font-weight: bold; + + // .numbering{ + // padding: 0.5em 0em; + // } +} + +.fieldset-actions-list{ + margin: 0; + cursor: pointer; +} + +// ::ng-deep .main-content-page .fieldset-header .field-title .mat-form-field-infix{ +// border-top: 0px; +// } + + +.numbering-label .mat-input-element:disabled{ + color: #212121; +} + +:host ::ng-deep .fieldset-checkbox-action-dataset-profile-editor +{ + .mat-checkbox-label{ + font-size: 0.8em; + color: #212121; + transform: translateY(3px); + } +} + + +.input_icon{ + width: 14px; + margin-right: 0.5em; + // display: flex; + // align-items: center; +} + +::ng-deep .mat-menu-panel{ + max-height: 32em; +} +:host ::ng-deep .fielset-header .mat-form-field-wrapper{ + padding-bottom: 0px; +} + +// ::ng-deep .underline-line-field .mat-form-field-appearance-legacy .mat-form-field-wapper{ +// padding-bottom: 1.25em !important; +// } \ No newline at end of file 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 e4fd16dfa..6744cd340 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,38 +1,291 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { ChangeDetectorRef, Component, Input, OnChanges, OnInit } from '@angular/core'; +import { AbstractControl, 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'; +import { ValidationType } from '@app/core/common/enum/validation-type'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionFormEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; +import { MatDialog } from '@angular/material'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { TranslateService } from '@ngx-translate/core'; +import { ViewStyleType } from '../field/view-style-enum'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BooleanDecisionFieldDataEditorModel } from '../../../admin/field-data/boolean-decision-field-data-editor-model'; +import { CheckBoxFieldDataEditorModel } from '../../../admin/field-data/check-box-field-data-editor-model'; +import { WordListFieldDataEditorModel } from '../../../admin/field-data/word-list-field-data-editor-model'; +import { AutoCompleteFieldDataEditorModel } from '../../../admin/field-data/auto-complete-field-data-editor-model'; +import { ResearchersAutoCompleteFieldDataEditorModel } from '../../../admin/field-data/researchers-auto-complete-field-data-editor-model'; +import { FreeTextFieldDataEditorModel } from '../../../admin/field-data/free-text-field-data-editor-model'; +import { RadioBoxFieldDataEditorModel } from '../../../admin/field-data/radio-box-field-data-editor-model'; +import { TextAreaFieldDataEditorModel } from '../../../admin/field-data/text-area-field-data-editor-model'; +import { DatePickerDataEditorModel } from '../../../admin/field-data/date-picker-data-editor-models'; +import { ExternalDatasetsDataEditorModel } from '../../../admin/field-data/external-datasets-data-editor-models'; +import { DataRepositoriesDataEditorModel } from '../../../admin/field-data/data-repositories-data-editor-models'; +import { RegistriesDataEditorModel } from '../../../admin/field-data/registries-data-editor-models'; +import { ServicesDataEditorModel } from '../../../admin/field-data/services-data-editor-models'; +import { TagsDataEditorModel } from '../../../admin/field-data/tags-data-editor-models'; +import { DatasetsAutoCompleteFieldDataEditorModel } from '../../../admin/field-data/datasets-autocomplete-field-data-editor-mode'; +import { DatasetIdentifierDataEditorModel } from '../../../admin/field-data/dataset-identifier-data-editor-models'; +import { CurrencyDataEditorModel } from '../../../admin/field-data/currency-data-editor-models'; +import { ValidationDataEditorModel } from '../../../admin/field-data/validation-data-editor-models'; +import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; +import { OrganizationsDataEditorModel } from '../../../admin/field-data/organizations-data-editor-models'; +import { EditorCustomValidators } from '../../custom-validators/editor-custom-validators'; +import { Field, FieldSet } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; +import { DatasetProfileInternalDmpEntitiesType } from '@app/core/common/enum/dataset-profile-internal-dmp-entities-type'; +import { AutoCompleteFieldData, BooleanDecisionFieldData, CheckBoxFieldData, CurrencyFieldData, DataRepositoriesFieldData, DatasetIdentifierFieldData, DatePickerFieldData, DmpsAutoCompleteFieldData, ExternalDatasetsFieldData, FieldDataOption, FreeTextFieldData, OrganizationsFieldData, RadioBoxFieldData, RegistriesFieldData, ResearchersAutoCompleteFieldData, ServicesFieldData, TagsFieldData, TextAreaFieldData, ValidationFieldData, WordListFieldData } from '@app/core/model/dataset-profile-definition/field-data/field-data'; +import { CompositeField } from '@app/core/model/dataset-profile-definition/composite-field'; +import {Field as FieldDefinition} from '@app/core/model/dataset-profile-definition/field'; +import { Subject } from 'rxjs'; +import { debounce, debounceTime } from 'rxjs/operators'; +import { setUncaughtExceptionCaptureCallback } from 'process'; +import { GENERAL_ANIMATIONS } from '../../animations/animations'; @Component({ selector: 'app-dataset-profile-editor-composite-field-component', templateUrl: './dataset-profile-editor-composite-field.component.html', - styleUrls: ['./dataset-profile-editor-composite-field.component.scss'] + styleUrls: ['./dataset-profile-editor-composite-field.component.scss'], + animations:[GENERAL_ANIMATIONS] }) -export class DatasetProfileEditorCompositeFieldComponent implements OnInit { +export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnChanges { @Input() form: FormGroup; @Input() indexPath: string; @Input() viewOnly: boolean; - isComposite = false; - isMultiplicityEnabled = false; + @Input() numbering: string; + @Input() hasFocus: boolean = false; + + showPreview: boolean = true; + previewDirty: boolean = false; + + + showDescription: boolean = true; + showAdditionalInfo: boolean = false; + showExtendedDescription: boolean = false; + + previewForm: FormGroup = null; + // isComposite = false; + // isMultiplicityEnabled = false; + viewStyleEnum = DatasetProfileFieldViewStyle; + + viewTypeEnum = ViewStyleType; + + private myCustomValidators:EditorCustomValidators = new EditorCustomValidators(); + + constructor( + private dialog: MatDialog, + private language: TranslateService, + public enumUtils: EnumUtils, + public datasetProfileService: DatasetProfileService + ) { } + + ngOnChanges(){ + // this.setTargetField(null); + // this.showExtendedDescription = !!this.form.get('extendedDescription').value; + // this.showAdditionalInfo = !!this.form.get('additionalInformation').value; + } + + get firstField(){ + try{ + return (this.form.get('fields') as FormArray).at(0); + }catch{ + return null; + } + } + + get isMultiplicityEnabled(){ + if(!this.form.get('multiplicity')){ + return false; + } + + if (this.form.get('multiplicity').value.min > 0 || this.form.get('multiplicity').value.max > 0) { + return true; + } + + return false; + } - constructor() { } ngOnInit() { //this.addNewField(); - if (this.form.get('multiplicity')) { - if (this.form.get('multiplicity').value.min > 1 || this.form.get('multiplicity').value.max > 1) { - this.isMultiplicityEnabled = true; - } - } - this.isComposite = (this.form.get('fields') as FormArray).length > 1; + // if (this.form.get('multiplicity')) { + // if (this.form.get('multiplicity').value.min > 1 || this.form.get('multiplicity').value.max > 1) { + // this.isMultiplicityEnabled = true; + // } + // } + // this.isComposite = (this.form.get('fields') as FormArray).length > 1; if (this.viewOnly) { this.form.get('hasCommentField').disable(); } + + //SET UP TARGET FIELD + // if((this.form.get('fields') as FormArray).length>0){ + // //get the first field in list + // this.targetField = (this.form.get('fields') as FormArray).at(0) as FormGroup; + // } + + this.showExtendedDescription = !!this.form.get('extendedDescription').value; + this.showAdditionalInfo = !!this.form.get('additionalInformation').value; + + this.form.valueChanges.subscribe(changes=>{ + // this.previewForm = null; + this.previewDirty = true; + this.generatePreviewForm(); + + }); + this.previewSubject$.pipe(debounceTime(600)).subscribe(model=>{ + const updatedForm = model.buildForm(); + this.reloadPreview(updatedForm) + }) + + + this.generatePreviewForm(); } + + get updatedClass(){ + if(this.previewDirty) return ''; + else return 'updated'; + } + private reloadPreview(updatedForm: FormGroup){ + setTimeout(() => { + + const previewContainer = document.getElementById('preview_container'+ this.form.get('id').value); + // let clientHeight = -1; + if(previewContainer){ + // console.log(previewContainer); + const clientHeight = previewContainer.clientHeight; + // console.log(clientHeight); + + if(clientHeight){ + previewContainer.style.height = clientHeight.toString() + 'px'; + + // console.log('height:' ,previewContainer.style.height); + } + } + this.showPreview = false; + this.previewDirty = true; + this.previewForm = updatedForm; + + setTimeout(() => { + + + this.showPreview = true; + this.previewDirty = false; + + if(previewContainer){ + setTimeout(() => { + if(previewContainer){ + previewContainer.style.height = 'auto'; + } + }); + } + }); + }); + } + + previewSubject$: Subject = new Subject(); + + private generatePreviewForm(){ + const formValue:FieldSet = this.form.getRawValue(); + const fields:FieldDefinition[] = formValue.fields.map(editorField=>this._fieldToFieldDefinition(editorField)); + + + const compositeField: CompositeField = { + id: formValue.id, + additionalInformation: formValue.additionalInformation, + extendedDescription: formValue.extendedDescription, + numbering:'', + title: formValue.title, + ordinal: formValue.ordinal, + description: formValue.description, + hasCommentField: formValue.hasCommentField, + commentFieldValue: '', + multiplicity: {max:formValue.multiplicity.max, min : formValue.multiplicity.min}, + multiplicityItems:null, + fields: fields.map(editorField=>{ + const model = new DatasetDescriptionFieldEditorModel().fromModel(editorField); + if(model.viewStyle.renderStyle === this.viewStyleEnum.CheckBox){ + model.value = model.value?"true":"false";//patch + } + return model; + }) + } + + + const section = new DatasetDescriptionSectionEditorModel(); + section.title = ''; + section.numbering = ''; + + const compositeForm = new DatasetDescriptionCompositeFieldEditorModel().fromModel(compositeField) + section.compositeFields = [compositeForm]; + + this.previewSubject$.next(section); + } + + + private _fieldToFieldDefinition(editorField: Field): FieldDefinition{ + const field = { + id: editorField.id, + title: '', + page: editorField.page, + numbering:'', + multiplicity:null, + multiplicityItems: null, + viewStyle: editorField.viewStyle, + defaultValue:editorField.defaultValue, + value: null, + validations: editorField.validations, + } as FieldDefinition; + + field.data = editorField.data; + + // return new DatasetDescriptionFieldEditorModel().fromModel(field); + return field; + } + + + // generatePreview(){ + // const editorModel = new DatasetDescriptionCompositeFieldEditorModel(); + // editorModel.title = this.form.get('title').value; + // editorModel.description = this.form.get('description').value; + // editorModel.extendedDescription = this.form.get('extendedDescription').value; + // editorModel.additionalInformation = this.form.get('additionalInformation').value; + // editorModel.hasCommentField = this.form.get('hasCommentField').value; + // editorModel.fields = []; + + // (this.form.get('fields') as FormArray).controls.forEach(field=>{ + // const fieldEditorModel = new DatasetDescriptionFieldEditorModel(); + + // fieldEditorModel.viewStyle= { + // renderStyle: field.get('viewStyle').get('renderStyle').value, + // cssClass: null + // }; + // fieldEditorModel.defaultValue = field.get('defaultValue').value; + // switch (field.get('viewStyle').get('renderStyle').value) { + // case DatasetProfileFieldViewStyle.TextArea: + // fieldEditorModel.data = { + // label: field.get('data').get('label').value + // }; + // break; + + // default: + // break; + // } + + + // editorModel.fields.push(fieldEditorModel); + // }); + + + // this.previewForm = editorModel.buildForm(); + // } + onIsCompositeChange(isComposite: boolean) { if (!isComposite && (this.form.get('fields')).length > 1) { for (let i = 0; i < (this.form.get('fields')).length - 1; i++) { @@ -46,25 +299,594 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit { } } - onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) { - if (!isMultiplicityEnabled) { - (this.form.get('multiplicity').get('min')).setValue(0); - (this.form.get('multiplicity').get('max')).setValue(0); + onIsMultiplicityEnabledChange(isMultiplicityEnabled: MatCheckboxChange) { + + const multiplicity = this.form.get('multiplicity') as FormGroup; + + const minControl = multiplicity.get('min'); + const maxControl = multiplicity.get('max'); + + if (isMultiplicityEnabled.checked) { + minControl.setValue(0); + maxControl.setValue(1); + }else{ + minControl.setValue(0); + maxControl.setValue(0); } + + minControl.updateValueAndValidity(); + maxControl.updateValueAndValidity(); + } addNewField() { const field: FieldEditorModel = new FieldEditorModel(); field.id=Guid.create().toString(); - (this.form.get('fields')).push(field.buildForm()); + + 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); + fieldForm.updateValueAndValidity(); } DeleteField(index) { - (this.form.get('fields')).removeAt(index); + + const fieldsForm = this.form.get('fields'); + fieldsForm.removeAt(index); + + // calculate ordinals + fieldsForm.controls.forEach((field, idx)=>{ + field.get('ordinal').setValue(idx); + field.updateValueAndValidity(); + }) } 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); } + + + targetField:FormGroup; + validationTypeEnum = ValidationType; + + + addVisibilityRule(targetField: FormGroup){ + const rule: RuleEditorModel = new RuleEditorModel(); + (targetField.get('visible').get('rules')).push(rule.buildForm()); + } + toggleRequired(targetField: FormGroup, event:MatCheckboxChange){ + + let validationsControl = targetField.get('validations') as FormControl; + let validations: Array = validationsControl.value; + + if(event.checked){ + if(!validations.includes(ValidationType.Required)){//IS ALREADY REQUIRED + // validationsControl.setValue(validations.filter(validator=> validator != ValidationType.Required)); + // validationsControl.updateValueAndValidity(); + validations.push(ValidationType.Required); + // validationsControl.setValue(validations); + validationsControl.updateValueAndValidity(); + } + }else{ + validationsControl.setValue(validations.filter(validator=> validator != ValidationType.Required)); + validationsControl.updateValueAndValidity(); + } + + + // if(validations.includes(ValidationType.Required)){//IS ALREADY REQUIRED + // validationsControl.setValue(validations.filter(validator=> validator != ValidationType.Required)); + // validationsControl.updateValueAndValidity(); + // }else{ + // //SET REQUIRED VALIDATOR + // console.log('setting required validator'); + // validations.push(ValidationType.Required); + // validationsControl.setValue(validations); + // validationsControl.updateValueAndValidity(); + // } + } + setTargetField(field:FormGroup){ + this.targetField = field; + } + + + + + + + deleteTargetField(){ + + 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().subscribe(result => { + if (result) { + this._deleteTargetField(); + } + }); + + } + + + private _deleteTargetField(){ + if(!this.targetField) return; + + let index = -1; + + const fields = this.form.get('fields') as FormArray; + + for(let i=0;i< fields.length; i++){ + let field = fields.at(i); + if(field.get('id').value === this.targetField.get('id').value){//index found + index = i; + break; + } + } + + if(index>=0){//target found in fields + this.DeleteField(index); + this.targetField = null; + } + + } + + deleteField(index: number){ + + 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().subscribe(result => { + if (result) { + this.DeleteField(index); + } + }); + + } + + + + + addNewInput(type: ViewStyleType){ + + const fieldsArray = this.form.get('fields') as FormArray; + + let targetOrdinal = fieldsArray.length; + try{ + targetOrdinal = fieldsArray.controls.map(control=> control.get('ordinal').value).reduce((a,b)=>Math.max(a,b)) +1; + }catch{ + + } + + + + const field = { + id: Guid.create().toString(), + ordinal: targetOrdinal, + visible:{rules:[],style:null}, + validations:[], + viewStyle:{} + + } as Field; + + + // const field: FieldEditorModel = new FieldEditorModel(); + // field.id=Guid.create().toString(); + + // 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); + + + + // if (fieldForm.get('data')) { + // fieldForm.removeControl('data'); + // } + + switch (type) { + case this.viewTypeEnum.BooleanDecision:{ + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.BooleanDecision) + // fieldForm.addControl('data', new BooleanDecisionFieldDataEditorModel().buildForm()); + + const data: BooleanDecisionFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.BooleanDecision; + field.data = data; + + break; + } + case this.viewTypeEnum.CheckBox:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.CheckBox) + // fieldForm.addControl('data', new CheckBoxFieldDataEditorModel().buildForm()); + const data: CheckBoxFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.CheckBox; + field.data = data; + + break; + } + case this.viewTypeEnum.Select:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) + // fieldForm.addControl('data', new WordListFieldDataEditorModel().buildForm()); + + // fieldForm.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + // fieldForm.get('data').updateValueAndValidity(); + + const firstOption = {label:'', value:''} as FieldDataOption; + + const data:WordListFieldData = { + label:'', + multiList:false, + options:[firstOption], + type:DatasetProfileComboBoxType.WordList + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ComboBox; + field.data = data; + + break; + } + case this.viewTypeEnum.Other:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) + // fieldForm.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE + + // fieldForm.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList')); + // fieldForm.get('data').updateValueAndValidity(); + + const data: AutoCompleteFieldData = { + autoCompleteSingleDataList:[], + multiAutoComplete: false, + label:'', + type: DatasetProfileComboBoxType.Autocomplete + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ComboBox; + field.data = data; + + break; + }case this.viewTypeEnum.InternalDmpEntities:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.InternalDmpEntities) + // fieldForm.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm());//TODO TO SEE + + const data: DmpsAutoCompleteFieldData = { + label:'', + multiAutoComplete: false, + type: DatasetProfileInternalDmpEntitiesType.Dmps + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.InternalDmpEntities; + field.data = data; + + break; + } + case this.viewTypeEnum.FreeText:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.FreeText) + // fieldForm.addControl('data', new FreeTextFieldDataEditorModel().buildForm()); + + const data: FreeTextFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.FreeText; + field.data = data; + break; + } + case this.viewTypeEnum.RadioBox:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox) + // fieldForm.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); + // fieldForm.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + // fieldForm.get('data').updateValueAndValidity(); + const data: RadioBoxFieldData= { + label:'', + options: [] + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.RadioBox; + field.data = data; + + break; + } + case this.viewTypeEnum.TextArea:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.TextArea) + // fieldForm.addControl('data', new TextAreaFieldDataEditorModel().buildForm()); + + const data: TextAreaFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.TextArea; + field.data = data; + + break; + } + case this.viewTypeEnum.DatePicker:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DatePicker) + // fieldForm.addControl('data', new DatePickerDataEditorModel().buildForm()); + const data: DatePickerFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DatePicker; + + break; + } + case this.viewTypeEnum.ExternalDatasets:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ExternalDatasets) + // fieldForm.addControl('data', new ExternalDatasetsDataEditorModel().buildForm()); + const data: ExternalDatasetsFieldData = { + label:'', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ExternalDatasets; + field.data = data; + break; + } + case this.viewTypeEnum.DataRepositories:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DataRepositories) + // fieldForm.addControl('data', new DataRepositoriesDataEditorModel().buildForm()); + + const data: DataRepositoriesFieldData = { + label: '', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DataRepositories; + field.data = data; + + break; + } + case this.viewTypeEnum.Registries:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Registries) + // fieldForm.addControl('data', new RegistriesDataEditorModel().buildForm()); + + const data:RegistriesFieldData = { + label: '', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Registries; + field.data = data; + + break; + } + case this.viewTypeEnum.Services:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Services) + // fieldForm.addControl('data', new ServicesDataEditorModel().buildForm()); + + const data:ServicesFieldData = { + label:'', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Services; + field.data = data; + + break; + } + case this.viewTypeEnum.Tags:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Tags) + // fieldForm.addControl('data', new TagsDataEditorModel().buildForm()); + + const data: TagsFieldData = { + label:'' + } + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Tags; + field.data = data; + + break; + } + case this.viewTypeEnum.Researchers:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Researchers) + // this.form.addControl('data', new ResearchersDataEditorModel().buildForm()); //TODO TO ASK + // fieldForm.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm()); + + // field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Researchers; + const data : ResearchersAutoCompleteFieldData = { + label:'', + multiAutoComplete: false, + type: DatasetProfileInternalDmpEntitiesType.Researchers + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.InternalDmpEntities; + field.data = data; + + break; + } + case this.viewTypeEnum.Organizations:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Organizations) + // fieldForm.addControl('data', new OrganizationsDataEditorModel().buildForm()); + // this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()) + // fieldForm.addControl('data', new DatasetsAutoCompleteFieldDataEditorModel().buildForm()); //TODO + + const data = { + autoCompleteSingleDataList:[], + label:'', + multiAutoComplete: false, + + } as OrganizationsFieldData; //TODO + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Organizations; + field.data = data; + + break; + } + case this.viewTypeEnum.DatasetIdentifier:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DatasetIdentifier) + // fieldForm.addControl('data', new DatasetIdentifierDataEditorModel().buildForm()); + + const data : DatasetIdentifierFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DatasetIdentifier; + field.data = data; + + break; + } + case this.viewTypeEnum.Currency:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Currency) + // fieldForm.addControl('data', new CurrencyDataEditorModel().buildForm()); + + const data: CurrencyFieldData = { + label:'' + } + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Currency; + field.data = data; + + break; + } + case this.viewTypeEnum.Validation:{ + + + // fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Validation) + // fieldForm.addControl('data', new ValidationDataEditorModel().buildForm()); + + const data:ValidationFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Validation; + field.data = data; + + break; + } + } + + (this.form.get('fields')).push(new FieldEditorModel().fromModel(field).buildForm()); + // fieldForm.get('viewStyle').get('renderStyle').updateValueAndValidity(); + // fieldForm.get('data').updateValueAndValidity(); + + + } + + // 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} + // } + // } + // } + + + // private _atLeastOneElementListValidator(arrayToCheck): ValidatorFn{ + // return (control: AbstractControl): ValidationErrors | null=>{ + + // const fa = control.get(arrayToCheck) as FormArray; + + // if(fa.length === 0){ + // return {emptyArray: true}; + // } + // return null; + // } + // } + + + calculateLabelWidth(numbering: string){ + + const width = numbering.split('.').reduce((acc,item)=> item+acc,'').length; + + + return {'width':width+'em'} + } } + + diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.html index b9c42bc35..31648ff9a 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.html @@ -1,7 +1,8 @@
- + {{placeHolder}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.NONE' | translate}} {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.BOOLEAN-DECISION.YES' @@ -16,7 +17,8 @@ - + {{placeHolder}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.CHECK-BOX.CHECKED' | translate}} {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.CHECK-BOX.UNCHECKED' | translate}} @@ -24,11 +26,13 @@ - + - + {{placeHolder}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.NONE' | translate }} {{opt.get('label').value}} @@ -36,25 +40,30 @@ - + - + {{placeHolder}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{placeHolder}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.NONE' | translate}} {{opt.get('label').value}} @@ -63,14 +72,16 @@ - + {{placeHolder}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{placeHolder}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.ts index aedb1fa72..a62bc0cb4 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-profile-editor-default-value/component-profile-editor-default-value.component.ts @@ -17,7 +17,7 @@ export class DatasetProfileEditorDefaultValueComponent implements OnInit { @Input() comboBoxType: DatasetProfileComboBoxType; @Input() internalDmpEntitiesType: DatasetProfileInternalDmpEntitiesType; @Input() placeHolder: String; - @Input() required: Boolean; + // @Input() required: Boolean; comboBoxTypeEnum = DatasetProfileComboBoxType; internalDmpEntitiesTypeEnum = DatasetProfileInternalDmpEntitiesType; diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component.html index 0b7c98d87..6037dbc05 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/auto-complete/dataset-profile-editor-auto-complete-field.component.html @@ -6,14 +6,36 @@ - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-PLACEHOLDER' | translate}} + -
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE-TITLE' | translate}}
- + +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE-TITLE' | translate}}
+
+ + + +
+ warning_amber + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.ERROR-MESSAGES.FIELD-OTHER-SOURCES-REQUIRED'| translate}} +
+
- +
+
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-TYPE' | translate}} @@ -24,20 +46,29 @@ - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-URL' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-OPTIONS-ROOT' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-LABEL' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-VALUE' | translate}} + - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component.html index 66105b839..e1f96a2e1 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/boolean-decision/dataset-profile-editor-boolean-decision-field.component.html @@ -1,8 +1,9 @@ -
+ diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component.html index cb2d82d7f..56ae77ff2 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/checkbox/dataset-profile-editor-checkbox-field.component.html @@ -3,6 +3,7 @@
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-TITLE' | translate}}
- + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}} +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.html index 014c776f1..9f4e545ab 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.html @@ -1,10 +1,10 @@
- +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts index 86cc30d8d..862cb61f9 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/combo-box/dataset-profile-editor-combo-box-field.component.ts @@ -22,7 +22,7 @@ export class DatasetProfileEditorComboBoxFieldComponent extends BaseComponent im ) { super(); } ngOnInit() { - this.setupListeners(); + // this.setupListeners(); } setupListeners() { diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/currency/dataset-profile-editor-currency-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/currency/dataset-profile-editor-currency-field.component.html index aeb72f4ed..da6e65ae7 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/currency/dataset-profile-editor-currency-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/currency/dataset-profile-editor-currency-field.component.html @@ -1,9 +1,9 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CURRENCY-TITLE' | translate}}
+ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CURRENCY-PLACEHOLDER' | translate}}
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/data-repositories/dataset-profile-editor-data-repositories-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/data-repositories/dataset-profile-editor-data-repositories-field.component.html index 95cf28e76..641c26ce1 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/data-repositories/dataset-profile-editor-data-repositories-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/data-repositories/dataset-profile-editor-data-repositories-field.component.html @@ -1,12 +1,12 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATA-REPOSITORIES-TITLE' | translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATA-REPOSITORIES-PLACEHOLDER' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component.html index aeb72f4ed..263601838 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dataset-identifier/dataset-profile-editor-dataset-identifier-field.component.html @@ -1,9 +1,9 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATASET-IDENTIFIER-TITLE' | translate}}
+ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATASET-IDENTIFIER-PLACEHOLDER' | translate}}
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component.html index 85de8192e..e7c6d01dc 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datasets-auto-complete/dataset-profile-editor-datasets-autocomplete-field.component.html @@ -6,7 +6,8 @@ - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATASETS-PLACEHOLDER' | translate}} +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component.html index aeb72f4ed..bf505dbea 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/datepicker/dataset-profile-editor-date-picker-field.component.html @@ -2,8 +2,8 @@
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' | translate}}
+ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-CHECKBOX-PLACEHOLDER' | translate}}
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component.html index 70d5106e7..2109b436b 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/dmps-auto-complete/dataset-profile-editor-dmps-autocomplete-field.component.html @@ -6,7 +6,8 @@ - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DMPS-PLACEHOLDER' | translate}} +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component.html index 96016ab7c..a5c074147 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/external-datasets/dataset-profile-editor-external-datasets-field.component.html @@ -1,13 +1,13 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-EXTERNAL-DATASETS-TITLE' | translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-EXTERNAL-DATASETS-PLACEHOLDER' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component.html index 9509b5a57..cc1248c46 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/free-text/dataset-profile-editor-free-text-field.component.html @@ -4,8 +4,8 @@ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-FREE-TEXT-TITLE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-FREE-TEXT-PLACEHOLDER' | translate}} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component.html index 96016ab7c..303388518 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/organizations/dataset-profile-editor-organizations-field.component.html @@ -1,13 +1,13 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-ORGANIZATIONS-TITLE' | translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-ORGANIZATIONS-PLACEHOLDER' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component.html index 612a43bc4..944b3e3a9 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/radio-box/dataset-profile-editor-radio-box-field.component.html @@ -1,24 +1,29 @@
+
+
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RADIO-BOX-TITLE' + | translate}}
+ + warning_amber + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.ERROR-MESSAGES.FIELD-RADIO-AT-LEAST-ONE-REQUIRED'| translate}} + +
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RADIO-BOX-TITLE' - | translate}}
- - +
+ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RADIO-BOX-LABEL' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RADIO-BOX-VALUE' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component.html index 7de5c855f..94260ad5a 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers-auto-complete/dataset-profile-editor-researchers-auto-complete-field.component.html @@ -6,7 +6,8 @@ - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RESEARCHERS-PLACEHOLDER' | translate}} +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component.html index 95cf28e76..bc1c84e39 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/researchers/dataset-profile-editor-researchers-field.component.html @@ -1,12 +1,12 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RESEARCHERS-TITLE' | translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-RESEARCHERS-PLACEHOLDER' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/services/dataset-profile-editor-services-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/services/dataset-profile-editor-services-field.component.html index 95cf28e76..9f0991328 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/services/dataset-profile-editor-services-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/services/dataset-profile-editor-services-field.component.html @@ -1,12 +1,12 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-SERVICES-TITLE' | translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-AUTOCOMPLETE' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-SERVICES-PLACEHOLDER' | translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/tags/dataset-profile-editor-tags-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/tags/dataset-profile-editor-tags-field.component.html index aeb72f4ed..bab2b500f 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/tags/dataset-profile-editor-tags-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/tags/dataset-profile-editor-tags-field.component.html @@ -1,9 +1,9 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-TAGS-TITLE' | translate}}
+ {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-TAGS-PLACEHOLDER' | translate}}
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component.html index bb2b107c7..f3fe6ee4a 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/textarea/dataset-profile-editor-text-area-field.component.html @@ -4,7 +4,10 @@ | translate}} - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-TEXT-AREA-PLACEHOLDER' | translate}} + +
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/validator/dataset-profile-editor-validator-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/validator/dataset-profile-editor-validator-field.component.html index 78920fe77..8b28d4c4e 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/validator/dataset-profile-editor-validator-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/validator/dataset-profile-editor-validator-field.component.html @@ -1,9 +1,9 @@
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-DATE-PICKER-TITLE' +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-VALIDATOR-TITLE' | translate}}
- + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-VALIDATOR-PLACEHOLDER' | translate}} +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component.html index 493b890b6..12d82cae4 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field-type/word-list/dataset-profile-editor-word-list-field.component.html @@ -1,28 +1,33 @@
+
-
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-WORD-LIST-TITLE' - | translate}}
+
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-WORD-LIST-TITLE' + | translate}}
+ + + warning_amber + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.ERROR-MESSAGES.FIELD-SELECT-AT-LEAST-ONE-REQUIRED' |translate}} + +
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-MULTIPLE-WORDLIST' | translate}} + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-WORD-LIST-PLACEHOLDER' | translate}}
- + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-WORD-LIST-LABEL' | translate}} + - + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-WORD-LIST-VALUE' | translate}} + + +
+
+
    +
  • + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
  • +
  • + visibility +
  • +
  • + delete +
  • + +
+
-
+ + +
+ + + + + + + + + TextArea icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.TextArea)}} + + + FreeText icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.FreeText)}} + + + + Boolean icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.BooleanDecision)}} + + + RadioBox icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.RadioBox)}} + + + + Select icon + + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Select)}} + + + CheckBox icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.CheckBox)}} + + + + + + DatePicker icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.DatePicker)}} + + + Current icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Currency)}} + + + + + + + + Registries icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Registries)}} + + + Services icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Services)}} + + + Researchers icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Researchers)}} + + + Organizations icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Organizations)}} + + + ExternalDatasets icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.ExternalDatasets)}} + + + DataRepositories icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.DataRepositories)}} + + + Other icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Other)}} + + + + + + + InternalDmpEntities icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.InternalDmpEntities)}} + + + Tags icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Tags)}} + + + DatasetIdentifier icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.DatasetIdentifier)}} + + + Validation icon + {{enumUtils.toDatasetProfileViewTypeString(viewTypeEnum.Validation)}} + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + + + + + + + + + + + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.RDA-COMMON-STANDARDS' | translate}} + + -- + + {{property}} + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + +

{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.RULES-TITLE' | translate}} +

+ + +
+ + + +
+ + + + + + + + + diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.scss index 3db0dee74..1c94581a8 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/dataset-profile-editor-field.component.scss @@ -1,3 +1,38 @@ .full-width { width: 100%; } + + +.preview-box{ + padding: 1em; + border: 1px solid #e8dcdc; + border-radius: 0.3em; +} + +mat-radio-button{ + padding-right: 1em; +} + +li.list-inline-item{ + color: #129D99; + .mat-icon{ + vertical-align: bottom; + } +} + +:host ::ng-deep .field-toggler +{ + .mat-slide-toggle-content{ + font-size: 0.8em; + color: #212121; + } + .mat-slide-toggle.mat-checked .mat-slide-toggle-thumb { + background-color:#129D99 ; + } +} + + +.input_icon{ + width: 14px; + margin-right: 0.5em; +} \ 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 d96993846..751c0af04 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, Input, OnInit } from '@angular/core'; -import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup, FormGroupDirective, NgForm, ValidationErrors, ValidatorFn } 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'; @@ -15,7 +15,7 @@ import { TextAreaFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admi import { WordListFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/word-list-field-data-editor-model'; import { RuleEditorModel } from '@app/ui/admin/dataset-profile/admin/rule-editor-model'; import { BaseComponent } from '@common/base/base.component'; -import { takeUntil } from 'rxjs/operators'; +import { debounce, debounceTime, takeUntil } from 'rxjs/operators'; import { ExternalDatasetEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { DataRepositoriesDataEditorModel } from '../../../admin/field-data/data-repositories-data-editor-models'; import { RegistriesDataEditorModel } from '../../../admin/field-data/registries-data-editor-models'; @@ -27,139 +27,810 @@ import { DatasetIdentifierDataEditorModel } from '../../../admin/field-data/data import { ExternalDatasetsDataEditorModel } from '../../../admin/field-data/external-datasets-data-editor-models'; import { CurrencyDataEditorModel } from '../../../admin/field-data/currency-data-editor-models'; import { ValidationDataEditorModel } from '../../../admin/field-data/validation-data-editor-models'; +import { DatasetDescriptionFieldEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; +import { Subject, Subscription } from 'rxjs'; +import { ViewStyleType } from './view-style-enum'; +import { AutoCompleteFieldDataEditorModel } from '../../../admin/field-data/auto-complete-field-data-editor-model'; +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 { ErrorStateMatcher, MatSlideToggleChange } from '@angular/material'; +import { DefaultValueEditorModel } from '../../../admin/default-value-editor-model'; +import { EditorCustomValidators } from '../../custom-validators/editor-custom-validators'; +import { Field } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { DatasetProfileInternalDmpEntitiesType } from '@app/core/common/enum/dataset-profile-internal-dmp-entities-type'; +import { FieldEditorModel } from '../../../admin/field-editor-model'; +import { AutoCompleteFieldData, BooleanDecisionFieldData, CheckBoxFieldData, CurrencyFieldData, DataRepositoriesFieldData, DatasetIdentifierFieldData, DatePickerFieldData, DmpsAutoCompleteFieldData, ExternalDatasetsFieldData, FieldDataOption, FreeTextFieldData, OrganizationsFieldData, RadioBoxFieldData, RegistriesFieldData, ResearchersAutoCompleteFieldData, ServicesFieldData, TagsFieldData, TextAreaFieldData, ValidationFieldData, WordListFieldData } from '@app/core/model/dataset-profile-definition/field-data/field-data'; @Component({ selector: 'app-dataset-profile-editor-field-component', templateUrl: './dataset-profile-editor-field.component.html', styleUrls: ['./dataset-profile-editor-field.component.scss'] }) -export class DatasetProfileEditorFieldComponent extends BaseComponent implements OnInit { +export class DatasetProfileEditorFieldComponent extends BaseComponent implements OnInit, ErrorStateMatcher { @Input() viewOnly: boolean; @Input() form: FormGroup; @Input() showOrdinal = true; @Input() indexPath: string; validationTypeEnum = ValidationType; viewStyleEnum = DatasetProfileFieldViewStyle; - isFieldMultiplicityEnabled = false; + // isFieldMultiplicityEnabled = false; + viewType: ViewStyleType; + viewTypeEnum = ViewStyleType; + // private subject$:Subject = new Subject(); + + + + @Input() expandView: boolean = true; + @Input() canBeDeleted:boolean = true; + + @Output() delete = new EventEmitter(); constructor( public enumUtils: EnumUtils, public datasetProfileService: DatasetProfileService - ) { super(); } + ) { super(); + + } + + + isErrorState(control: FormControl, form: FormGroupDirective | NgForm): boolean { + + if(this.form.get('viewStyle').untouched) return false; + + return this.form.get('viewStyle').invalid; + } ngOnInit() { - if (this.form.get('multiplicity')) { - if (this.form.get('multiplicity').value.min > 1 && this.form.get('multiplicity').value.max > 1) { - this.isFieldMultiplicityEnabled = true; + + // this.subject$.pipe(takeUntil(this._destroyed)).pipe(debounceTime(600)).subscribe(model=>{ + // this.previewForm = model.buildForm(); + // }); + + + + + // if (this.form.get('multiplicity')) { + // if (this.form.get('multiplicity').value.min > 1 && this.form.get('multiplicity').value.max > 1) { + // this.isFieldMultiplicityEnabled = true; + // } + // } + + if(this.form.get('viewStyle').get('renderStyle').value){ + + // this.matcher.setReference(this.form); + const type = this.form.get('viewStyle').get('renderStyle').value; + + switch(type){ + case DatasetProfileFieldViewStyle.BooleanDecision: + this.viewType = this.viewTypeEnum.BooleanDecision; + break; + case DatasetProfileFieldViewStyle.CheckBox: + this.viewType = this.viewTypeEnum.CheckBox; + break; + case DatasetProfileFieldViewStyle.ComboBox: + + const comboType = this.form.get('data').get('type').value; + if(comboType === DatasetProfileComboBoxType.Autocomplete){ + this.viewType = this.viewTypeEnum.Other; + }else if(comboType === DatasetProfileComboBoxType.WordList){ + this.viewType = this.viewTypeEnum.Select; + } + break; + case DatasetProfileFieldViewStyle.InternalDmpEntities: + this.viewType = this.viewTypeEnum.InternalDmpEntities; + break; + case DatasetProfileFieldViewStyle.FreeText: + this.viewType = this.viewTypeEnum.FreeText; + break; + case DatasetProfileFieldViewStyle.RadioBox: + this.viewType = this.viewTypeEnum.RadioBox; + break; + case DatasetProfileFieldViewStyle.TextArea: + this.viewType = this.viewTypeEnum.TextArea; + break; + case DatasetProfileFieldViewStyle.DatePicker: + this.viewType = this.viewTypeEnum.DatePicker; + break; + case DatasetProfileFieldViewStyle.ExternalDatasets: + this.viewType = this.viewTypeEnum.ExternalDatasets; + break; + case DatasetProfileFieldViewStyle.DataRepositories: + this.viewType = this.viewTypeEnum.DataRepositories; + break; + case DatasetProfileFieldViewStyle.Registries: + this.viewType = this.viewTypeEnum.Registries; + break; + case DatasetProfileFieldViewStyle.Services: + this.viewType = this.viewTypeEnum.Services; + break; + case DatasetProfileFieldViewStyle.Tags: + this.viewType = this.viewTypeEnum.Tags; + break; + case DatasetProfileFieldViewStyle.Researchers: + this.viewType = this.viewTypeEnum.Researchers; //TODO RESEARCHERS + break; + case DatasetProfileFieldViewStyle.Organizations: + this.viewType = this.viewTypeEnum.Organizations; + break; + case DatasetProfileFieldViewStyle.DatasetIdentifier: + this.viewType = this.viewTypeEnum.DatasetIdentifier; + break; + case DatasetProfileFieldViewStyle.Currency: + this.viewType = this.viewTypeEnum.Currency; + break; + case DatasetProfileFieldViewStyle.Validation: + this.viewType = this.viewTypeEnum.Validation; + break; } + } + + // this.showPreview = true; + + + + // this.addNewRule(); - this.form.get('viewStyle').get('renderStyle').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - if (this.form.get('data')) { - this.form.removeControl('data'); + // this.form.get('viewStyle').get('renderStyle').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { - switch (x) { - case DatasetProfileFieldViewStyle.BooleanDecision: - this.form.addControl('data', new BooleanDecisionFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.CheckBox: - this.form.addControl('data', new CheckBoxFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.ComboBox: - this.form.addControl('data', new WordListFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.InternalDmpEntities: - this.form.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.FreeText: - this.form.addControl('data', new FreeTextFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.RadioBox: - this.form.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.TextArea: - this.form.addControl('data', new TextAreaFieldDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.DatePicker: - this.form.addControl('data', new DatePickerDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.ExternalDatasets: - this.form.addControl('data', new ExternalDatasetsDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.DataRepositories: - this.form.addControl('data', new DataRepositoriesDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Registries: - this.form.addControl('data', new RegistriesDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Services: - this.form.addControl('data', new ServicesDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Tags: - this.form.addControl('data', new TagsDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Researchers: - this.form.addControl('data', new ResearchersDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Organizations: - this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.DatasetIdentifier: - this.form.addControl('data', new DatasetIdentifierDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Currency: - this.form.addControl('data', new CurrencyDataEditorModel().buildForm()); - break; - case DatasetProfileFieldViewStyle.Validation: - this.form.addControl('data', new ValidationDataEditorModel().buildForm()); - break; - } - } - }); + + // // const previewStatus = this.showPreview; + // //!! Important to be before the if statement + // this.showPreview = false; + + // if (this.form.get('data')) { + // this.form.removeControl('data'); + + // switch (x) { + // case DatasetProfileFieldViewStyle.BooleanDecision: + // this.form.addControl('data', new BooleanDecisionFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.CheckBox: + // this.form.addControl('data', new CheckBoxFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.ComboBox: + // this.form.addControl('data', new WordListFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.InternalDmpEntities: + // this.form.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.FreeText: + // this.form.addControl('data', new FreeTextFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.RadioBox: + // this.form.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.TextArea: + // this.form.addControl('data', new TextAreaFieldDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.DatePicker: + // this.form.addControl('data', new DatePickerDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.ExternalDatasets: + // this.form.addControl('data', new ExternalDatasetsDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.DataRepositories: + // this.form.addControl('data', new DataRepositoriesDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Registries: + // this.form.addControl('data', new RegistriesDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Services: + // this.form.addControl('data', new ServicesDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Tags: + // this.form.addControl('data', new TagsDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Researchers: + // this.form.addControl('data', new ResearchersDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Organizations: + // this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.DatasetIdentifier: + // this.form.addControl('data', new DatasetIdentifierDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Currency: + // this.form.addControl('data', new CurrencyDataEditorModel().buildForm()); + // break; + // case DatasetProfileFieldViewStyle.Validation: + // this.form.addControl('data', new ValidationDataEditorModel().buildForm()); + // break; + // } + // } + + + // //reset the preview status + // // this.showPreview = previewStatus; + // this.showPreview = true; + // }); } - defaulValueRequired(viewStile: DatasetProfileFieldViewStyle): boolean { - switch (viewStile) { - case DatasetProfileFieldViewStyle.CheckBox: - return true; - case DatasetProfileFieldViewStyle.RadioBox: - case DatasetProfileFieldViewStyle.TextArea: - case DatasetProfileFieldViewStyle.FreeText: - case DatasetProfileFieldViewStyle.ComboBox: - case DatasetProfileFieldViewStyle.InternalDmpEntities: - case DatasetProfileFieldViewStyle.BooleanDecision: - case DatasetProfileFieldViewStyle.DatePicker: - case DatasetProfileFieldViewStyle.ExternalDatasets: - case DatasetProfileFieldViewStyle.DataRepositories: - case DatasetProfileFieldViewStyle.Registries: - case DatasetProfileFieldViewStyle.Services: - case DatasetProfileFieldViewStyle.Tags: - case DatasetProfileFieldViewStyle.Registries: - case DatasetProfileFieldViewStyle.Organizations: - case DatasetProfileFieldViewStyle.DatasetIdentifier: - case DatasetProfileFieldViewStyle.Currency: - case DatasetProfileFieldViewStyle.Validation: - return false; - default: - return false; - } - } + // defaulValueRequired(viewStile: DatasetProfileFieldViewStyle): boolean { + // switch (viewStile) { + // case DatasetProfileFieldViewStyle.CheckBox: + // return true; + // case DatasetProfileFieldViewStyle.RadioBox: + // case DatasetProfileFieldViewStyle.TextArea: + // case DatasetProfileFieldViewStyle.FreeText: + // case DatasetProfileFieldViewStyle.ComboBox: + // case DatasetProfileFieldViewStyle.InternalDmpEntities: + // case DatasetProfileFieldViewStyle.BooleanDecision: + // case DatasetProfileFieldViewStyle.DatePicker: + // case DatasetProfileFieldViewStyle.ExternalDatasets: + // case DatasetProfileFieldViewStyle.DataRepositories: + // case DatasetProfileFieldViewStyle.Registries: + // case DatasetProfileFieldViewStyle.Services: + // case DatasetProfileFieldViewStyle.Tags: + // case DatasetProfileFieldViewStyle.Registries: + // case DatasetProfileFieldViewStyle.Organizations: + // case DatasetProfileFieldViewStyle.DatasetIdentifier: + // case DatasetProfileFieldViewStyle.Currency: + // case DatasetProfileFieldViewStyle.Validation: + // return false; + // default: + // return false; + // } + // } - onIsFieldMultiplicityEnabledChange(isFieldMultiplicityEnabled: boolean) { - if (!isFieldMultiplicityEnabled) { - (this.form.get('multiplicity').get('min')).setValue(0); - (this.form.get('multiplicity').get('max')).setValue(0); - } - } + // onIsFieldMultiplicityEnabledChange(isFieldMultiplicityEnabled: boolean) { + // if (!isFieldMultiplicityEnabled) { + // (this.form.get('multiplicity').get('min')).setValue(0); + // (this.form.get('multiplicity').get('max')).setValue(0); + // } + // } addNewRule() { const rule: RuleEditorModel = new RuleEditorModel(); (this.form.get('visible').get('rules')).push(rule.buildForm()); } -} + + + private _formChangesSubscription:Subscription; + private _showPreview: boolean = false;; + + // get showPreview(): boolean{ + + // return this._showPreview; + // } + + // set showPreview(value:boolean){ + // if(value == false){//hide preview + // //close subsciption + // if(this._formChangesSubscription){ + // this._formChangesSubscription.unsubscribe(); + // this._formChangesSubscription = null; + // } + // } + + // if(value == true){ + // //value is already true + // if(this._showPreview){ + // if(this._formChangesSubscription){ + // this._formChangesSubscription.unsubscribe(); + // this._formChangesSubscription = null; + // } + // } + + // //initialize + // if(this.form.get('viewStyle').get('renderStyle').value){ + // this._generatePreviewForm(); + // } + // this._formChangesSubscription = this.form.valueChanges.subscribe(()=>{ + // this._generatePreviewForm(); + // }); + // } + // this._showPreview = value; + + // } + + // previewForm: FormGroup; + + // private _generatePreviewForm(){ + + // if(!this.form.get('data')){ + // return; + // } + // this.previewForm = null; + // const fieldEditorModel = new DatasetDescriptionFieldEditorModel(); + + // fieldEditorModel.viewStyle= { + // renderStyle: this.form.get('viewStyle').get('renderStyle').value, + // cssClass: null + // }; + + // fieldEditorModel.data = (this.form.get('data') as FormGroup).getRawValue(); + // fieldEditorModel.value = this.form.get('defaultValue').get('value').value; + // fieldEditorModel.validationRequired = (this.form.get('validations').value as Array).includes(ValidationType.Required); + + // if(this.form.get('viewStyle').get('renderStyle').value == DatasetProfileFieldViewStyle.CheckBox){ + // fieldEditorModel.value = this.form.get('defaultValue').get('value').value === 'true'; + // } + // // if(this.form.get('viewStyle').get('renderStyle').value == DatasetProfileFieldViewStyle.Researchers){ + // // fieldEditorModel.data = new ResearchersAutoCompleteFieldDataEditorModel().buildForm().getRawValue(); + // // } + // if(fieldEditorModel.viewStyle.renderStyle === DatasetProfileFieldViewStyle.Validation || (fieldEditorModel.viewStyle.renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) + // || (fieldEditorModel.viewStyle.renderStyle === DatasetProfileFieldViewStyle.Tags) + // ){ + // fieldEditorModel.value = null; + // } + + // // const myTicket = Guid.create().toString(); + // // this.validTicket = myTicket; + // // setTimeout(() => { //TODO + // // //user hasnt make any new change to inputs /show preview + // // if(myTicket === this.validTicket){ + // // this.previewForm = fieldEditorModel.buildForm(); + // // } + // // }, 600); + + // this.subject$.next(fieldEditorModel); + + + // // setTimeout(() => { + // // this.previewForm = fieldEditorModel.buildForm(); + // // }); + // }; + + get canApplyVisibility():boolean{ + + + switch(this.viewType){ + case this.viewTypeEnum.TextArea: + case this.viewTypeEnum.FreeText: + case this.viewTypeEnum.BooleanDecision: + case this.viewTypeEnum.RadioBox: + case this.viewTypeEnum.Select: + case this.viewTypeEnum.CheckBox: + case this.viewTypeEnum.DatePicker: + return true; + + } + + + return false; + + } + + // validTicket:string; + // generatePreview(){ + // const fieldEditorModel = new DatasetDescriptionFieldEditorModel(); + + // fieldEditorModel.viewStyle= { + // renderStyle: this.form.get('viewStyle').get('renderStyle').value, + // cssClass: null + // }; + // fieldEditorModel.defaultValue = this.form.get('defaultValue').value; + // switch (this.form.get('viewStyle').get('renderStyle').value) { + // case DatasetProfileFieldViewStyle.TextArea: + // fieldEditorModel.data = { + // label: this.form.get('data').get('label').value + // }; + // break; + + // default: + // break; + // } + + // // this.previewForm = fieldEditorModel.buildForm(); + + + // } + onInputTypeChange(){ + + + const x = this.viewType; + + // this.showPreview = false; + + + + const field: Field = this.form.getRawValue(); + // field.defaultValue = {type:null, value: null}; + field.defaultValue = undefined; + if(!this.canApplyVisibility){ + field.visible.rules = []; + } + + + + // if (this.form.get('data')) { + // this.form.removeControl('data'); + // } + + // this.form.removeControl('defaultValue'); + // const defaultValueModel = new DefaultValueEditorModel(); + // this.form.addControl('defaultValue',defaultValueModel.buildForm()); + + switch (x) { + case this.viewTypeEnum.BooleanDecision:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.BooleanDecision) + // this.form.addControl('data', new BooleanDecisionFieldDataEditorModel().buildForm()); + + const data: BooleanDecisionFieldData = { + label:"" + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.BooleanDecision; + field.data = data; + + break; + } + case this.viewTypeEnum.CheckBox:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.CheckBox) + // this.form.addControl('data', new CheckBoxFieldDataEditorModel().buildForm()); + + const data: CheckBoxFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.CheckBox; + field.data = data; + + break; + } + case this.viewTypeEnum.Select:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) + // this.form.addControl('data', new WordListFieldDataEditorModel().buildForm()); + + // this.form.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + // this.form.get('data').updateValueAndValidity(); + const option1 = {label:'', value:''} as FieldDataOption; + + const data:WordListFieldData = { + label:'', + multiList:false, + options:[option1], + type:DatasetProfileComboBoxType.WordList + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ComboBox; + field.data = data; + + break; + } + case this.viewTypeEnum.Other:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) + // this.form.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE + + // this.form.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList')); + // this.form.get('data').updateValueAndValidity(); + + const data: AutoCompleteFieldData = { + autoCompleteSingleDataList:[], + multiAutoComplete: false, + label:'', + type: DatasetProfileComboBoxType.Autocomplete + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ComboBox; + field.data = data; + + break; + } + case this.viewTypeEnum.InternalDmpEntities:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.InternalDmpEntities) + // this.form.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm());//TODO TO SEE + + const data: DmpsAutoCompleteFieldData = { + label:'', + multiAutoComplete: false, + type: DatasetProfileInternalDmpEntitiesType.Dmps + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.InternalDmpEntities; + field.data = data; + + break; + } + case this.viewTypeEnum.FreeText:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.FreeText) + // this.form.addControl('data', new FreeTextFieldDataEditorModel().buildForm()); + + const data: FreeTextFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.FreeText; + field.data = data; + + break; + } + case this.viewTypeEnum.RadioBox:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox) + // this.form.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); + + // this.form.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + // this.form.get('data').updateValueAndValidity(); + + const data: RadioBoxFieldData= { + label:'', + options: [] + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.RadioBox; + field.data = data; + + break; + } + case this.viewTypeEnum.TextArea:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.TextArea) + // this.form.addControl('data', new TextAreaFieldDataEditorModel().buildForm()); + + const data: TextAreaFieldData = { + label:'' + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.TextArea; + field.data = data; + break; + } + case this.viewTypeEnum.DatePicker:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DatePicker) + // this.form.addControl('data', new DatePickerDataEditorModel().buildForm()); + + const data: DatePickerFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DatePicker; + field.data = data; + + break; + } + case this.viewTypeEnum.ExternalDatasets:{ + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ExternalDatasets) + // this.form.addControl('data', new ExternalDatasetsDataEditorModel().buildForm()); + + const data: ExternalDatasetsFieldData = { + label:'', + multiAutoComplete: false + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.ExternalDatasets; + field.data = data; + + break; + } + case this.viewTypeEnum.DataRepositories:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DataRepositories) + // this.form.addControl('data', new DataRepositoriesDataEditorModel().buildForm()); + + const data: DataRepositoriesFieldData = { + label: '', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DataRepositories; + field.data = data; + + break; + } + case this.viewTypeEnum.Registries:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Registries) + // this.form.addControl('data', new RegistriesDataEditorModel().buildForm()); + + const data:RegistriesFieldData = { + label: '', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Registries; + field.data = data; + + break; + } + case this.viewTypeEnum.Services:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Services) + // this.form.addControl('data', new ServicesDataEditorModel().buildForm()); + + const data:ServicesFieldData = { + label:'', + multiAutoComplete: false + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Services; + field.data = data; + + break; + } + case this.viewTypeEnum.Tags:{ + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Tags) + // this.form.addControl('data', new TagsDataEditorModel().buildForm()); + + const data: TagsFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Tags; + field.data = data; + + + break; + } + case this.viewTypeEnum.Researchers:{ + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Researchers) + // // this.form.addControl('data', new ResearchersDataEditorModel().buildForm()); //TODO TO ASK + // this.form.addControl('data', new ResearchersAutoCompleteFieldDataEditorModel().buildForm()); + + // field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Researchers; + + const data : ResearchersAutoCompleteFieldData = { + label:'', + multiAutoComplete: false, + type: DatasetProfileInternalDmpEntitiesType.Researchers + } + + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.InternalDmpEntities; + field.data = data; + + + break; + } + case this.viewTypeEnum.Organizations:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Organizations) + // this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()); + + const data = { + autoCompleteSingleDataList:[], + label:'', + multiAutoComplete: false, + + } as OrganizationsFieldData; //TODO + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Organizations; + field.data = data; + + break; + } + case this.viewTypeEnum.DatasetIdentifier:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.DatasetIdentifier) + // this.form.addControl('data', new DatasetIdentifierDataEditorModel().buildForm()); + + const data : DatasetIdentifierFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.DatasetIdentifier; + field.data = data; + + break; + } + case this.viewTypeEnum.Currency:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Currency) + // this.form.addControl('data', new CurrencyDataEditorModel().buildForm()); + + const data: CurrencyFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Currency; + field.data = data; + break; + } + case this.viewTypeEnum.Validation:{ + + + // this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Validation) + // this.form.addControl('data', new ValidationDataEditorModel().buildForm()); + + const data:ValidationFieldData = { + label:'' + } + + field.viewStyle.renderStyle = DatasetProfileFieldViewStyle.Validation; + field.data = data; + + break; + } + } + + // this.form.get('data').updateValueAndValidity(); + // this.form.get('viewStyle').get('renderStyle').updateValueAndValidity(); + // this.form.updateValueAndValidity(); + + + const form = (new FieldEditorModel).fromModel(field).buildForm(); + + + const fields = this.form.parent as FormArray; + let index = -1; + + fields.controls.forEach((control,i)=>{ + if(this.form.get('id').value === control.get('id').value){ + index = i + } + }); + if(index>=0){ + fields.removeAt(index); + fields.insert(index, form); + this.form = form; + + + } + + // setTimeout(() => { //TODO + // this.showPreview = true; + // }); + } + + + toggleRequired(event:MatSlideToggleChange){ + + let validationsControl = this.form.get('validations') as FormControl; + let validations: Array = validationsControl.value; + + if(event.checked){ + if(!validations.includes(ValidationType.Required)){//IS ALREADY REQUIRED + // validationsControl.setValue(validations.filter(validator=> validator != ValidationType.Required)); + // validationsControl.updateValueAndValidity(); + validations.push(ValidationType.Required); + // validationsControl.setValue(validations); + validationsControl.updateValueAndValidity(); + } + }else{ + validationsControl.setValue(validations.filter(validator=> validator != ValidationType.Required)); + validationsControl.updateValueAndValidity(); + } + + } + + get isRequired(){ + let validationsControl = this.form.get('validations') as FormControl; + let validations: Array = validationsControl.value; + + if(validations.includes(ValidationType.Required)){ + return true; + } + return false; + + } + + + onDelete(){ + this.delete.emit(); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/view-style-enum.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/view-style-enum.ts new file mode 100644 index 000000000..f1da6d5cd --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/field/view-style-enum.ts @@ -0,0 +1,21 @@ +export enum ViewStyleType{ + TextArea = "textarea", + BooleanDecision = "booleanDecision", + CheckBox = "checkBox", + FreeText = "freetext", + RadioBox = "radiobox", + DatePicker = "datePicker", + InternalDmpEntities = "internalDmpEntities", + ExternalDatasets = "externalDatasets", + DataRepositories = "dataRepositories", + Registries = "registries", + Services = "services", + Tags = "tags", + Researchers = "researchers", + Organizations = "organizations", + DatasetIdentifier = "datasetIdentifier", + Currency = "currency", + Validation = 'validation', + Select ="selection", + Other ="other" +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.html new file mode 100644 index 000000000..39882e08c --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts new file mode 100644 index 000000000..25afc4373 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts @@ -0,0 +1,28 @@ +import { Component, Input, OnInit} from '@angular/core'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; +import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; + + +@Component({ + selector: 'app-final-preview-component', + templateUrl: './final-preview.component.html', + styleUrls: ['./final-preview.component.scss'], + providers:[VisibilityRulesService] +}) + +export class FinalPreviewComponent implements OnInit { + + + @Input() formGroup = null; + @Input() visibilityRules:Rule[] = []; + constructor(private visibilityRulesService: VisibilityRulesService){ + + } + + + + ngOnInit(): void { + this.visibilityRulesService.buildVisibilityRules(this.visibilityRules, this.formGroup); + } + +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.html index b92190104..dd2a26762 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.html @@ -1,24 +1,99 @@
- {{i + 1}} + {{i + 1}} - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.RULE.FIELDS.RULE-IF'| translate}} + - --> + + + - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.RULE.FIELDS.RULE-THEN'| translate}} + - + + + + + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.RULE.FIELDS.RULE-THEN'| translate}} + + + + + + + + {{option.label? option.label:'<'+ ('DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate) + '>'}} +
+ + {{option.id}} + +
+
+ + + + + {{option.label? option.label:'<'+ ('DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate) + '>'}} +
+ + {{option.id}} + +
+
-
+ + + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.ts index 37e753353..14963db30 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/rule/dataset-profile-editor-rule.component.ts @@ -1,7 +1,10 @@ -import { Component, Input } from '@angular/core'; -import { FormArray, FormControl } from '@angular/forms'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { FormArray, FormControl, FormGroup } from '@angular/forms'; import { DatasetProfileFieldViewStyle } from '../../../../../../core/common/enum/dataset-profile-field-view-style'; import { DatasetProfileComboBoxType } from '../../../../../../core/common/enum/dataset-profile-combo-box-type'; +import { ToCEntryType } from '../../../table-of-contents/table-of-contents-entry'; +import { Rule } from '@app/core/model/admin/dataset-profile/dataset-profile'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-dataset-profile-editor-rule-component', @@ -9,21 +12,198 @@ import { DatasetProfileComboBoxType } from '../../../../../../core/common/enum/d styleUrls: ['./dataset-profile-editor-rule.component.scss'] }) -export class DatasetProfileEditorRuleComponent { - +export class DatasetProfileEditorRuleComponent implements OnInit{ + + @Input() form: FormArray; - + @Input() viewStyleForCheck: DatasetProfileFieldViewStyle; @Input() formControlForCheck: FormControl; @Input() formArrayOptionsForCheck: FormArray; @Input() comboBoxTypeForCheck: DatasetProfileComboBoxType; @Input() viewOnly: boolean; + + + options: OptionItem[]; + sectionOptions: OptionItem[]; + fieldSetOptions: OptionItem[]; + fieldOptions: OptionItem[]; + + constructor(private language: TranslateService){ + + } targetValidation() { //TODO } - + deleteRule(index) { this.form.removeAt(index); } + + ngOnInit(): void { + this._computeOptions(); + } + + private _computeOptions(){ + this.options = this.getOptions(); + + this.sectionOptions = []; + this.fieldOptions = []; + this.fieldSetOptions = []; + this.options.forEach(option=>{ + switch (option.type) { + case ToCEntryType.Field: + this.fieldOptions.push(option); + break; + case ToCEntryType.FieldSet: + this.fieldSetOptions.push(option); + break; + case ToCEntryType.Section: + this.sectionOptions.push(option); + break; + default: + break; + } + }); + //remove options to hide if given fieldset is already hidden by option + + this.fieldOptions.forEach(e=>this._buildHiddenBy(e)); + this.fieldSetOptions.forEach(e=>this._buildHiddenBy(e)); + } + + + + computeOptions(isOpened: boolean){ + if(isOpened){ + this._computeOptions(); + } + } + + private _buildHiddenBy(fo:OptionItem){ + try{ + this.fieldOptions.forEach(foption=>{ + const rules = (foption.form.get('visible').get('rules') as FormArray).controls.map(c=>(c as FormGroup).getRawValue()) as Rule[] + const targets = rules.map(rule=>rule.target); + targets.forEach(target=>{ + if(fo.parentsIds.includes(target) && !fo.hiddenBy.includes(foption.id)){ + fo.hiddenBy.push(...foption.parentsIds); + } + }) + + }); + }catch{ + console.log('error'); + } + } + + + + + + getOptions():OptionItem[]{ + const rootForm = this.form.root; + if(rootForm){ + // const parentSections = rootForm.get('sections') as FormArray; + + const result:OptionItem[] =[]; + + const sections = rootForm.get('sections') as FormArray; + + if(sections){ + sections.controls.forEach(section=>{ + const subResult = this.buildOptions(section as FormGroup, ToCEntryType.Section,[]); + result.push(...subResult); + }); + } + + //return options + return result; + + } + //nothing found + return []; + } + + private buildOptions(form: FormGroup, type: ToCEntryType, parentIds:string[]):OptionItem[]{ + + const sections = form.get('sections') as FormArray; + const fieldSets = form.get('fieldSets') as FormArray; + const fields = form.get('fields') as FormArray; + + const result:OptionItem[] = []; + + // parentIds.push(form.get('id').value); + const currentOptionItem:OptionItem = { + id: form.get('id').value, + type: type, + label: type ===ToCEntryType.Field? form.get('data').get('label').value :form.get('title').value, + // parentsIds: [form.get('id').value] + parentsIds: [...parentIds, form.get('id').value], + form: form, + hiddenBy:[] + } + result.push(currentOptionItem); + + if(sections){ + sections.controls.forEach(section=>{ + result.push( ...this.buildOptions(section as FormGroup, ToCEntryType.Section, currentOptionItem.parentsIds) ); + }); + } + if(fieldSets){ + fieldSets.controls.forEach(fieldset=>{ + result.push( ...this.buildOptions(fieldset as FormGroup, ToCEntryType.FieldSet, currentOptionItem.parentsIds) ); + }); + } + if(fields){ + fields.controls.forEach(field=>{ + result.push( ...this.buildOptions(field as FormGroup, ToCEntryType.Field, currentOptionItem.parentsIds) ); //TODO NA TO DOUME + }); + } + + return result; + } + + get parentIds(): string[]{ + + if(!this.formControlForCheck.get('id')) return []; + + const current = this.options.find(opt=> opt.id === this.formControlForCheck.get('id').value); + + if(current){ + return current.parentsIds; + } + return []; + } + get hiddenBy(): string[]{ + if(!this.formControlForCheck.get('id')) return []; + + const current = this.options.find(opt=> opt.id === this.formControlForCheck.get('id').value); + + if(current){ + return current.hiddenBy; + } + return []; + } + + getToolTipMessage(id: string){ + if(this.parentIds.includes(id)){ + // return 'Cannot hide element that contain the field'; + return this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.RULE.HINTS.ELEMENT-CHILD-OF-TARGET'); + }else if(this.hiddenBy.includes(id)){ + return this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.RULE.HINTS.ELEMENT-HIDDEN-FROM-ELEMENT'); + } + return ''; + } + } + + +interface OptionItem{ + id: string, + label: string, + type: ToCEntryType, + parentsIds: string[], + form:FormGroup, + hiddenBy:string[] +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.html new file mode 100644 index 000000000..ee9cacacd --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.html @@ -0,0 +1,154 @@ +
+
+ + +
+
+ + + + + + + +
+ +
+ +
+
+
+ +
+ + +
+ +
+ + + + + + + + + + + drag_indicator + + + + + + +
+ +
+ +
+
+ + + + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.scss new file mode 100644 index 000000000..bb5162e77 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.scss @@ -0,0 +1,60 @@ +$blue-color : #129D99; +$blue-color-light: #5cf7f2; + + +.field-container-active{ + border-radius: .3em; + border-left: 0.3em solid $blue-color; +} +.fieldset-actions-list li{ + cursor: pointer; +} + + + +.actions-list{ + // border: 1px solid $blue-color; + // box-shadow: 0px 3px 12px #129D9999; + border-radius: 4px; + // padding-top: 1rem; + padding: 1em 0.9em; + padding-bottom: 3em; + min-width: 166px; + + .mat-list-item-content{ + padding: 0px; + } + + + .action-list-item{ + display: flex; + align-items: center; + cursor: pointer; + + + .action-list-icon{ + font-size: 1.2em; + // padding-right: 1em; + width: 14px; + margin-right: 0.5em; + margin-left: -.09em; + height: auto; + color: #129D99;; + } + .input_icon{ + width: 14px; + margin-right: .5em; + } + .action-list-text{ + font-size: 0.9em; + } + } + .action-list-label{ + color: #212121; + font-size: small; + opacity: 0.6; + } + .list-unstyled{ + margin-bottom: 0.2rem; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.ts new file mode 100644 index 000000000..ea6b8089f --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section-fieldset/dataset-profile-editor-section-fieldset.component.ts @@ -0,0 +1,307 @@ +import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { ChangeDetectorRef, Inject, OnDestroy } from '@angular/core'; +import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { FormArray, FormGroup } from '@angular/forms'; +import { FieldEditorModel } from '@app/ui/admin/dataset-profile/admin/field-editor-model'; +import { FieldSetEditorModel } from '@app/ui/admin/dataset-profile/admin/field-set-editor-model'; +import { SectionEditorModel } from '@app/ui/admin/dataset-profile/admin/section-editor-model'; +import { BaseComponent } from '@common/base/base.component'; +import { Guid } from '@common/types/guid'; +import { DragulaService } from 'ng2-dragula'; +import { Subscription } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { ToCEntry, ToCEntryType } from '../../../table-of-contents/table-of-contents-entry'; + +@Component({ + selector: 'app-dataset-profile-editor-section-fieldset-component', + templateUrl: './dataset-profile-editor-section-fieldset.component.html', + styleUrls: ['./dataset-profile-editor-section-fieldset.component.scss'] +}) + +export class DatasetProfileEditorSectionFieldSetComponent implements OnInit, OnChanges, OnDestroy { + // @Input() form: FormGroup; + //@Input() dataModel: SectionEditorModel; + // @Input() indexPath: string; + @Input() viewOnly: boolean; + // @Input() numbering: string; + @Input() tocentry: ToCEntry; + + @Output() selectedEntryId = new EventEmitter(); + @Output() dataNeedsRefresh = new EventEmitter (); + @Output() removeFieldSet = new EventEmitter(); + @Output() addNewFieldSet = new EventEmitter(); + @Output() cloneFieldSet = new EventEmitter(); + + + // FIELDSET_PREFIX_ID="FIELDSET_PREFIX_ID"; + + // @Output() fieldsetAdded = new EventEmitter(); //returns the id of the fieldset added + idprefix = "id"; + private subs = new Subscription(); + private FIELDSETS = 'FIELDSETS'; + constructor( + private dragulaService: DragulaService, + private myElement: ElementRef + ) + { + if(this.dragulaService.find(this.FIELDSETS)){ + this.dragulaService.destroy(this.FIELDSETS); + } + + + this.dragulaService.createGroup(this.FIELDSETS,{ + moves:(el, container, handle)=>{ + // if(this.viewOnly) return false; //uncomment if want to unable drag n drop in viewonly mode + if(el.id != (this.idprefix+this.tocentry.id)) return false; + if(handle.className && handle.classList.contains('handle')) return true; + return false; + } + }); + this.subs.add(this.dragulaService.drop(this.FIELDSETS).subscribe(obs=>{ + + + (this.form.get('fieldSets') as FormArray).controls.forEach((e,i)=>{ + e.get('ordinal').setValue(i); + }); + + + // obs. + this.dataNeedsRefresh.emit(); + return ; + })); + + } + ngOnDestroy(){ + // console.log('elemement destroyed -->'); + + this.subs.unsubscribe(); + } + ngOnChanges(changes: SimpleChanges): void { + // console.log('---------element updated-------'); + // console.log('numbering before:', this.numbering); + + + this.initialize(); + // console.log('----post update----'); + // console.log('numbering now', this.numbering, ' changes detected:', changes); + + + } + + + form; + numbering; + + + + private _selectedFieldSetId: string = null; + get selectedFieldSetId(){ + return this._selectedFieldSetId; + } + set selectedFieldSetId(id: string){ + + if(id === this._selectedFieldSetId) return; + this._selectedFieldSetId = id; + this.selectedEntryId.emit(this._selectedFieldSetId); + } + + private _findParentSection():FormGroup{ + const parent = this.form.parent; + + return parent; + } + + + private initialize(){ + if(this.tocentry.type === ToCEntryType.Section){ + this.form = this.tocentry.form; + this.numbering = this.tocentry.numbering; + this._selectedFieldSetId = null; + + // this._scrollToElement(this.tocentry.id); + this._scrollOnTop(); + }else if(this.tocentry.type === ToCEntryType.FieldSet){ + this.form = this.tocentry.form.parent.parent; + const numberingArray = this.tocentry.numbering.split('.'); + if(numberingArray.length){ + numberingArray.splice(numberingArray.length-1); + this.numbering = numberingArray.join('.'); + }else{ + // console.warn('!not found numbering'); + } + this.selectedFieldSetId = this.tocentry.id; + + this._scrollToElement(this.selectedFieldSetId); + }else{//scroll on top + this._scrollOnTop(); + } + } + + private _scrollToElement(id: string){ + let el = this.myElement.nativeElement.querySelector("#"+this.idprefix+id); + // let el = this.myElement.nativeElement.getElementbyId (this.selectedFieldSetId); + + if(el){ + + /* + Give time to template to build itself (extending and collapsing). + In case we are dragging from one container to another, then the ui takes around 600ms to build + individual previews (dataset-profile-editor-field.component.ts); + + */ + setTimeout(() => { + const el = this.myElement.nativeElement.querySelector("#"+this.idprefix+id); + if(el){ + el.scrollIntoView({behavior: "smooth"}); + } + }, 700); + } + + } + private _scrollOnTop(){ + setTimeout(() => { + const el = this.myElement.nativeElement.querySelector('#topofcontainer'); + if(el){ + el.scrollIntoView({behavior:'smooth'}) + } + },200); + + } + ngOnInit() { + + // console.log('<-- element created'); + // this.initialize(); + + + + //TODO + // this.form.root.get('pages').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => + // this.keepPageSelectionValid(x) + // ); + } + + drop(event: CdkDragDrop) { + // if(!this.links || !this.links.length) return; + + if(event.container === event.previousContainer){ + // moveItemInArray(this.links, event.previousIndex, event.currentIndex); + + let arrayToUpdate: FormArray = this.form.get('fieldSets') as FormArray; + // if(this.parentLink && this.parentLink.form){ + // switch(this.parentLink.subEntriesType){ + // case this.tocEntryType.Field: + // arrayToUpdate = (this.parentLink.form.get('fields') as FormArray); + // break; + // case this.tocEntryType.FieldSet: + // arrayToUpdate = (this.parentLink.form.get('fieldSets') as FormArray); + // break; + // case this.tocEntryType.Section: + // arrayToUpdate = (this.parentLink.form.get('sections') as FormArray); + // break + // } + + // } + if(arrayToUpdate.controls){ + moveItemInArray(arrayToUpdate.controls, event.previousIndex, event.currentIndex); + //update ordinality + arrayToUpdate.controls.forEach((element,idx ) => { + element.get('ordinal').setValue(idx); + element.updateValueAndValidity(); + }); + } + + this.dataNeedsRefresh.emit(); + }else{ + console.log('not same container'); + } + + } + + + onRemoveFieldSet(fieldsetId: string){ + this.removeFieldSet.emit(fieldsetId); + } + + onCloneFieldSet(fieldset: FormGroup){ + this.cloneFieldSet.emit(fieldset); + } + onAddFieldSet(){ + this.addNewFieldSet.emit(this.form); + } + + + // addField() { + // const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); + // fieldSet.ordinal = (this.form.get('fieldSets') as FormArray).length; + + // const field: FieldEditorModel = new FieldEditorModel(); + // field.id = Guid.create().toString(); + // field.ordinal = 0;//first field in fields + // fieldSet.fields.push(field); + // // if (this.dataModel.fieldSets) { + // fieldSet.id = Guid.create().toString(); + // //this.dataModel.fieldSets.push(fieldSet); + // //} + // const fieldsetsArray = this.form.get('fieldSets') as FormArray; + // fieldsetsArray.push(fieldSet.buildForm()); + + // const fieldSetForm = fieldsetsArray.at(fieldsetsArray.length-1); + // //emit id inserted + // if(fieldSetForm){ + // const id: string = fieldSetForm.get('id').value; + // this.fieldsetAdded.emit(id); + // } + // } + + // addSectioninSection() { + // const section: SectionEditorModel = new SectionEditorModel(); + // //this.dataModel.sections.push(section); + // (this.form.get('sections')).push(section.buildForm()); + // } + + // DeleteSectionInSection(index) { + // //this.dataModel.sections.splice(index, 1); + // (this.form.get('sections')).removeAt(index); + // } + + // deleteFieldSet(index) { + // //this.dataModel.fieldSets.splice(index, 1); + // (this.form.get('fieldSets')).removeAt(index); + // } + + // keepPageSelectionValid(pagesJson: Array) { + // const selectedPage = this.form.get('page').value as String; + // // const pages: Array = JsonSerializer.fromJSONArray(pagesJson, Page); + // if (pagesJson.find(elem => elem.id === selectedPage) === undefined) { + // this.form.get('page').reset(); + // } + // } + + // 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); + // } + 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; + } + } + + return tocEntryFound? tocEntryFound: null; + } +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.html index c1f35e67a..2b799f3f6 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.html @@ -1,31 +1,42 @@ 
-

{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.TITLE' | translate}}

+ + - + + +
{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-NAME' | translate}} *
+
{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-NAME-HINT' | translate}}
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + + +
{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-DESCRIPTION' | translate}}
+
{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-DESCRIPTION-HINT' | translate}}
+ + + + + -

{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.FIELDS-TITLE' | + + + + + + + + + + + -

diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.scss index 02d304fc1..7645fb831 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.scss @@ -1,4 +1,6 @@ .dataset-profile-editor { + + .field-card { margin-bottom: 1em; } @@ -6,3 +8,24 @@ .deleteBtn{ margin-right:2em; } + +.heading { + text-align: left; + font-weight: 700; + font-size: 18px; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + // margin-top: 1.625rem; + margin-bottom: 0.625rem; +} + +.hint { + text-align: left; + font-weight: 400; + font-size: 16px; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + margin-bottom: 0.125rem; +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts index 9f54487c6..4e6fac781 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/section/dataset-profile-editor-section.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormArray, FormGroup } from '@angular/forms'; import { FieldEditorModel } from '@app/ui/admin/dataset-profile/admin/field-editor-model'; import { FieldSetEditorModel } from '@app/ui/admin/dataset-profile/admin/field-set-editor-model'; @@ -15,45 +15,59 @@ import { takeUntil } from 'rxjs/operators'; export class DatasetProfileEditorSectionComponent extends BaseComponent implements OnInit { @Input() form: FormGroup; - @Input() dataModel: SectionEditorModel; + //@Input() dataModel: SectionEditorModel; @Input() indexPath: string; @Input() viewOnly: boolean; + @Output() fieldsetAdded = new EventEmitter(); //returns the id of the fieldset added constructor() { super(); } ngOnInit() { - this.form.root.get('pages').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => - this.keepPageSelectionValid(x) - ); + + //TODO + // this.form.root.get('pages').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => + // this.keepPageSelectionValid(x) + // ); } addField() { const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); + fieldSet.ordinal = (this.form.get('fieldSets') as FormArray).length; + const field: FieldEditorModel = new FieldEditorModel(); field.id = Guid.create().toString(); + field.ordinal = 0;//first field in fields fieldSet.fields.push(field); - if (this.dataModel.fieldSets) { + // if (this.dataModel.fieldSets) { fieldSet.id = Guid.create().toString(); - this.dataModel.fieldSets.push(fieldSet); + //this.dataModel.fieldSets.push(fieldSet); + //} + const fieldsetsArray = this.form.get('fieldSets') as FormArray; + fieldsetsArray.push(fieldSet.buildForm()); + + const fieldSetForm = fieldsetsArray.at(fieldsetsArray.length-1); + //emit id inserted + if(fieldSetForm){ + const id: string = fieldSetForm.get('id').value; + this.fieldsetAdded.emit(id); } - (this.form.get('fieldSets')).push(fieldSet.buildForm()); } addSectioninSection() { const section: SectionEditorModel = new SectionEditorModel(); - this.dataModel.sections.push(section); + //this.dataModel.sections.push(section); (this.form.get('sections')).push(section.buildForm()); } DeleteSectionInSection(index) { - this.dataModel.sections.splice(index, 1); + //this.dataModel.sections.splice(index, 1); (this.form.get('sections')).removeAt(index); } deleteFieldSet(index) { - this.dataModel.fieldSets.splice(index, 1); + //this.dataModel.fieldSets.splice(index, 1); (this.form.get('fieldSets')).removeAt(index); } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/custom-validators/editor-custom-validators.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/custom-validators/editor-custom-validators.ts new file mode 100644 index 000000000..f23d30d9f --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/custom-validators/editor-custom-validators.ts @@ -0,0 +1,67 @@ +import { Inject, Injectable } from "@angular/core"; +import { AbstractControl, FormArray, ValidationErrors, ValidatorFn } from "@angular/forms"; + + +export class EditorCustomValidators{ + + static atLeastOneElementListValidator(arrayToCheck): ValidatorFn{ + return (control: AbstractControl): ValidationErrors | null=>{ + + const fa = control.get(arrayToCheck) as FormArray; + + if(!fa || fa.length === 0){ + return {[EditorCustomValidatorsEnum.emptyArray]: true}; + } + return null; + } + } + static pagesHaveAtLeastOneSection(pagesArrayName:string,sectionsArrayName:string ): ValidatorFn{ + + return (control: AbstractControl): ValidationErrors | null=>{ + + const pages = control.get(pagesArrayName) as FormArray; + const sections = control.get(sectionsArrayName) as FormArray; + + + const pageIdsArray = pages.controls.map(page=>page.get('id').value); + const sectionsPageIds = sections.controls.map(section=> section.get('page').value); + + let invalidMessage = null; + + pageIdsArray.forEach(pageId=>{ + if(!sectionsPageIds.includes(pageId)){ + invalidMessage = {[EditorCustomValidatorsEnum.atLeastOneSectionInPage]:true}; + } + }) + + return invalidMessage; + } + } + + static sectionHasAtLeastOneChildOf(fieldsetsArrayName, sectionsArrayName): ValidatorFn{ + + return (control: AbstractControl): ValidationErrors | null=>{ + + const fieldsets = control.get(fieldsetsArrayName) as FormArray; + const sections = control.get(sectionsArrayName) as FormArray; + + + if((fieldsets && fieldsets.length) || (sections && sections.length)){ + return null; + } + + return {[EditorCustomValidatorsEnum.sectionMustHaveOneChild] : true}; + } + } + + + +} + + + +export enum EditorCustomValidatorsEnum{ + sectionMustHaveOneChild = "sectionMustHaveOneChild", + atLeastOneSectionInPage = 'atLeastOneSectionInPage', + emptyArray="emptyArray" +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts index 700dd4ae7..f99b16318 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts @@ -3,6 +3,7 @@ import { DatasetProfile } from '../../../../core/model/admin/dataset-profile/dat import { BaseFormModel } from '../../../../core/model/base-form-model'; import { PageEditorModel } from '../admin/page-editor-model'; import { SectionEditorModel } from '../admin/section-editor-model'; +import { EditorCustomValidators } from './custom-validators/editor-custom-validators'; export class DatasetProfileEditorModel extends BaseFormModel { @@ -48,6 +49,10 @@ export class DatasetProfileEditorModel extends BaseFormModel { pagesFormArray.push(form); }); formGroup.addControl('pages', this.formBuilder.array(pagesFormArray)); + + formGroup.setValidators([EditorCustomValidators.atLeastOneElementListValidator('pages'), EditorCustomValidators.pagesHaveAtLeastOneSection('pages','sections')]); + formGroup.updateValueAndValidity(); + return formGroup; } } 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 c6d9198aa..52eeb2322 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 @@ -1,106 +1,487 @@ -
+ + +
-

{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE' | translate}}

-

- {{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-CLONE' | translate}} - {{form.get('label').value}} -

-

- {{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-VERSION' | translate}} - {{form.get('label').value}} -

-

{{form.get('label').value}}

- - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - + - - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - - - - - - {{ lang.name }} - - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - + -
- -
- - - {{'DATASET-PROFILE-EDITOR.STEPS.PAGES.TITLE' | translate}} -
- -
- + +
+ +
+

{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE' | translate}}

+

+ {{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-CLONE' | translate}} + {{form.get('label').value}} +

+

+ {{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-VERSION' | translate}} + {{form.get('label').value}} +

+ +

{{form.get('label').value}}

+ +
+ +
+
+ + +
+
+
+
+
+ + + done + + + {{idx+1}} + + {{step.label}} + +
- - - {{'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate}} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + +
- - - - {{i + 1}}. {{form.get('sections').get(''+i).get('title').value}} - - - -
- - -
-
-
- +
1.1 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME'| translate}} *
+
{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME-HINT'| translate}}
+ + + {{'GENERAL.VALIDATION.REQUIRED' | + translate}} + +
+
+
1.2 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION'| translate}} *
+ +
{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-HINT'| translate}}
+ + + {{'GENERAL.VALIDATION.REQUIRED' + | translate}} + + +
+ +
+ +
1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *
+ + + + + {{ lang.name }} + + + {{'GENERAL.VALIDATION.REQUIRED' | + translate}} + + +
+ +
+ + +
+ + +
+ + +
+ + + +
+
+ + + +
+ +
+ +
+
+ + +
+
+
+ +
+
{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME' | translate}} *
+
{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME-HINT' | translate}}
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+ +
+ +
+ + +
+ +
+
+ +
+ + + +
+ + +
+ +
+
+
+
+ {{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.NOTHING-HERE-HINT'| translate}} +
+
+
+
+ {{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.START-CREATING-PAGE-START'| translate}} + + add + + {{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.START-CREATING-PAGE-END'| translate}} + +
+
+
+
+ +
+ + + + + + + + +
+ + +
+ + +
+
+ + + + + + + + + + + + +
-
- -
-
- - - + + + + + +
+ +
+
+ + + + + + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ +
- -
-
- - -
-
- -
-
- -
-
-
+ + + + + + + + + + +
-
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.scss index 5121e378f..c66aa6f9e 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.scss @@ -9,3 +9,222 @@ .deleteBtn{ margin-right:2em; } + + + +// REFACTORED CSS + +.stepper{ + background-color: transparent; + min-height: 500px; +} +.content-displayer{ + background-color: #fff; + border-radius: 7px; + box-shadow: 0px 1px 2px #bfbfbf; + padding: 0em; + // padding-top: 0em; + overflow: visible; + // min-height: 30em; +} + +.heading { + text-align: left; + font-weight: 700; + font-size: 18px; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + // margin-top: 1.625rem; + margin-bottom: 0.625rem; +} + +.hint { + text-align: left; + font-weight: 400; + font-size: 16px; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + margin-bottom: 0.125rem; +} + +//TO CHECK +:host ::ng-deep .mat-horizontal-content-container { + overflow: visible; + // padding: 0px; +} +:host ::ng-deep .mat-form-field-outline{ + background-color: #ffffff4f; +} + +:host ::ng-deep .mat-horizontal-stepper-header-container { + display: none !important; +} + +#progress{ + position: absolute; + height: 100%; + width: 100%; + clip-path: polygon(0 0, 0 0, 0 0, 0 0); + transition-property: clip-path; + transition-duration: 600ms; + transition-timing-function: ease-out; + transition-delay: 50ms; + box-shadow: 0px 1px 2px #bfbfbf; + background-color: #F7DD72; +} +#progress-container{ + box-shadow: 1px 1px 6px #00000029;; + // border-radius: .3em; +} +// .import-btn { +// background: #ffffff 0% 0% no-repeat padding-box; +// border-radius: 30px; +// // color: #129d99; +// // border: 1px solid #129d99; +// padding-left: 2em; +// padding-right: 2em; +// color: #000; +// border: 1px solid #000; +// } +.navigate-btn { + border-radius: 30px; + background-color: #f7dd72; + border: 1px solid transparent; + padding-left: 2em; + padding-right: 2em; + box-shadow: 0px 3px 6px #1E202029; + + transition-property: background-color, color; + transition-duration: 200ms; + transition-delay: 50ms; + transition-timing-function: ease-in-out; +} +.navigate-btn-disabled{ +background-color: #CBCBCB; +color: #FFF; +} + +.create-section-btn { + border-radius: 30px; + background-color: #f7dd72; + border: 1px solid transparent; + padding-left: 1em; + padding-right: 1em; + box-shadow: 0px 3px 6px #1E202029; + line-height: 1.7em; +} + + +$blue-color : #129D99; +$blue-color-light: #5cf7f2; + +.finalize-btn { + border-radius: 30px; + border: 1px solid #129D99; + background: transparent; + padding-left: 2em; + padding-right: 2em; + box-shadow: 0px 3px 6px #1E202029; + color: #129D99; +} + + + + +.stepper-title-label{ + cursor: pointer; + transition-property: color, opacity; + transition-duration: 200ms; + transition-delay: 50ms; + transition-timing-function: ease-in-out; + color: #212121; + font-size: 0.9em; +} + +.stepper-title-label-locked{ + color: #DEDEDE; +} + +.stepper-title-label-completed{ + opacity: 0.5; +} +.page-infos{ + padding: 2em; +} +.mat-subheader{ + padding: 0px; +} + +//for the acitons list toolbar +// .mat-list-item.mat-list-item-with-avatar{ +// padding-left: 0em; +// } + + +.actions-list{ + // border: 1px solid $blue-color; + box-shadow: 0px 3px 12px #129D9999; + border-radius: 4px; + // padding-top: 1rem; + padding: 1em 0.9em; + min-width: 166px; + + .mat-list-item-content{ + padding: 0px; + } + + + .action-list-item{ + display: flex; + align-items: center; + cursor: pointer; + + + .action-list-icon{ + font-size: 1.2em; + // padding-right: 1em; + width: 14px; + margin-right: 0.5em; + margin-left: -.09em; + height: auto; + color: #129D99;; + } + .input_icon{ + width: 14px; + margin-right: .5em; + } + .action-list-text{ + font-size: 0.9em; + } + } + .action-list-label{ + color: #212121; + font-size: small; + opacity: 0.6; + } + .list-unstyled{ + margin-bottom: 0.2rem; + } +} + + +// .mli{ +// height: auto; +// } + + +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline { + background: #fafafa !important; +} + +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { + font-size: 1rem; + padding: 0.6em 0 1em 0 !important; +} + +.basic-info-input{ + margin-top: 2em; + margin-bottom: 2em; +} \ No newline at end of file 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 d30180f76..29a0917c8 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 @@ -1,10 +1,10 @@ import { of as observableOf, Observable } from 'rxjs'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { AfterViewInit, Component, OnChanges, OnInit, QueryList, SimpleChanges, ViewChild } from '@angular/core'; +import { AbstractControl, Form, FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; -import { MatHorizontalStepper } from '@angular/material/stepper'; +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'; @@ -26,13 +26,35 @@ 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 { NewEntryType, 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'; +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; +import { invalid } from '@angular/compiler/src/render3/view/util'; +import { SideNavService } from '@app/core/services/sidenav/side-nav.sevice'; +import { EditorCustomValidators, EditorCustomValidatorsEnum } from './custom-validators/editor-custom-validators'; +import { CustomErrorValidator } from '@common/forms/validation/custom-validator'; +import { STEPPER_ANIMATIONS } from './animations/animations'; +import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; + 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'] + styleUrls: ['./dataset-profile-editor.component.scss'], + animations:[...STEPPER_ANIMATIONS], + providers:[VisibilityRulesService] }) export class DatasetProfileEditorComponent extends BaseComponent implements OnInit { @@ -52,6 +74,17 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn nestedCount: number[] = []; nestedIndex: number = 0; errorMessages: string[] = []; + tocEntryEnumValues = ToCEntryType; + + colorizeInvalid:boolean = false; + + + // customEditorValidators = new EditorCustomValidators(); + + // sectionIdPreviewed:string = null; + // currentSubForm:FormGroup = null; + // currentSectionIndex: number = null; + // currentSectionEditorModel: SectionEditorModel = null; constructor( private datasetProfileService: DatasetProfileService, @@ -63,14 +96,24 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn private dialog: MatDialog, private languageInfoService: LanguageInfoService, private httpClient: HttpClient, - private matomoService: MatomoService + private matomoService: MatomoService, + private enumUtils: EnumUtils, + private datasetWizardService: DatasetWizardService, + private visibilityRulesService: VisibilityRulesService, + private fb: FormBuilder, + private sidenavService: SideNavService ) { super(); // this.profileID = route.snapshot.params['id']; // this.cloneId = route.snapshot.params['cloneid']; } + ngOnDestroy(){ + this.sidenavService.setStatus(true); + } + ngOnInit() { + this.sidenavService.setStatus(false); this.matomoService.trackPageView('Admin: Dataset Profile Edit'); this.route.paramMap.pipe(takeUntil(this._destroyed)).subscribe((paramMap: ParamMap) => { this.datasetProfileId = paramMap.get('id'); @@ -150,20 +193,48 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn } else { this.dataModel = new DatasetProfileEditorModel(); this.form = this.dataModel.buildForm(); + // this.form.setValidators([EditorCustomValidators.atLeastOneElementListValidator('pages'), EditorCustomValidators.pagesHaveAtLeastOneSection('pages', 'sections')]); + if (this.dataModel.status === DatasetProfileEnum.FINALIZED) { this.form.disable(); this.viewOnly = true; } - this.addSection(); - this.addPage(); + // this.addSection(); + // this.addPage(); + this.visibilityRulesService.buildVisibilityRules([],this.form); + setTimeout(() => { + this.steps = this.stepper.steps; + }); + this._initializeToCEntries(); + } }); + + } + private _initializeToCEntries(){ + const tocentries = this.refreshToCEntries();//tocentries are sorted based on their ordinal value + + this._updateOrdinals(tocentries); + + if(tocentries && tocentries.length){ + this.selectedTocEntry = tocentries[0]; + } + // this._initializeFormValidity(tocentries); + + + } + + prepareForm() { + this.visibilityRulesService.buildVisibilityRules([],this.form); + // this.form.setValidators([EditorCustomValidators.atLeastOneElementListValidator('pages'),EditorCustomValidators.pagesHaveAtLeastOneSection('pages', 'sections')]); + // this.form.updateValueAndValidity(); this.form.valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(change => { + // this.datasetProfileService.preview(this.form.value) // .pipe(takeUntil(this._destroyed)) // .subscribe(dataset => { @@ -173,7 +244,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn // this.previewerFormGroup = this.dataWizardModel.buildForm().get('datasetProfileDefinition'); // }); }); - this.form.updateValueAndValidity(); + setTimeout(() => { + this.steps = this.stepper.steps; + }); + this._initializeToCEntries(); + } onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) { @@ -183,31 +258,33 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn } } - addSection() { - const section: SectionEditorModel = new SectionEditorModel(); - this.dataModel.sections.push(section); - (this.form.get('sections')).push(section.buildForm()); - } + // 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()); - } + // 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); - } + // 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']); - }); + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success); + },error=> this.onCallbackError(error)); } else if (this.newVersionId) { data.label = this.form.get('label').value; data.description = this.form.get('description').value; @@ -215,17 +292,21 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success); }, error => this.onCallbackErrorNewVersion(error) ); } else { - this.form.get('status').setValue(DatasetStatus.Draft); + if(this.form.get('status').value != DatasetStatus.Finalized){// forn created and finalized instantly + 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']); - }); + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success); + }, error=> this.onCallbackError(error)); } } @@ -241,21 +322,22 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn .pipe(takeUntil(this._destroyed)) .subscribe(() => { this.router.navigate(['/dataset-profiles']); - }); + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success) + },error=>this.onCallbackError(error)); } showUpdateButton() { return !this.isNew && this.dataModel.status === DatasetProfileEnum.FINALIZED; } - isStepActive(step: number) { - return this.stepper && this.stepper.selectedIndex === step; - } + // 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']); - } + // 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); @@ -341,66 +423,1412 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn } checkFormValidation() { - if (!this.form.valid) { - this.nestedIndex = -1; - this.form.markAllAsTouched(); - this.printErrors(this.form); - this.showValidationErrorsDialog(); - this.nestedCount = []; - this.nestedIndex = 0; - this.errorMessages = []; - } + this.colorizeInvalid = true; + this.printMyErrors(this.form); + + + // 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 { + + //BEFORE REDESIGN + // 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; + // } + + + datasetWizardModel: DatasetWizardEditorModel; + formGroup: FormGroup; + getPreview() { + let data = this.form.getRawValue(); + this.datasetProfileService.preview(data).subscribe(x => { + this.datasetWizardModel = new DatasetWizardEditorModel().fromModel({ + datasetProfileDefinition: x + }); + this.updateVisibilityRules(); + 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); + // this._updateNumbering(this.toCEntries); + return this.toCEntries; + } + + /** + * Updates entries ordinal form value + * based on the index they have on the tocentry array. + * Tocentries that are on the same level have distinct ordinal value + * + * @param 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); + }); + } + + //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; + } + private _updateNumbering(entries:ToCEntry[], parentNumbering:string){ + if(!entries || !entries.length) return; + let prefix =''; + if(parentNumbering.length){ + prefix = parentNumbering + '.'; + } + entries.forEach((entry,index)=>{ + const numbering = prefix + (index+1); + entry.numbering = numbering; + this._updateNumbering(entry.subEntries, numbering); + }) + } + + 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); + + }); + this._sortToCentries(result);//ordeby ordinal + this._updateNumbering(result, '');//update nubering if needed + 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 || !tocentries.length){ + 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; + } + } + + return tocEntryFound? tocEntryFound: null; + } + addNewEntry(tce: NewEntryType) { + + const parent = tce.parent; + + //define entry type + switch (tce.childType) { + case ToCEntryType.Page: + const pagesArray = (this.form.get('pages') as FormArray); + + const page: PageEditorModel = new PageEditorModel(pagesArray.length); + const pageForm = page.buildForm(); + // this.dataModel.pages.push(page); + + pagesArray.push(pageForm); + // this.form.updateValueAndValidity(); + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries); + + break; + case ToCEntryType.Section: + + const section: SectionEditorModel = new SectionEditorModel(); + section.id = Guid.create().toString(); + let sectionsArray:FormArray; + + if (parent.type === ToCEntryType.Page) {//FIRST LEVEL SECTION + sectionsArray = this.form.get('sections') as FormArray; + + section.page = parent.id; + + try{ + const max = sectionsArray.controls.filter(control=>control.get('page').value === parent.id) + .map(control=>control.get('ordinal').value) + .reduce((a,b)=>Math.max(a,b)); + + section.ordinal = max + 1; + }catch{ + section.ordinal = sectionsArray.length; + + } + sectionsArray.push(section.buildForm()); + // this.form.updateValueAndValidity(); + + } 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; + try{ + const maxOrdinal = sectionsArray.controls.map(control=>control.get('ordinal').value).reduce((a,b)=>Math.max(a, b)); + section.ordinal = maxOrdinal+1; + }catch{ + section.ordinal = sectionsArray.length; + } + + sectionsArray.push(section.buildForm()); + // (child.form.parent as FormArray).push(section.buildForm()); + + }else{ + console.error('Section can only be child of a page or another section'); + } + + + const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup; + // sectionAdded.setValidators(this.customEditorValidators.sectionHasAtLeastOneChildOf('fieldSets','sections')); + // sectionAdded.updateValueAndValidity(); + + + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.toCEntries); + + break; + case ToCEntryType.FieldSet: + + //create one field form fieldset + const field: FieldEditorModel = new FieldEditorModel(); + field.id = Guid.create().toString(); + field.ordinal = 0;//first filed in the fields list + 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 + const fieldSet: FieldSetEditorModel = new FieldSetEditorModel(); + const fieldSetId = Guid.create().toString(); + fieldSet.id = fieldSetId; + + try{ + const maxOrdinal = fieldSetsArray.controls.map(control=>control.get('ordinal').value).reduce((a,b)=>Math.max(a, b)); + fieldSet.ordinal = maxOrdinal+1; + }catch{ + fieldSet.ordinal = fieldSetsArray.length; + } + const fieldsetForm = fieldSet.buildForm(); + + + + (fieldsetForm.get('fields') as FormArray).push(fieldForm); + fieldSetsArray.push(fieldsetForm); + + this.refreshToCEntries(); + this.selectedTocEntry = this._findTocEntryById(fieldSetId, this.toCEntries); + // fieldForm.updateValueAndValidity(); + + break; + + default: + break; + } + + this.form.updateValueAndValidity(); + } + + + 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); + + const sectionsIndexToBeRemoved = []; + + sections.controls.forEach((section,idx)=>{ + if(section.get('page').value === tce.id){ + sectionsIndexToBeRemoved.push(idx); + } + }); + + if(sectionsIndexToBeRemoved.length){ + sectionsIndexToBeRemoved.reverse().forEach(index=>{ + sections.removeAt(index); + }); + } + + //update page ordinals + 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; } } - 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--; + 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); + console.log(this.form); + } + + get barPercentage(){ + if(!this.stepper || !this.steps){ + return 0; + } + const selectedIndex = this.stepper.selectedIndex + 1; + return (selectedIndex / this.stepper.steps.length) * 100; + } + + + get progressStyle(){ + // return {'transform': 'translateX('+this.barPercentage+'%) skewX(-25deg)'} + const diff = 3; + + return { + 'clip-path': `polygon(0 0, ${Math.round(this.barPercentage + diff)}% 0, ${Math.round(this.barPercentage)}% 100%, 0 100%)` + } + } + + 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(); + // } + + + updateVisibilityRules(){ + const rules:Rule[] =[]; + const fieldSets = this._getFieldSets(this.getTocEntries()); + + 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); + }); + } + }); + } + }); + + this.visibilityRules = rules; + + } + + 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 === (this.steps.length -1)){//preview selected + // this.generatePreviewForm();//TODO LAZY LOADING IN THE TEMPLATE + this.getPreview(); + }else{ + // this.previewForm = null; + this.formGroup = null; + } + this.form.markAsUntouched(); + + } + + // previewForm:FormGroup; + onDataNeedsRefresh(params?){ + + const tocentries = this.refreshToCEntries(); + + if(params && params.draggedItemId){ + if(params.draggedItemId){ + this.displayItem(this._findTocEntryById(params.draggedItemId, tocentries)); + } + } + } + + cloneFieldSet(fieldset: FormGroup){ + 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); + + + + + } + + isStepCompleted(stepIndex: number){ + + let stepCompleted = false; + this.steps.forEach((step,index)=>{ + if(stepIndex === index){ + stepCompleted = step.completed; + } + }); + + return stepCompleted; + } + + isStepUnlocked(stepIndex: number): boolean{ + if(stepIndex === 0) return true; + if(stepIndex <0 ) return false; + //if previous step is valid then unlock + let stepUnlocked: boolean = false; + + if(!this.isStepUnlocked(stepIndex -1)) return false; + + this.steps.forEach((step,index)=>{ + + if(index+1 == stepIndex){//previous step + + if(step.completed){ + stepUnlocked = true; + } + } + }); + + return stepUnlocked; + } + + validateStep(selectedIndex){ + + if(selectedIndex === 1){//form description + if(this.form.invalid){ + this.checkFormValidation(); + } + } + + + // if(step.hasError){ + // this.printMyErrors(this.form); + // } + } + + // 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); + // } + // } + + + + private _buildErrorMessage(errors, numbering, key):string[]{ + const errmess: string[] = []; + + Object.keys(errors).forEach(keyError => { + + switch(keyError){ + case EditorCustomValidatorsEnum.atLeastOneSectionInPage: + errmess.push( this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.PAGE-MUST-HAVE-SECTION')); + break; + case EditorCustomValidatorsEnum.emptyArray: + errmess.push(numbering+this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.NEEDS-MORE-INFORMATION')) + break; + case EditorCustomValidatorsEnum.sectionMustHaveOneChild: + errmess.push(numbering+this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.MUST-HAVE-SECTION-OR-FIELDSET')) + break; + default: + if (typeof errors[keyError] === 'boolean') { + errmess.push(numbering + ' ' + key + ' is ' + keyError); + } else { + errmess.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError])); + } + + } + + }); + + return errmess; + } + + + printMyErrors(form: AbstractControl){ + // this._printToCentriesErrrors(this.toCEntries); + const result = this._getErrors(form); + + // console.log('got errors '); + // console.log(result); + + if(result && form.invalid){ + const errmess:string[] = []; + if(result.length){ + form.markAllAsTouched(); + + let indexes:number[] = []; + ///search in pages,sections and fieldsets for the id + result.forEach((err,i)=>{ + const entry = this._findTocEntryById(err.id, this.toCEntries); + if(entry){ + + // errmess.push(`Error on ${entry.numbering} ${entry.label} . ${err.key}`); + errmess.push(...this._buildErrorMessage(err.errors, entry.numbering, err.key)); + indexes.push(i); + } + }); + indexes.reverse().forEach(index=>{ + result.splice(index,1); + }); + + indexes = []; + //searching in fields + const fieldsets = this._getAllFieldSets(this.toCEntries); + result.forEach((err,i)=>{ + fieldsets.filter(fs=>{ + let fieldFound = false; + (fs.form.get('fields') as FormArray).controls.forEach(field=>{ + if(field.get('id').value === err.id){ + fieldFound = true; + indexes.push(i); + } + }); + return fieldFound; + }) + //printing fieldsets that the field missing + .forEach(fs=>{ + // errmess.push(`Missing input in ${fs.numbering} ${fs.label} . ${err.key}`); + errmess.push(...this._buildErrorMessage(err.errors, fs.numbering, err.key)); + }); + }); + + indexes.reverse().forEach(index=>{ + result.splice(index,1); + }); + + result.forEach(err=>{ + // console.log(err); + if(err.key){ + errmess.push(`${this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.MISSING')} ${err.key}` ); + }else{ + + errmess.push(this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.PROVIDE-PAGE-AND-SECTION')); + } + // errmess.push(...this._buildErrorMessage(err.errors,"", err.key) ); + + }) + } + + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + autoFocus: false, + restoreFocus: false, + data: { + errorMessages: errmess, + projectOnly: false + }, }); } } - private showValidationErrorsDialog(projectOnly?: boolean) { - const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { - disableClose: true, - autoFocus: false, - restoreFocus: false, - data: { - errorMessages: this.errorMessages, - projectOnly: projectOnly - }, + /** + * Get all filedsets in a tocentry array; + * @param entries Tocentries to search in + * @returns The tocentries that are Fieldsets provided in the entries + */ + private _getAllFieldSets(entries: ToCEntry[]):ToCEntry[]{ + + const fieldsets:ToCEntry[] = []; + if(!entries || !entries.length) return fieldsets; + + + entries.forEach(e=>{ + if(e.type === ToCEntryType.FieldSet){ + fieldsets.push(e); + }else{ + fieldsets.push(...this._getAllFieldSets(e.subEntries)); + } }); + return fieldsets; } + + + private _getErrors(aControl: AbstractControl):InvalidControl[]{ + + + 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"; + + + const invalidControls:InvalidControl[] = []; + //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) return; //// !!!!! Important to be !invalid. (In case the template is finalized) + + if(control instanceof FormControl){ + const ctrl = control as FormControl; + + invalidControls.push({ + errors:ctrl.errors, + id: ctrl.get('id')? ctrl.get('id').value: null, + invalidSubControls: [], + key: key + }); + + }else{ + // if(aControl.errors){ + // invalidControls.push({ + // id: aControl.get('id')? aControl.get('id').value: null, + // errors:aControl.errors, + // key: aControl.get('title')? aControl.get('title').value: 'unspecified', + // invalidSubControls:[]//TODO TO CHECK + // }); + // } + + + //THE ONE WE REMOVED + // if(control.errors){ + // // invalidControls.push({ + // // id: aControl.get('id')? aControl.get('id').value: null, + // // errors:aControl.errors, + // // key: aControl.get('title')? aControl.get('title').value: 'unspecified', + // // invalidSubControls:[]//TODO TO CHECK + // // }); + + // invalidControls.push({ + // errors:control.errors, + // id: control.get('id')? control.get('id').value: null, + // invalidSubControls: [], + // key: key + // }); + // } + invalidControls.push(...this._getErrors(control)) ; + + } + }); + + /**In case there is an error in a formgroup then the validator probably is custom */ + if(aControl.errors){ + invalidControls.push({ + errors:aControl.errors, + id: aControl.get('id')? aControl.get('id').value: null, + invalidSubControls: [], + key: aControl.get('title')?aControl.get('title').value: null + }); + } + + break; + case 'fa': + // const fa = (aControl as FormArray); + const ctrls = (aControl as FormArray).controls; + const keys_ = Object.keys(ctrls); + keys_.forEach(key=>{ + const control = ctrls[key]; + if(control.valid) return; + + + if(control instanceof FormControl){ //for completion purposes. should never run this case + const ctrl = control as FormControl; + invalidControls.push({ + errors:ctrl.errors, + id: ctrl.get('id')? ctrl.get('id').value: null, + invalidSubControls: [], + key: key + }); + + }else{ + invalidControls.push(... this._getErrors(control)); + } + }); + + break; + } + + invalidControls.forEach(e=>{ + if(!e.id){ + e.id = aControl.get('id')? aControl.get('id').value : null; + } + }) + return invalidControls; + + } + + + //Temporary patch + /** + * Append custom validators to fields. Some validators are applied on template. In case they are never rendereed, + * he form might be valid when it shouldnt. + * @param + */ + private _initializeFormValidity(tocentries: ToCEntry[]) { + const fieldsets = this._getAllFieldSets(tocentries); + + try{ + fieldsets.forEach(fs=>{ + fs.form.get('title').setValidators(Validators.required); + const fieldsF = fs.form.get('fields') as FormArray; + if(fieldsF){ + fieldsF.controls.forEach(field=>{ + const renderStyleValue = field.get('viewStyle').get('renderStyle').value; + + if(renderStyleValue === DatasetProfileFieldViewStyle.CheckBox){ + field.get('defaultValue').get('value').setValidators(Validators.required); + }else if(renderStyleValue === 'combobox'){ + + const comboType = field.get('data').get('type').value; + if(comboType === DatasetProfileComboBoxType.Autocomplete){//As 'Other' in UI + field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList')); + }else if(comboType === DatasetProfileComboBoxType.WordList){ + field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + } + + }else if(renderStyleValue === DatasetProfileFieldViewStyle.RadioBox){ + field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options')); + } + }); + } + }); + }catch(e){ + console.error('Error initializing validators.'); + console.error(e); + } + + } + } + +interface InvalidControl{ + key: string, + errors: any, + id: string, + invalidSubControls: InvalidControl[] +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.html index c303267ef..45a016601 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.html @@ -1,23 +1,23 @@ -
- -
- - - - - - {{'DATASET-PROFILE-STATUS.NONE' | translate}} - {{'DATASET-PROFILE-STATUS.DRAFT' | translate}} - {{'DATASET-PROFILE-STATUS.FINALIZED' | translate}} - - -
-
- - -
+
+
+
+ {{'CRITERIA.USERS.SHOW' | translate}}:
- + + + + {{'DATASET-PROFILE-STATUS.NONE' | translate}} + {{'DATASET-PROFILE-STATUS.DRAFT' | translate}} + {{'DATASET-PROFILE-STATUS.FINALIZED' | translate}} + + + +
+
+ + + search + +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.scss index e69de29bb..9b64c055a 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.scss @@ -0,0 +1,17 @@ +.mat-form-field{ + display: inline-block !important; +} + +:host ::ng-deep .status-form-field .mat-form-field-wrapper { + background-color: white !important; + padding-bottom: 0 !important; +} + +:host ::ng-deep .search-form-field .mat-form-field-wrapper { + background-color: white !important; + padding-bottom: 0 !important; +} + +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { + padding: 0.3rem 0rem 0.6rem 0rem !important; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts index f0b1b3e17..7cf625f1f 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; -import { DialodConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { DialogConfirmationUploadDatasetProfiles } from '@app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; @@ -11,7 +11,7 @@ import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-dataset-profile-criteria-component', templateUrl: './dataset-profile.component.html', - styleUrls: ['./dataset-profile.component.scss'], + styleUrls: ['./dataset-profile.component.scss'] }) export class DatasetProfileCriteriaComponent extends BaseCriteriaComponent implements OnInit { @@ -47,26 +47,4 @@ export class DatasetProfileCriteriaComponent extends BaseCriteriaComponent imple } } - openDialog(): void { - const dialogRef = this.dialog.open(DialodConfirmationUploadDatasetProfiles, { - width: '500px', - restoreFocus: false, - data: { - message: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML-FILE-TITLE'), - confirmButton: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML'), - cancelButton: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML-FILE-CANCEL'), - name: "", - file: FileList, - sucsess: false - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { - if (data && data.sucsess && data.name != null && data.file != null) { - this.datasetService.uploadFile(data.file, data.name) - .pipe(takeUntil(this._destroyed)) - .subscribe(); - } - }); - } - } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html index dec3649ac..d071e4cb2 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html @@ -4,22 +4,41 @@

{{ data.message }}

- - + close
+ +
+
+ + + {{ selectedFileName }} + + +
+
+ +
+
+ + +
+
+
- +
- +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss index 226db6ce8..63c42f81e 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss @@ -1,3 +1,102 @@ .hidden { display: none; +} + + +.cancel-btn { + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #b5b5b5; + border-radius: 30px; + width: 101px; + height: 43px; + color: #212121; + font-weight: 500; +} + +.next-btn { + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #129d99; + border-radius: 30px; + opacity: 1; + width: 101px; + height: 43px; + color: #129d99; + font-weight: 500; +} + +.next-btn[disabled] { + width: 100px; + height: 43px; + background: #ffffff 0% 0% no-repeat padding-box; + border: 1px solid #b5b5b5; + border-radius: 30px; + opacity: 1; +} + +.next-btn:not([disabled]):hover { + background-color: #129d99; + color: #ffffff; +} + +//ngx dropzone +.drop-file { + background-color: #fafafa; + border: 1px dashed #d1d1d1; + border-radius: 4px; + max-width: 480px; + height: 98px; + margin-top: 0.5rem; +} + +.file-preview { + height: auto !important; + width: auto !important; + max-width: 500px !important; + min-height: 1rem !important; + + background-color: #e0e0e0 !important; + background-image: none !important; + color: rgba(0, 0, 0, 0.87) !important; + font-weight: 500 !important; + border-radius: 24px !important; + line-height: 1.25 !important; +} + +.file-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 14px !important; +} + +::ng-deep ngx-dropzone-remove-badge { + opacity: 1 !important; + margin-left: .5rem !important; + position: initial !important; +} + + +//attach file + +.attach-btn { + top: -20px; +} + +.attach-file { + width: 156px; + height: 44px; + color: #ffffff; + background: #129d99 0% 0% no-repeat padding-box; + box-shadow: 0px 3px 6px #1e202029; + border-radius: 30px; +} + +.attach-file:hover { + background-color: #ffffff; + border: 1px solid #129d99; + color: #129d99; +} + +.close-btn:hover{ + cursor: pointer; } \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts index 8db9791c4..2fe4b0343 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts @@ -7,30 +7,35 @@ import { Inject, Component } from '@angular/core'; templateUrl: './dialog-confirmation-upload-profiles.component.html', styleUrls: ['./dialog-confirmation-upload-profiles.component.scss'] }) -export class DialodConfirmationUploadDatasetProfiles { +export class DialogConfirmationUploadDatasetProfiles { sizeError = false; - btnColore:String="primary"; + selectedFileName= ""; selectFile =false; maxFileSize: number = 1048576; constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any ) { } selectXML(event) { - const file: FileList = event.target.files; + let file: FileList = null; + + if(event.target && event.target.files){ + file = event.target.files; + }else if(event.addedFiles && event.addedFiles.length){ + file = event.addedFiles; + } + if(!file) return;//no select closed with cancel . no file selected const size: number = file[0].size; // Get file size. this.sizeError = size > this.maxFileSize; // Checks if file size is valid. const formdata: FormData = new FormData(); if (!this.sizeError) { this.data.file = file; this.selectFile=true; - this.btnColore="primary"; - }else{ - this.btnColore="warn"; + this.selectedFileName = file[0].name; } this.data.name = file[0].name; } @@ -41,7 +46,6 @@ export class DialodConfirmationUploadDatasetProfiles { } confirm() { - this.data.name = this.data.name; this.data.sucsess = true; this.dialogRef.close(this.data); } @@ -50,4 +54,10 @@ export class DialodConfirmationUploadDatasetProfiles { return (this.selectFile && !this.sizeError); } + //remove selected file + onRemove(){ + this.data.name=""; + this.selectFile = false; + this.selectedFileName = ""; + } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html index bd754914e..6414e32fb 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html @@ -1,9 +1,26 @@
-

{{titlePrefix}} {{'DATASET-PROFILE-LISTING.TITLE' | translate}}

- - +
+
+

{{titlePrefix}} {{'DATASET-PROFILE-LISTING.TITLE' | translate}}

+
+
+
+ + +
+
+
+
+
+ +
+
+ +
+ + @@ -31,12 +48,12 @@ {{'DATASET-PROFILE-LISTING.COLUMNS.STATUS' | translate}} - {{ (row.status | parseStatus) | translate}} +
{{ (row.status | parseStatus) | translate}}
- {{'DATASET-PROFILE-LISTING.COLUMNS.ACTIONS' | translate}} + @@ -50,10 +67,18 @@ library_books {{'DATASET-PROFILE-LISTING.ACTIONS.VIEW-VERSIONS' | translate}} + + @@ -63,14 +88,10 @@
+ - - -
- +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.scss index b2318bf16..456be7372 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.scss +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.scss @@ -1,9 +1,14 @@ .dataset-profile-listing { margin-top: 1rem; + margin-left: 1rem; + margin-right: 2rem; } .mat-table { - margin: 24px; + margin-top: 47px; + // margin-bottom: 20px; + border-radius: 4px; + } .mat-fab-bottom-right { @@ -16,6 +21,10 @@ z-index: 5; } +.mat-header-row{ + background: #f3f5f8; +} + .full-width { width: 100%; } @@ -26,48 +35,85 @@ .mat-row { cursor: pointer; + min-height: 4.5em; } mat-row:hover { - background-color: lightgray; + background-color: #eef5f6; } +.status-chip{ + + border-radius: 20px; + padding-left: 1em; + padding-right: 1em; + padding-top: 0.2em; + font-size: .8em; +} + +.status-chip-finalized{ + color: #568b5a; + background: #9dd1a1 0% 0% no-repeat padding-box; +} + +.status-chip-draft{ + color: #00c4ff; + background: #d3f5ff 0% 0% no-repeat padding-box; +} // mat-row:nth-child(even){ // background-color:red; // } -mat-row:nth-child(odd) { - background-color: #0c748914; - // background-color: #eef0fb; -} +// mat-row:nth-child(odd) { +// background-color: #0c748914; +// // background-color: #eef0fb; +// } -::ng-deep .mat-paginator-container { +:host ::ng-deep .mat-paginator-container { flex-direction: row-reverse !important; justify-content: space-between !important; background-color: #f6f6f6; - height: 30px; - min-height: 30px !important; + align-items: center; + // height: 30px; + // min-height: 30px !important; } -::ng-deep .mat-paginator-page-size { - height: 43px; -} +// ::ng-deep .mat-paginator-page-size { +// height: 43px; +// } -::ng-deep .mat-paginator-range-label { - margin: 15px 32px 0 24px !important; -} +// ::ng-deep .mat-paginator-range-label { +// margin: 15px 32px 0 24px !important; +// } -::ng-deep .mat-paginator-range-actions { - width: 55% !important; - min-height: 43px !important; - justify-content: space-between; -} +// ::ng-deep .mat-paginator-range-actions { +// width: 55% !important; +// min-height: 43px !important; +// justify-content: space-between; +// } -::ng-deep .mat-paginator-navigation-previous { - margin-left: auto !important; -} +// ::ng-deep .mat-paginator-navigation-previous { +// margin-left: auto !important; +// } -::ng-deep .mat-icon-button { - height: 30px !important; - font-size: 12px !important; +// ::ng-deep .mat-icon-button { +// height: 30px !important; +// font-size: 12px !important; +// } + +.import-btn { + background: #ffffff 0% 0% no-repeat padding-box; + border-radius: 30px; + // color: #129d99; + // border: 1px solid #129d99; + padding-left: 2em; + padding-right: 2em; + color: #000; + border: 1px solid #000; } +.create-btn { + border-radius: 30px; + background-color: #f7dd72; + padding-left: 2em; + padding-right: 2em; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts index 0b17a2951..fafcd4f0f 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.ts @@ -1,9 +1,11 @@ import { DataSource } from '@angular/cdk/table'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit, ViewChild } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { ActivatedRoute, Params, Router } from '@angular/router'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; import { DmpModel } from '@app/core/model/dmp/dmp'; @@ -11,13 +13,17 @@ import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset- import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { MatomoService } from '@app/core/services/matomo/matomo-service'; -import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { DatasetProfileCriteriaComponent } from '@app/ui/admin/dataset-profile/listing/criteria/dataset-profile.component'; import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { BaseComponent } from '@common/base/base.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; +import * as FileSaver from 'file-saver'; import { merge as observableMerge, Observable, of as observableOf } from 'rxjs'; import { map, startWith, switchMap, takeUntil } from 'rxjs/operators'; +import { DialogConfirmationUploadDatasetProfiles } from './criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; +import { ParseStatus } from './pipe/parse-status.pipe'; @Component({ selector: 'app-dataset-profile-listing-component', @@ -37,6 +43,7 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI titlePrefix: String; dmpId: String; itemId: string; + datasetStatusEnum = DatasetStatus; constructor( private datasetService: DatasetProfileService, @@ -46,7 +53,9 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI private language: TranslateService, private uiNotificationService: UiNotificationService, private httpClient: HttpClient, - private matomoService: MatomoService + private matomoService: MatomoService, + private dialog: MatDialog, + private datasetProfileService: DatasetProfileService, ) { super(); } @@ -117,11 +126,121 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI viewVersions(rowId, rowLabel) { this.router.navigate(['/dataset-profiles/versions/' + rowId], { queryParams: { groupLabel: rowLabel } }); } + downloadXML(datasetProfileId: string): void { + this.datasetProfileService.downloadXML(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; + } + + deleteTemplate(id: string){ + if(id){ + 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(id, null) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => { + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success); + this.refresh(); + }, + 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); + } + } + ); + } + }); + + + } + } + + onCallbackError(errorResponse: HttpErrorResponse) { + this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning); + } // makeItPublic(id: String) { // debugger; // this.datasetService.makeDatasetPublic(id).pipe(takeUntil(this._destroyed)).subscribe(); // } + + openDialog(): void { + const dialogRef = this.dialog.open(DialogConfirmationUploadDatasetProfiles, { + width: '500px', + restoreFocus: false, + data: { + message: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML-FILE-TITLE'), + confirmButton: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML'), + cancelButton: this.language.instant('DATASET-WIZARD.UPLOAD.UPLOAD-XML-FILE-CANCEL'), + name: "", + file: FileList, + sucsess: false + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { + if (data && data.sucsess && data.name != null && data.file != null) { + this.datasetService.uploadFile(data.file, data.name) + .pipe(takeUntil(this._destroyed)) + .subscribe(_=>{ + this.uiNotificationService.snackBarNotification('Template successfully uploaded', SnackBarNotificationLevel.Success); + this.refresh(); + }, + error=>{ + this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error); + } + ); + } + }); + } + + /** + * gets as a a pameter a number representing the status and returns the class that is applied + * to status-chip */ + getStatusClass(status: DatasetStatus):string{ + + if(status == DatasetStatus.Finalized){ + return 'status-chip-finalized' + } + + return 'status-chip-draft'; + } + } export class DatasetDataSource extends DataSource { diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/pipe/parse-status.pipe.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/pipe/parse-status.pipe.ts index 33cbd4b8c..82b75d2ab 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/pipe/parse-status.pipe.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/pipe/parse-status.pipe.ts @@ -1,4 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; +import { DatasetStatus } from '@app/core/common/enum/dataset-status'; @Pipe({ name: 'parseStatus', @@ -10,7 +11,17 @@ export class ParseStatus implements PipeTransform { } - parseStatus(status: number): string { - return status != 0 ? 'DATASET-PROFILE-STATUS.FINALIZED' : 'DATASET-PROFILE-STATUS.DRAFT'; + parseStatus(status: DatasetStatus): string { + + switch (status) { + case DatasetStatus.Finalized: + return 'DATASET-PROFILE-STATUS.FINALIZED'; + case DatasetStatus.Draft: + return 'DATASET-PROFILE-STATUS.DRAFT'; + case DatasetStatus.Deleted: + return 'DATASET-PROFILE-STATUS.DRAFT.DELETED'; + default: + return 'DATASET-PROFILE-STATUS.DRAFT.NONE'; + } } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-entry.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-entry.ts new file mode 100644 index 000000000..b1ddf7e9a --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-entry.ts @@ -0,0 +1,29 @@ +import { AbstractControl } from "@angular/forms"; + +export interface ToCEntry { + id: string; + label: string; + subEntriesType: ToCEntryType; + subEntries: ToCEntry[]; + type: ToCEntryType; + form: AbstractControl; + numbering: string; +} + + +export enum ToCEntryType { + Page = 0, + Section = 1, + FieldSet = 2, + Field = 3 +} + +export interface NewEntryType { + childType: ToCEntryType, + parent: ToCEntry +} + +export interface TableUpdateInfo{ + draggedItemId?: string; + data?:any; +} \ 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 new file mode 100644 index 000000000..72a3d7179 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.html @@ -0,0 +1,249 @@ + + +
+ +
+ + + + + {{parentLink.subEntries?.length}} + + + + + + delete + +
+
+ + + + +
+ + +
+ + +
+ +
+ +
+ + + + + + + + + + + + + + + +
+ + +
+ +
\ 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.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.scss new file mode 100644 index 000000000..03cd37891 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.scss @@ -0,0 +1,113 @@ +// .docs-toc-container { +// width: 100%; +// padding: 5px 0 10px 0px; +// // cursor: pointer; +// // border-left: solid 4px #0c7489; + +// .scroll-container { +// overflow-y: auto; +// // calc(100vh - 250px) +// // height: calc(100vh - 250px); +// } + +// .docs-link { +// color: rgba(0, 0, 0, 0.54); +// // color: mat-color($app-blue-theme-foreground, secondary-text); +// transition: color 100ms; + +// &:hover, +// &.docs-active { +// .link-name { +// background-color: #ececec; +// border-radius: 6px; +// cursor: pointer;; +// // color: #0c7489; +// } +// // color: mat-color($primary, if($is-dark-theme, 200, default)); +// } +// } +// } + +// .docs-toc-heading { +// margin: 0; +// padding: 0; +// font-size: 13px; +// font-weight: bold; +// } + +// .table-item-actions{ +// // display: none; +// display: inline-block; +// visibility: hidden; +// } + +// .table-item:hover { +// .table-item-actions{ +// // display: inline-block; +// visibility: visible; +// } +// } + +// .table-item col{ +// text-overflow: ellipsis; +// overflow: hidden; +// white-space: nowrap; +// } + +.link-info{ + // display: inline-block; cursor: pointer; + // padding-top: .6em; + // padding-left: .6em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + + +.border-left-active{ + border-left: 1px solid #000; +} + + +.side-bolder{ + border-left: 1px solid red; +} + + +.cdk-link-list { + + display: block; + // background: white; + overflow: hidden; +} + + + +$blue-color : #129D99; +$blue-color-light: #5cf7f2; +$yellow: #f7dd72; +.badge-ball{ + display: inline-block; + border-radius: 50%; + background-color: #FFF; + font-size: small; + font-weight: bold; + min-width: 2em; + text-align: center; +} + +.table-label-element{ + cursor: pointer; + // font-weight: normal; + + // transition-property: font-weight; + // transition-duration: 160ms; + // transition-delay: 50ms; + // transition-timing-function: ease-in-out; +} + + +.table-label-element-active{ + font-weight: bold; + // color: red; +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.ts new file mode 100644 index 000000000..922f1d050 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section.ts @@ -0,0 +1,281 @@ +import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; +import { DOCUMENT } from '@angular/common'; +import { Component, EventEmitter, Inject, Input, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { BaseComponent } from '@common/base/base.component'; +import { NewEntryType, ToCEntry, ToCEntryType } from '../table-of-contents-entry'; + +@Component({ + selector: 'app-dataset-profile-table-of-contents-internal-section', + styleUrls: ['./table-of-contents-internal-section.scss'], + templateUrl: './table-of-contents-internal-section.html' +}) +export class DatasetProfileTableOfContentsInternalSection extends BaseComponent implements OnInit { + + @Input() links: ToCEntry[]; + @Output() itemClick = new EventEmitter(); + @Output() removeEntry = new EventEmitter(); + + @Output() createFooEntry = new EventEmitter(); + + @Output() dataNeedsRefresh = new EventEmitter(); + + + + @Input() parentLink: ToCEntry; + @Input() itemSelected: ToCEntry; + @Input() DRAGULA_ITEM_ID_PREFIX; + @Input() overContainerId: string; + @Input() isDragging; + @Input() draggingItemId: string; + @Input() parentRootId: string; + + @Input() colorizeInvalid:boolean = false; + + @Input() viewOnly: boolean; + // @Input() dropListGroup: Set = new Set(); + // @Input() dropListGroup: string[]; + + // @Input() dragHoveringOver: boolean = false; + // @Input() depth: number = 0; + + // @Input() dropListStruct: { id: string, depth: number}[] = []; + + constructor( + @Inject(DOCUMENT) private _document: Document) { + super(); + } + + tocEntryType = ToCEntryType; + + + // compareFn(a, b){ + // if(a.depth> b.depth) return -1; + // if(a.depth< b.depth) return 1; + + // return 0; + // } + + ngOnInit(): void { + } + + // hoveroverEnter(){ + // // console.log('user hovering drag over', this.parentLink.id, this.parentLink.label); + // this.dragHoveringOver = true; + // } + // hoveroverLeft(){ + // this.dragHoveringOver = false; + // } + + ngOnChanges(changes: SimpleChanges) { + + } + + // get grouListIds(){ + // return Array.from(this.dropListGroup); + // } + itemClicked(item: ToCEntry) { + //leaf node + this.itemClick.emit(item); + } + + deleteEntry(currentLink: ToCEntry){ + this.removeEntry.emit(currentLink); + } + + createNewEntry(foo: NewEntryType){ + this.createFooEntry.emit(foo); + } + + // 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; + // } + + get selectedItemInLinks(){ + if(!this.links || !this.itemSelected) return false; + + const link = this.links.find(l=>l.id === this.itemSelected.id); + + if(link) return true; + return false; + } + + // appendAndGetDroplists(dropList: CdkDropList){ + // this.dropListGroup.push(dropList); + // return this.dropListGroup; + // } + + // drop(event: CdkDragDrop) { + // // if(!this.links || !this.links.length) return; + + // if(event.container === event.previousContainer){ + // moveItemInArray(this.links, event.previousIndex, event.currentIndex); + + // let arrayToUpdate: FormArray = this.links[0].form.parent as FormArray; + // // if(this.parentLink && this.parentLink.form){ + // // switch(this.parentLink.subEntriesType){ + // // case this.tocEntryType.Field: + // // arrayToUpdate = (this.parentLink.form.get('fields') as FormArray); + // // break; + // // case this.tocEntryType.FieldSet: + // // arrayToUpdate = (this.parentLink.form.get('fieldSets') as FormArray); + // // break; + // // case this.tocEntryType.Section: + // // arrayToUpdate = (this.parentLink.form.get('sections') as FormArray); + // // break + // // } + + // // } + // if(arrayToUpdate.controls){ + // moveItemInArray(arrayToUpdate.controls, event.previousIndex, event.currentIndex); + // //update ordinality + // arrayToUpdate.controls.forEach((element,idx ) => { + // element.get('ordinal').setValue(idx); + // element.updateValueAndValidity(); + // }); + // } + + // this.dataNeedsRefresh.emit(); + // }else{ + // console.log('not same container'); + // } + + // console.log(event.container.id); + + // } + + onDataNeedsRefresh(){ + this.dataNeedsRefresh.emit(); + } + + + // get hoveringOverParent(){ + // if(!this.overContainerId) return false; + // const child = this._findTocEntryById(this.overContainerId, this.parentLink.subEntries); + // if(!child) return false; + // return true; + // } + + + public _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; + } + } + + return tocEntryFound? tocEntryFound: null; + } + + + + colorError():boolean{ + + if(!this.colorizeInvalid) return false; + + const form = this.parentLink.form; + if((!form || form.valid || !form.touched) && this.parentLink.type !== this.tocEntryType.Page) return false; + + const allFieldsAreTouched = this.allFieldsAreTouched(form); + + //fieldset may have errros that are inside its controls and not in the fieldsetFormGroup + if(this.parentLink.type === this.tocEntryType.FieldSet && allFieldsAreTouched) return true; + + if(form.errors && allFieldsAreTouched) return true; + + //check if page has sections + if(this.parentLink.type === this.tocEntryType.Page && allFieldsAreTouched){ + const rootForm = form.root; + if(rootForm){ + const sections = rootForm.get('sections') as FormArray; + if(!sections.controls.find(section=>section.get('page').value === this.parentLink.id)){ + return true; + } + } + } + + + //checking first child form controls if have errors + let hasErrors = false; + if(allFieldsAreTouched){ + if(form instanceof FormGroup){ + const formGroup = form as FormGroup; + + const controls = Object.keys(formGroup.controls); + + controls.forEach(control=>{ + if(formGroup.get(control).errors){ + hasErrors = true; + } + }) + + } + } + + return hasErrors; + } + + + allFieldsAreTouched(aControl:AbstractControl){//auto na testaroume + + if(!aControl|| aControl.untouched) return false; + + if(aControl instanceof FormControl){ + return aControl.touched; + }else if(aControl instanceof FormGroup){ + const controlKeys = Object.keys((aControl as FormGroup).controls); + let areAllTouched = true; + controlKeys.forEach(key=>{ + if(!this.allFieldsAreTouched(aControl.get(key))){ + areAllTouched = false; + } + }) + // const areAllTouched = controlKeys.reduce((acc, key)=>acc && this._allFieldsAreTouched(aControl.get(key)), true); + return areAllTouched; + + }else if(aControl instanceof FormArray){ + const controls = (aControl as FormArray).controls; + // const areAllTouched = controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true); + let areAllTouched = true; + // controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true); + controls.forEach(control=>{ + if(!this.allFieldsAreTouched(control)){ + areAllTouched = false; + } + }); + return areAllTouched; + } + + + return false; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.html b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.html new file mode 100644 index 000000000..c88f0a71b --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.html @@ -0,0 +1,23 @@ +
+

{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TEMPLATE-OUTLINE' | translate}}

+
+ + + + +
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.scss b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.scss new file mode 100644 index 000000000..ebd142270 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.scss @@ -0,0 +1,62 @@ + +.scroll-container { + // overflow-y: auto; + max-height: 60vh; + overflow-y: scroll; + padding-left: .2em; + padding-right: 1em; +} + +// #style-6::-webkit-scrollbar-track +// { +// -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +// background-color: #F5F5F5; +// } + +// #style-6::-webkit-scrollbar +// { +// width: 6px; +// background-color: #F5F5F5; +// } + +// #style-6::-webkit-scrollbar-thumb +// { +// background-color: rgb(162, 163, 163); +// background-image: -webkit-linear-gradient(45deg, +// rgba(255, 255, 255, .2) 25%, +// transparent 25%, +// transparent 50%, +// rgba(255, 255, 255, .2) 50%, +// rgba(255, 255, 255, .2) 75%, +// transparent 75%, +// transparent) +// } + + +#tocentrytable::-webkit-scrollbar-track +{ + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + border-radius: 10px; + background-color: #F5F5F5; +} + +#tocentrytable::-webkit-scrollbar +{ + width: 4px; + background-color: #F5F5F5; +} + +#tocentrytable::-webkit-scrollbar-thumb +{ + border-radius: 2px; + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); + background-color: rgb(158, 158, 158);// #FFF;//$blue-color-light;// rgb(162, 163, 163);// #D62929; +} + + +#guide-steps{ + color: #212121; + opacity: 0.6; + font-size: 1.6em; + margin-top: 0px; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.ts new file mode 100644 index 000000000..69717e782 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/table-of-contents/table-of-contents.ts @@ -0,0 +1,559 @@ +import { DOCUMENT } from '@angular/common'; +import { Component, EventEmitter, Inject, OnInit, Output, Input } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { interval, Subject, Subscription } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; +import { type } from 'os'; +import { SimpleChanges } from '@angular/core'; +import { NewEntryType, TableUpdateInfo, ToCEntry, ToCEntryType } from './table-of-contents-entry'; +import { DragulaService } from 'ng2-dragula'; +import { FormArray } from '@angular/forms'; +import { MatSnackBar, MatSnackBarConfig } from '@angular/material'; +import { TranslateService } from '@ngx-translate/core'; +import { ContentObserver } from '@angular/cdk/observers'; + + +@Component({ + selector: 'dataset-profile-table-of-contents', + styleUrls: ['./table-of-contents.scss'], + templateUrl: './table-of-contents.html' +}) +export class DatasetProfileTableOfContents extends BaseComponent implements OnInit { + + @Input() links: ToCEntry[]; + @Input() itemSelected: ToCEntry; + @Input() colorizeInvalid: boolean = false; + @Input() viewOnly: boolean; + + + @Output() itemClick = new EventEmitter(); + // @Output() newEntry = new EventEmitter(); + @Output() removeEntry = new EventEmitter(); + @Output() createEntry = new EventEmitter(); + @Output() dataNeedsRefresh = new EventEmitter(); + + isDragging: boolean = false; + draggingItemId: string = null; + tocEntryType = ToCEntryType; + + DRAGULA_ITEM_ID_PREFIX="table_item_id_"; + ROOT_ID: string = "ROOT_ID";//no special meaning + private _dragStartedAt; + private VALID_DROP_TIME = 500;//ms + overcontainer: string = null; + + constructor( + @Inject(DOCUMENT) private _document: Document, + private dragulaService: DragulaService, + private snackbar: MatSnackBar, + private language: TranslateService + ) { + super(); + + if(this.dragulaService.find('TABLEDRAG')){ + this.dragulaService.destroy('TABLEDRAG'); + } + + const dragula = this.dragulaService.createGroup('TABLEDRAG', {}); + + const drake = dragula.drake; + + drake.on('drop', (el, target, source,sibling)=>{ + + if(this._dragStartedAt){ + const timeNow = new Date().getTime(); + + if(timeNow - this._dragStartedAt> this.VALID_DROP_TIME){ + // console.log('timenow: ', timeNow); + // console.log('timestarted', this._dragStartedAt); + this._dragStartedAt = null; + + }else{ + this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed + return; + } + }else{ + this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed + return; + + } + + const elementId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX,''); + const targetId = target.id as string; + const sourceId = source.id as string; + + + if(!(elementId && targetId && sourceId)){ + console.info('Elements do not have an id'); + this.dataNeedsRefresh.emit(); + return; + } + + + const element:ToCEntry = this._findTocEntryById(elementId, this.links); + const targetContainer:ToCEntry = this._findTocEntryById(targetId , this.links); + const sourceContainer:ToCEntry = this._findTocEntryById(sourceId, this.links); + + if(!(element && (targetContainer ||((element.type===ToCEntryType.Page) && (targetId === this.ROOT_ID))) && (sourceContainer||((element.type===ToCEntryType.Page) && (sourceId === this.ROOT_ID))))){ + // console.info('Could not find elements'); + this.dataNeedsRefresh.emit(); + drake.cancel(true); + return; + } + + + switch(element.type){ + case ToCEntryType.FieldSet:{ + if(targetContainer.type != this.tocEntryType.Section){ + // const message = 'Fieldset can only be child of Subsections'; + const message = this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.FIELDSET-MUST-HAVE-PARENT-SECTION'); + // console.error(message); + this.notifyUser(message) + this.dataNeedsRefresh.emit(); + return; + } + + //check if target container has no sections + if((targetContainer.form.get('sections') as FormArray).length){ + // const message = 'Cannot have inputs and sections on the same level'; + const message = this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL'); + this.notifyUser(message); + // console.error(message); + this.dataNeedsRefresh.emit(); + return; + } + + const fieldsetForm = element.form; + const targetFieldsets = targetContainer.form.get('fieldSets') as FormArray; + const sourceFieldsets = sourceContainer.form.get('fieldSets') as FormArray; + + if(!targetFieldsets){ + console.info('Not target fieldsets container found'); + this.dataNeedsRefresh.emit(); + return; + } + + let sourceOrdinal=-1; + let idx = -1; + sourceFieldsets.controls.forEach((elem,index)=>{ + if(elem.get('id').value === elementId){ + sourceOrdinal = elem.get('ordinal').value; + idx = index + } + }); + + if(sourceOrdinal>=0 && idx>=0){ + sourceFieldsets.removeAt(idx); + + sourceFieldsets.controls.forEach(control=>{ + const ordinal = control.get('ordinal'); + if((ordinal.value>= sourceOrdinal) && sourceOrdinal>0){ + const updatedOrdinalVal = ordinal.value -1; + ordinal.setValue(updatedOrdinalVal); + } + }); + sourceFieldsets.controls.sort(this._compareOrdinals); + } + + let position:number = targetFieldsets.length; + + if(!sibling ||!sibling.id){ + console.info('No sibling Id found'); + }else{ + const siblingId = (sibling.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX,''); + let siblingIndex = -1; + targetFieldsets.controls.forEach((e,idx)=>{ + if(e.get('id').value === siblingId){ + siblingIndex = idx; + position = e.get('ordinal').value; + } + + }); + + if(siblingIndex>=0){ //sibling found + + targetFieldsets.controls.filter(control=> control.get('ordinal').value >= position).forEach(control=>{ + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value +1; + ordinal.setValue(updatedOrdinalVal); + }) + } + + } + + + fieldsetForm.get('ordinal').setValue(position); + targetFieldsets.insert(position,fieldsetForm); + targetFieldsets.controls.sort(this._compareOrdinals); + this.dataNeedsRefresh.emit({draggedItemId: elementId}); + + break; + } + case ToCEntryType.Section:{ + + if(targetContainer.type == ToCEntryType.Section){ + if((targetContainer.form.get('fieldSets')as FormArray).length){ + // const message = 'Cannot have inputs and sections on the same level'; + const message = this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');; + this.notifyUser(message); + // console.info(message); + this.dataNeedsRefresh.emit(); + return; + } + + const targetSections = targetContainer.form.get('sections') as FormArray; + const elementSectionForm = element.form; + const sourceSections = elementSectionForm.parent as FormArray; + + if(!(targetSections && sourceSections && elementSectionForm)){ + console.info('Could not load sections'); + this.dataNeedsRefresh.emit(); + return; + } + + let idx = -1; + sourceSections.controls.forEach((section,i)=>{ + if(section.get('id').value === elementId){ + idx = i; + } + }); + + if(!(idx>=0)){ + console.info('Could not find element in Parent container'); + this.dataNeedsRefresh.emit(); + return; + } + + sourceSections.controls.filter(control=>control.get('ordinal').value >= elementSectionForm.get('ordinal').value).forEach(control=>{ + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value? ordinal.value -1: 0; + ordinal.setValue(updatedOrdinalVal); + }); + + + sourceSections.removeAt(idx); + + let targetOrdinal = targetSections.length; + + if(sibling && sibling.id){ + const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX,''); + + targetSections.controls.forEach((section,i)=>{ + if(section.get('id').value === siblingId){ + targetOrdinal = section.get('ordinal').value; + } + }) + + // if(targetOrdinal!=targetSections.length){//mporei na einai idio + // section.get('ordinal').setValue(i+1); + targetSections.controls.filter(control=> control.get('ordinal').value>=targetOrdinal).forEach(control=>{ + const ordinal = control.get('ordinal'); + const updatedOrdinalVal = ordinal.value+1; + ordinal.setValue(updatedOrdinalVal); + }); + // } + + }else{ + console.info('no siblings found'); + } + elementSectionForm.get('ordinal').setValue(targetOrdinal); + targetSections.insert(targetOrdinal, elementSectionForm); + + }else if(targetContainer.type === ToCEntryType.Page){ + // const pageId = targetContainer.form.get('id').value; + + const rootform = targetContainer.form.root; + const sectionForm = element.form; + const parentSections = sectionForm.parent as FormArray; + + let parentIndex = -1; + parentSections.controls.forEach((section,i )=>{ + if(section.get('id').value === elementId){ + parentIndex = i + } + }) + + + if(parentIndex<0){ + console.info('could not locate section in parents array'); + this.dataNeedsRefresh.emit(); + return; + } + + //update parent sections ordinal + parentSections.controls.filter(section=>section.get('ordinal').value >= sectionForm.get('ordinal').value).forEach(section=>{ + const ordinal = section.get('ordinal'); + const updatedOrdinalVal = ordinal.value?ordinal.value -1: 0; + ordinal.setValue(updatedOrdinalVal); + }) + + parentSections.removeAt(parentIndex); + + + + let position = 0; + if(targetContainer.subEntries){ + position = targetContainer.subEntries.length; + } + //populate sections + const targetSectionsArray = rootform.get('sections') as FormArray; + + + if(sibling && sibling.id){ + const siblingId= sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + let indx = -1; + + targetContainer.subEntries.forEach((e,i)=>{ + if(e.form.get('id').value === siblingId){ + indx = i; + position = e.form.get('ordinal').value; + } + }); + if(indx>=0) { + + // e.form.get('ordinal').setValue(i+1); + targetContainer.subEntries.filter(e=>e.form.get('ordinal').value >= position).forEach(e=>{ + const ordinal = e.form.get('ordinal'); + const updatedOrdinalVal = ordinal.value +1; + ordinal.setValue(updatedOrdinalVal); + }); + } + + }else{ + console.info('No sibling found'); + } + + sectionForm.get('ordinal').setValue(position); + sectionForm.get('page').setValue(targetContainer.id); + targetSectionsArray.push(sectionForm); + + }else{ + // const message = 'Drag not support to specific container'; + const message = this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.DRAG-NOT-SUPPORTED'); + this.notifyUser(message); + // console.info(message); + this.dataNeedsRefresh.emit(); + return; + } + + + + this.dataNeedsRefresh.emit({draggedItemId: elementId}); + break; + } + case ToCEntryType.Page:{ + if(targetId != this.ROOT_ID){ + // const message = 'A page element can only be at top level'; + const message = this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.PAGE-ELEMENT-ONLY-TOP-LEVEL'); + this.notifyUser(message); + // console.info(message); + this.dataNeedsRefresh.emit(); + return; + } + + const rootForm = element.form.root; + if(!rootForm){ + console.info('Could not find root!') + this.dataNeedsRefresh.emit(); + return; + } + + + const pages = rootForm.get('pages') as FormArray; + const pageForm = element.form; + + let index = -1; + + pages.controls.forEach((page,i)=>{ + if(page.get('id').value === elementId){ + index =i; + } + }); + + if(index<0){ + console.info('Could not locate page on pages'); + this.dataNeedsRefresh.emit(); + return; + } + + + //ordinality + pages.controls.filter(page=> page.get('ordinal').value>= pageForm.get('ordinal').value).forEach(page=>{ + const ordinal = page.get('ordinal'); + const ordinalVal = ordinal.value? ordinal.value - 1: 0; + ordinal.setValue(ordinalVal); + }); + + pages.removeAt(index); + + let targetPosition = pages.length; + + if(sibling){ + const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + pages.controls.forEach((page,i)=>{ + if(page.get('id').value === siblingId){ + targetPosition = page.get('ordinal').value; + } + }); + } + pageForm.get('ordinal').setValue(targetPosition); + + //update ordinality + pages.controls.filter(page=> page.get('ordinal').value>= targetPosition).forEach(page=>{ + const ordinal = page.get('ordinal'); + const ordinalVal = ordinal.value +1; + ordinal.setValue(ordinalVal); + }); + + + pages.insert(targetPosition, pageForm); + this.dataNeedsRefresh.emit({draggedItemId:elementId}); + break; + } + default: + + console.info('Could not support moving objects for specific type of element'); + this.dataNeedsRefresh.emit(); + return; + + } + }); + + + drake.on('drag',(el,source)=>{ + this._dragStartedAt = new Date().getTime(); + // console.log('drag fired'); + this.isDragging = true; + this.draggingItemId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, ''); + + // setTimeout(() => { + // if(this.isDragging){ + // this._scrollIntoDragginItem(this.draggingItemId); + // } + // }, this.VALID_DROP_TIME); + }); + drake.on('over',(el, container, source)=>{ + try { + this.overcontainer = container.id; + } catch (error) { + this.overcontainer = null; + } + }); + drake.on('dragend',(el)=>{ + this.isDragging = false; + this.draggingItemId = null; + this.overcontainer = null; + }); + + + + + } + + private _scrollIntoDragginItem(id: string){ + + // const table = document.getElementById('tocentrytable'); + // if(table){ + // // const element = document.getElementById('TABLE_ENTRY'+id); + // console.log('Table found!'); + // const element = document.getElementById('TABLE_ENTRY' + id); + // const elementFromTable = table.closest('#TABLE_ENTRY'+ id); + + + // if(elementFromTable){ + // console.log('found from table:', elementFromTable); + // } + // if(element){ + // console.log('Element found!'); + // // element.classList.add('text-danger'); + // // console.log(element); + + // const tableRect = table.getBoundingClientRect(); + // const elementRect = element.getBoundingClientRect(); + + + // console.log('tablerect :',tableRect); + // console.log('elementRect :',elementRect); + + // const dY = elementRect.top - tableRect.top; + // console.log('Distance from table is ', dY); + // // table.scroll({top:dY,behavior:'smooth'}); + // console.log('found from document ', element); + + // // element.scrollIntoView(); + // } + // // element.scrollIntoView(); + // } + } + + 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; + } + } + + return tocEntryFound? tocEntryFound: null; + } + + ngOnInit(): void { + + + } + + ngOnChanges(changes: SimpleChanges) { + + } + + + itemClicked(item: ToCEntry){ + //leaf node + this.itemClick.emit(item); + } + + // addNewEntry(tce: ToCEntry){ + // this.newEntry.emit(tce); + // } + deleteEntry(currentLink: ToCEntry){ + this.removeEntry.emit(currentLink); + } + + createNewEntry(newEntry: NewEntryType){ + this.createEntry.emit(newEntry); + } + onDataNeedsRefresh(){ + this.dataNeedsRefresh.emit(); + } + + notifyUser(message:string){ + this.snackbar.open(message, null, this._snackBarConfig); + } + + private _snackBarConfig: MatSnackBarConfig = { + duration:2000 + } + + private _compareOrdinals(a, b){ + + const aValue = a.get('ordinal').value as number; + const bValue = b.get('ordinal').value as number; + + // if(!aValue || !bValue) return 0; + return aValue - bValue; + } + + +} diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss index ca94110d8..7720847f5 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss +++ b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss @@ -33,7 +33,7 @@ } } -::ng-deep .mat-paginator-container { +:host ::ng-deep .mat-paginator-container { flex-direction: row-reverse !important; justify-content: space-between !important; background-color: #f6f6f6; @@ -41,25 +41,25 @@ min-height: 30px !important; } -::ng-deep .mat-paginator-page-size { +:host ::ng-deep .mat-paginator-page-size { height: 43px; } -::ng-deep .mat-paginator-range-label { +:host ::ng-deep .mat-paginator-range-label { margin: 15px 32px 0 24px !important; } -::ng-deep .mat-paginator-range-actions { +:host ::ng-deep .mat-paginator-range-actions { width: 55% !important; min-height: 43px !important; justify-content: space-between; } -::ng-deep .mat-paginator-navigation-previous { +:host ::ng-deep .mat-paginator-navigation-previous { margin-left: auto !important; } -::ng-deep .mat-icon-button { +:host ::ng-deep .mat-icon-button { height: 30px !important; font-size: 12px !important; } diff --git a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss index 54a7a60bf..0691742c2 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/user/listing/role-editor/user-role-editor.component.scss @@ -76,11 +76,11 @@ } } -::ng-deep .mat-form-field-wrapper { +:host ::ng-deep .mat-form-field-wrapper { background-color: white !important; padding-bottom: 0 !important; } -::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { padding: 0.3rem 0rem 0.6rem 0rem !important; } diff --git a/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.scss b/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.scss index e44188b1d..f9e30031c 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.scss +++ b/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.scss @@ -59,7 +59,7 @@ } } -::ng-deep .mat-paginator-container { +:host ::ng-deep .mat-paginator-container { // flex-direction: row-reverse !important; // justify-content: space-between !important; // height: 30px; diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss b/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss index b58c0a435..92724be2b 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.scss @@ -399,24 +399,24 @@ input[type="text"] { margin-left: 40px; } -::ng-deep .mat-tab-group.mat-primary .mat-ink-bar, +:host ::ng-deep .mat-tab-group.mat-primary .mat-ink-bar, .mat-tab-nav-bar.mat-primary .mat-ink-bar { background: #129d99; height: 5px; } -::ng-deep .mat-tab-label { +:host ::ng-deep .mat-tab-label { min-width: auto !important; background-color: transparent; } -::ng-deep .mat-tab-label.mat-tab-label-active { +:host ::ng-deep .mat-tab-label.mat-tab-label-active { min-width: auto !important; background-color: transparent; font-weight: 700; } -::ng-deep .mat-form-field-wrapper { +:host ::ng-deep .mat-form-field-wrapper { background-color: white !important; padding-bottom: 0 !important; } diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html index 19dc7757f..a3479015f 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.html @@ -165,7 +165,7 @@
-
+
diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts index ddd660f57..d004c57bb 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts @@ -62,6 +62,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn datasetOffset: number = 0; pageSize: number = 5; dmpFormGroup: FormGroup; + hasMoreActivity:boolean = true; public formGroup = new FormBuilder().group({ like: new FormControl(), order: new FormControl() @@ -605,6 +606,10 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn } refresh(): void { + this.hasMoreActivity = true; + this.datasetOffset = 0; + this.dmpOffset = 0; + const fields: Array = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value]; // const fields: Array = ["-modified"]; this.startIndex = 0; @@ -623,6 +628,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn this.dmpOffset = this.dmpOffset + 1; } }); + + if(response.length< this.pageSize) {this.hasMoreActivity = false;} this.totalCountRecentEdited.emit(this.allRecentActivities.length); }); } @@ -636,7 +643,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn request.criteria.order = this.formGroup.get("order").value; this.dashboardService.getRecentActivity(request).pipe(takeUntil(this._destroyed)).subscribe(result => { - if (!result) { return []; } + if (!result) { this.hasMoreActivity = false; return []; } result.forEach(recentActivity => { if (recentActivity.type === RecentActivityType.Dataset) { this.datasetOffset = this.datasetOffset + 1; @@ -644,6 +651,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn this.dmpOffset = this.dmpOffset + 1; } }); + if(result.length 0 ? this.mergeTwoSortedLists(this.allRecentActivities, result, this.formGroup.get('order').value) : result; this.totalCountRecentEdited.emit(this.allRecentActivities.length); diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html index a0f15db1b..aa72179ba 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.html @@ -50,11 +50,11 @@
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
+
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
- +
@@ -81,14 +81,25 @@
- +
+ + ${index+1}`)); + }); + + } + } + + return errmess; + } + save(saveType?: SaveType) { - this.formService.touchAllFormFields(this.formGroup); + + Object.keys(this.formGroup.controls).forEach(controlName=>{ + if(controlName == 'datasetProfileDefinition'){ + return; + } + this.formService.touchAllFormFields(this.formGroup.get(controlName)); + }) + + + // this.formService.touchAllFormFields(this.formGroup); if (!this.isSemiFormValid(this.formGroup)) { - this.showValidationErrorsDialog(); + //build messages + const errorMessages = this._buildSemiFormErrorMessages(); + this.showValidationErrorsDialog(undefined, errorMessages); + this.hintErrors = true; return; } this.submit(saveType); } - private showValidationErrorsDialog(projectOnly?: boolean) { - const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { - disableClose: true, - autoFocus: false, - restoreFocus: false, - data: { - formGroup: this.formGroup, - projectOnly: projectOnly - }, - }); + private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) { + if(errmess){ + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + autoFocus: false, + restoreFocus: false, + data: { + errorMessages:errmess, + projectOnly: projectOnly + }, + }); + }else{ + + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + autoFocus: false, + restoreFocus: false, + data: { + formGroup: this.formGroup, + projectOnly: projectOnly + }, + }); + } + } hasReversableStatus(): boolean { @@ -886,18 +1004,30 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr } public changeStep(index: number, dataset?: FormControl) { + if(this.step != index){ //view is changing + this.resetScroll(); + } this.step = index; - this.resetScroll(); } public nextStep() { - this.step = this.step < this.maxStep ? this.step + 1 : this.step; - this.resetScroll(); + if(this.step < this.maxStep){//view is changing + if(this.step === 0 && this.table0fContents){ + this.table0fContents.seekToFirstElement(); + } + this.step++; + this.resetScroll(); + } + // this.step = this.step < this.maxStep ? this.step + 1 : this.step; } public previousStep() { - this.step = this.step !== 0 ? this.step - 1 : this.step; - this.resetScroll(); + if(this.step > 0){ + this.resetScroll(); + this.step--; + } + + // this.step = this.step !== 0 ? this.step - 1 : this.step; } private resetScroll() { @@ -911,10 +1041,16 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr discardChanges() { this.isDiscarded = true; this.hasChanges = false; + this.hintErrors = false; if (this.isNew) { Object.keys(this.formGroup['controls']).forEach((key: string) => { - if (key !== 'dmp') { - this.formGroup.get(key).reset(); + if (key !== 'dmp' && (key!== 'profile')) { + if(key === 'datasetProfileDefinition'){ + this.formGroup.get(key).patchValue(this.datasetProfileDefinitionModel.buildForm().getRawValue); + }else{ + this.formGroup.get(key).reset(); + } + } }); } else { @@ -938,4 +1074,140 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, IBr getLinks(currentLinks: Link[]) { this.links = currentLinks; } + + printForm(){ + console.log(this.formGroup); + } + printFormValue(){ + console.log(this.formGroup.value); + } + + // tocentries; + // this.tocentries = this.getTocEntries(this.formGroup.get('datasetProfileDefinition')); //TODO + + + + // get tocentries(){ + // const form = this.formGroup.get('datasetProfileDefinition') + // if(!form) return null; + + // return this.getTocEntries(this.formGroup.get('datasetProfileDefinition')); + // } + + + // private _buildRecursively(form: FormGroup,whatAmI:ToCEntryType):ToCEntry{ + // if(!form) return null; + + // switch(whatAmI){ + // case ToCEntryType.Section: + // const sections = form.get('sections') as FormArray; + // const fieldsets = form.get('compositeFields') as FormArray; + + + // const tempResult:ToCEntry[] = []; + + // if(sections &§ions.length){ + // sections.controls.forEach(section=>{ + // tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); + // }); + + // }else if(fieldsets && fieldsets.length){ + // fieldsets.controls.forEach(fieldset=>{ + // tempResult.push(this._buildRecursively(fieldset as FormGroup, ToCEntryType.FieldSet)); + // }); + // } + // return { + // form: form, + // id: form.get('id').value, + // label: form.get('title').value, + // numbering: '', + // subEntries:tempResult, + // subEntriesType: sections &§ions.length? ToCEntryType.Section: ToCEntryType.FieldSet, + // type: ToCEntryType.Section, + // ordinal: form.get('ordinal').value + // } + // case ToCEntryType.FieldSet: + // return { + // form: form, + // label:form.get('title').value, + // id: form.get('id').value, + // numbering:'s', + // subEntries:[], + // subEntriesType: ToCEntryType.Field, + // type: ToCEntryType.FieldSet, + // ordinal: form.get('ordinal').value + // } + // } + // } + + // private _sortByOrdinal(tocentries: ToCEntry[]){ + + // if(!tocentries || !tocentries.length) return; + + // tocentries.sort(this._customCompare); + // tocentries.forEach(entry=>{ + // this._sortByOrdinal(entry.subEntries); + // }); + // } + + // private _customCompare(a,b){ + // return a.ordinal - b.ordinal; + // } + + // private _calculateNumbering(tocentries: ToCEntry[], depth:number[] = []){ + // if(!tocentries || !tocentries.length){ + // return; + // } + + // let prefixNumbering = depth.length? depth.join('.'): ''; + + // if(depth.length) prefixNumbering = prefixNumbering+"."; + // tocentries.forEach((entry,i)=>{ + // entry.numbering = prefixNumbering + (i+1); + // this._calculateNumbering(entry.subEntries, [...depth, i+1]) + // }); + // } + + + // getTocEntries(form): ToCEntry[] { + // if (form == null) { return []; } + // const result: ToCEntry[] = []; + + // //build parent pages + // (form.get('pages') as FormArray).controls.forEach((pageElement, i) => { + // result.push({ + // id: i+'id', + // label: pageElement.get('title').value, + // type: ToCEntryType.Page, + // form: pageElement, + // numbering: (i + 1).toString(), + // subEntriesType: ToCEntryType.Section, + // subEntries:[], + // ordinal: pageElement.get('ordinal').value + // } as ToCEntry) + // }); + + + + // result.forEach((entry,i)=>{ + + // const sections = entry.form.get('sections') as FormArray; + + // sections.controls.forEach(section=>{ + // const tempResults = this._buildRecursively(section as FormGroup,ToCEntryType.Section); + // entry.subEntries.push(tempResults); + // }); + + // }); + + // this._sortByOrdinal(result); + // //calculate numbering + // this._calculateNumbering(result); + // return result; + + // } + + + + } diff --git a/dmp-frontend/src/app/ui/dataset/dataset.module.ts b/dmp-frontend/src/app/ui/dataset/dataset.module.ts index 720e27218..ec553bef5 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset.module.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset.module.ts @@ -1,4 +1,5 @@ import { NgModule } from '@angular/core'; +import { FormattingModule } from '@app/core/formatting.module'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; @@ -22,14 +23,10 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation- import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { CommonUiModule } from '@common/ui/common-ui.module'; import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; -import { DatasetCopyDialogModule } from './dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module'; -import { DatasetOverviewModule } from './overview/dataset-overview.module'; -import { DatasetCriteriaDialogComponent } from './listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component'; -import { DmpEditorComponent } from '../dmp/editor/dmp-editor.component'; -import { DatasetEditorDetailsComponent } from '../dmp/editor/dataset-editor-details/dataset-editor-details.component'; -import { DatasetEditorDetailsModule } from '../dmp/editor/dataset-editor-details/dataset-editor-details.module'; import { FormProgressIndicationModule } from '../misc/dataset-description-form/components/form-progress-indication/form-progress-indication.module'; -import { FormattingModule } from '@app/core/formatting.module'; +import { DatasetCopyDialogModule } from './dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.module'; +import { DatasetCriteriaDialogComponent } from './listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component'; +import { DatasetOverviewModule } from './overview/dataset-overview.module'; @NgModule({ imports: [ @@ -77,7 +74,10 @@ import { FormattingModule } from '@app/core/formatting.module'; DatasetExternalDataRepositoryDialogEditorComponent, DatasetExternalDatasetDialogEditorComponent, DatasetExternalRegistryDialogEditorComponent, - DatasetExternalServiceDialogEditorComponent + DatasetExternalServiceDialogEditorComponent, + + DatasetEditorComponent, + DatasetDescriptionFormModule ] }) export class DatasetModule { } diff --git a/dmp-frontend/src/app/ui/dataset/dataset.routing.ts b/dmp-frontend/src/app/ui/dataset/dataset.routing.ts index 7d54ef8b6..b024aa044 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset.routing.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset.routing.ts @@ -4,7 +4,6 @@ import { AuthGuard } from '../../core/auth-guard.service'; import { DatasetWizardComponent } from './dataset-wizard/dataset-wizard.component'; import { DatasetListingComponent } from './listing/dataset-listing.component'; import { DatasetOverviewComponent } from './overview/dataset-overview.component'; -import { DmpEditorComponent } from '../dmp/editor/dmp-editor.component'; const routes: Routes = [ { diff --git a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component.scss b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component.scss index 362c44bc3..6ad258085 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component.scss +++ b/dmp-frontend/src/app/ui/dataset/listing/criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component.scss @@ -10,11 +10,11 @@ padding: 0.4rem; } -::ng-deep .mat-form-field-wrapper { +:host ::ng-deep .mat-form-field-wrapper { background-color: white !important; padding-bottom: 0 !important; } -::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { padding: 0.3rem 0rem 0.6rem 0rem !important; } diff --git a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.scss b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.scss index c0077a83d..e50263a3e 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.scss +++ b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.scss @@ -199,11 +199,11 @@ padding-bottom: 0 !important; } -::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { +:host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { padding: 0.3rem 0rem 0.6rem 0rem !important; } -::ng-deep .mat-paginator-container { +:host ::ng-deep .mat-paginator-container { flex-direction: row-reverse !important; justify-content: space-between !important; background-color: #f6f6f6; @@ -211,27 +211,27 @@ min-height: 30px !important; } -::ng-deep .mat-paginator-page-size { +:host ::ng-deep .mat-paginator-page-size { height: 43px; } -::ng-deep .mat-icon-button { +:host ::ng-deep .mat-icon-button { height: 30px !important; font-size: 12px !important; } -::ng-deep .mat-paginator-range-label { +:host ::ng-deep .mat-paginator-range-label { margin: 15px 32px 0 24px !important; } -::ng-deep .mat-paginator-range-actions { +:host ::ng-deep .mat-paginator-range-actions { width: auto !important; min-width: 55% !important; min-height: 43px !important; justify-content: space-between; } -::ng-deep .mat-paginator-navigation-previous { +:host ::ng-deep .mat-paginator-navigation-previous { margin-left: auto !important; } diff --git a/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.html b/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.html index 79a8c1464..b46adb5fc 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.html @@ -14,7 +14,7 @@
{{'DMP-EDITOR.FIELDS.SELECT-TEMPLATE' | translate}} - + {{formGroup.get('profiles').getError('backendError').message}} diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html index ea6fc8b49..7c979743a 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.html @@ -33,17 +33,17 @@
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
    -
  1. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (1)
  2. +
  3. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (1)
  4. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
  5. -
  6. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
  7. +
  8. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
  9. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
  10. -
  11. {{'DMP-EDITOR.STEPPER.FUNDING-INFO' | translate}} (2)
  12. +
  13. {{'DMP-EDITOR.STEPPER.FUNDING-INFO' | translate}} (2)
  14. {{'DMP-EDITOR.STEPPER.FUNDING-INFO' | translate}} (done)
  15. {{'DMP-EDITOR.STEPPER.LICENSE-INFO' | translate}}
  16. -
  17. {{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}} (1)
  18. +
  19. {{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}} (1)
  20. {{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}} (done)
  21. diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 2566c390e..e6aef200c 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -99,6 +99,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC maxStep: number = 4; scrollTop: number; + hintErrors:boolean = false; constructor( private dmpProfileService: DmpProfileService, @@ -412,6 +413,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC // console.log("update ", this.formGroup); if (!this.isFormValid()) { this.showValidationErrorsDialog(); + this.hintErrors = true; return; } this.onSubmit(addNew, showAddDatasetDialog); @@ -429,16 +431,31 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC return this.formGroup.get('datasets')['controls'][0].valid; } - private showValidationErrorsDialog(projectOnly?: boolean) { - const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { - disableClose: true, - autoFocus: false, - restoreFocus: false, - data: { - formGroup: this.formGroup, - projectOnly: projectOnly - }, - }); + private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) { + + if(errmess){ + + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + autoFocus: false, + restoreFocus: false, + data: { + errorMessages:errmess, + projectOnly: projectOnly + }, + }); + }else{ + const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { + disableClose: true, + autoFocus: false, + restoreFocus: false, + data: { + formGroup: this.formGroup, + projectOnly: projectOnly + }, + }); + } + } onSubmit(addNew?: boolean, showAddDatasetDialog?: boolean): void { @@ -734,8 +751,128 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC this.formSubmit(true); } + //checks if the dpm is valid not taking into account the datasets validity + private _isDMPDescriptionValid():boolean{ + + const form: FormGroup = this.formGroup; + if(form.controls){ + return Object.keys(form.controls) + .map(controlName=>{//get validity of each control + if(controlName === 'datasets'){//we dont care if datasets are valid + return true; + } + return !form.get(controlName).invalid;//!! in case the control is disabled, we consider it valid + }) + .reduce((isFormValid,isControlValid)=>{//aggregate validities + return isControlValid && isFormValid; + }, true); + } + return true; + } + + private _getErrorMessage(formControl: AbstractControl, name: string): string[] { + const errors: string[] = []; + Object.keys(formControl.errors).forEach(key => { + if (key === 'required') { errors.push(this.language.instant(name + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED'))); } + // if (key === 'required') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + this.getPlaceHolder(formControl) + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')); } + else if (key === 'email') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.EMAIL')); } + else if (key === 'min') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MIN-VALUE', { 'min': formControl.getError('min').min })); } + else if (key === 'max') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MAX-VALUE', { 'max': formControl.getError('max').max })); } + else { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + formControl.errors[key].message); } + }); + return errors; + } + + private _getPlaceHolder(formControl: any): string { + if (formControl.nativeElement.localName === 'input' || formControl.nativeElement.localName === 'textarea') { + return formControl.nativeElement.getAttribute('placeholder'); + } else if (formControl.nativeElement.localName === 'mat-select') { + return formControl.nativeElement.getAttribute('aria-label'); + } else if (formControl.nativeElement.localName === 'app-single-auto-complete') { + return (Array.from(formControl.nativeElement.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); + } else if (formControl.nativeElement.localName === 'app-multiple-auto-complete') { + return (Array.from(formControl.nativeElement.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); + } + } + + + + private _buildDMPDescriptionErrorMessages(): string[]{//not including datasets + const errmess: string[] = []; + Object.keys(this.formGroup.controls).forEach(controlName=>{ + if(controlName != 'datasets' && this.formGroup.get(controlName).invalid){ + errmess.push(...this._buildErrorMessagesForAbstractControl(this.formGroup.get(controlName), controlName)); + } + }) + + return errmess; + } + + // takes as an input an abstract control and gets its error messages[] + private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string):string[]{ + const errmess:string[] = []; + + if(aControl.invalid){ + + if(aControl.errors){ + //check if has placeholder + if( (aControl).nativeElement !== undefined && (aControl).nativeElement !== null){ + const placeholder = this._getPlaceHolder(aControl); + if(placeholder){ + controlName = placeholder; + } + } + const errorMessage = this._getErrorMessage(aControl, controlName); + + errmess.push(...errorMessage); + } + /*in case the aControl is FormControl then the it should have provided its error messages above. + No need to check case of FormControl below*/ + + if(aControl instanceof FormGroup){ + + const fg = aControl as FormGroup; + //check children + Object.keys(fg.controls).forEach(controlName=>{ + errmess.push(...this._buildErrorMessagesForAbstractControl(fg.get(controlName), controlName)); + }); + }else if(aControl instanceof FormArray){ + + const fa = aControl as FormArray; + + fa.controls.forEach((control,index)=>{ + errmess.push(... this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index+1}`)); + }); + + } + + } + + return errmess; + } + + + + + addDataset() { - this.formSubmit(true, false); + + + if(!this._isDMPDescriptionValid()){ + const errmess = this._buildDMPDescriptionErrorMessages(); + this.showValidationErrorsDialog(undefined, errmess); + this.hintErrors = true; + return; + } + + + + this.onSubmit(true, false); + // this.formSubmit(true, false); + + + + // Add dataset to list // if (!this.formGroup.get('datasets')) { // this.formGroup.addControl('datasets', new FormBuilder().array(new Array())); diff --git a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.scss b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.scss index 41829afd6..002c554f8 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.scss +++ b/dmp-frontend/src/app/ui/dmp/listing/criteria/dmp-criteria.component.scss @@ -122,7 +122,7 @@ background-color: #2e74b649; } -::ng-deep .mat-form-field-wrapper { +:host ::ng-deep .mat-form-field-wrapper { background-color: white !important; padding-bottom: 0 !important; } diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss index 234707e72..d3b0ddec5 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.scss @@ -6,12 +6,12 @@ .lightblue-btn { font-size: 12px; } - ::ng-deep .mat-paginator-container { + :host ::ng-deep .mat-paginator-container { height: auto !important; } } -::ng-deep .mat-paginator-container { +:host ::ng-deep .mat-paginator-container { flex-direction: row-reverse !important; justify-content: space-between !important; background-color: #f6f6f6; @@ -19,7 +19,7 @@ min-height: 30px !important; } -::ng-deep .mat-paginator-page-size { +:host ::ng-deep .mat-paginator-page-size { height: 43px; } @@ -28,18 +28,18 @@ font-size: 12px !important; } -::ng-deep .mat-paginator-range-label { +:host ::ng-deep .mat-paginator-range-label { margin: 15px 32px 0 24px !important; } -::ng-deep .mat-paginator-range-actions { +:host ::ng-deep .mat-paginator-range-actions { width: auto !important; min-width: 55% !important; min-height: 43px !important; justify-content: space-between; } -::ng-deep .mat-paginator-navigation-previous { +:host ::ng-deep .mat-paginator-navigation-previous { margin-left: auto !important; } @@ -256,7 +256,7 @@ padding-bottom: 0 !important; } -::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { +:host::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { padding: 0.3rem 0rem 0.6rem 0rem !important; } diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html index 0a6d80018..a158ea875 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html @@ -4,7 +4,7 @@
    - +
    @@ -27,7 +27,7 @@
    - +
    diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts index 08a261e48..9776cf201 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormArray, FormGroup, AbstractControl } from '@angular/forms'; import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel } from '../../dataset-description-form.model'; +import { ToCEntry } from '../../dataset-description.component'; import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; @Component({ @@ -14,6 +15,7 @@ export class FormCompositeFieldComponent { @Input() form: FormGroup; @Input() isChild: Boolean = false; @Input() showDelete: Boolean = false; + @Input() tocentry: ToCEntry; constructor( public visibilityRulesService: VisibilityRulesService, @@ -22,6 +24,10 @@ export class FormCompositeFieldComponent { } ngOnInit() { + + if(this.tocentry){ + this.form = this.tocentry.form as FormGroup; + } } // addMultipleField(fieldIndex: number) { diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-title/form-composite-title.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-title/form-composite-title.component.html index 374519f49..747b63432 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-title/form-composite-title.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-title/form-composite-title.component.html @@ -1,7 +1,7 @@
    - {{form.get('numbering').value}} + {{tocentry? tocentry.numbering :form.get('numbering').value}} {{form.get('title').value}} + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}
    @@ -237,9 +252,24 @@
    - + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} --> + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}
    diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts index 3a7b4171e..a76cfcae8 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-field/form-field.component.ts @@ -34,6 +34,7 @@ import { ENTER, COMMA } from '@angular/cdk/keycodes'; import { DatasetIdModel } from '@app/core/model/dataset/dataset-id.model'; import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model'; import { CurrencyService } from '@app/core/services/currency/currency.service'; +import { AutoCompleteSingleData } from '@app/core/model/dataset-profile-definition/field-data/field-data'; @Component({ selector: 'app-form-field', @@ -46,6 +47,7 @@ export class FormFieldComponent extends BaseComponent implements OnInit { @Input() form: FormGroup; @Input() datasetProfileId: any; @Input() isChild: Boolean = false; + @Input() autocompleteOptions: AutoCompleteSingleData; // change: Subscription; // trackByFn = (index, item) => item ? item['id'] : null; @@ -123,20 +125,20 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.singleAutoCompleteConfiguration = { filterFn: this.searchFromAutocomplete.bind(this), initialItems: () => this.searchFromAutocomplete(''), - displayFn: (item) => (item != null && item.length > 1) ? JSON.parse(item).label : item['label'], - titleFn: (item) => item['label'], - valueAssign: (item) => JSON.stringify(item), - subtitleFn: (item) => item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') + displayFn: (item) => {try{return (item != null && item.length > 1) ? JSON.parse(item).label : item['label']}catch{return ''}}, + titleFn: (item) => {try{return item['label'] }catch{return''}}, + valueAssign: (item) => {try{return JSON.stringify(item)}catch{return''}}, + subtitleFn: (item) => {try{return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE')}catch{return''}} }; } else { this.multipleAutoCompleteConfiguration = { filterFn: this.searchFromAutocomplete.bind(this), initialItems: () => this.searchFromAutocomplete(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item), - subtitleFn: (item) => item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') + displayFn: (item) =>{try{return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label']}catch{return''}}, + titleFn: (item) =>{ try{return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label']}catch{return''}}, + valueAssign: (item) =>{ try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}, + subtitleFn: (item) => { try{return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE')}catch{return''}} } } } @@ -146,49 +148,49 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.externalDatasetAutoCompleteConfiguration = { filterFn: this.searchDatasetExternalDatasets.bind(this), initialItems: () => this.searchDatasetExternalDatasets(''),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.DataRepositories: this.dataRepositoriesAutoCompleteConfiguration = { filterFn: this.searchDatasetExternalDataRepositories.bind(this), initialItems: () => this.searchDatasetExternalDataRepositories(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.Registries: this.registriesAutoCompleteConfiguration = { filterFn: this.searchDatasetExternalRegistries.bind(this), initialItems: () => this.searchDatasetExternalRegistries(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.Services: this.servicesAutoCompleteConfiguration = { filterFn: this.searchDatasetExternalServices.bind(this), initialItems: () => this.searchDatasetExternalServices(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return ''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.Tags: this.tagsAutoCompleteConfiguration = { filterFn: this.filterTags.bind(this), initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), - displayFn: (item) => this.showTag(item), - titleFn: (item) => item['name'], - valueAssign: (item) => this.addTag(item) + displayFn: (item) => { try{return this.showTag(item)}catch{return''}}, + titleFn: (item) => { try{return item['name']}catch{return''}}, + valueAssign: (item) => { try{return this.addTag(item)}catch{return''}} }; this.parseTags(); break; @@ -196,20 +198,20 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.researchersAutoCompleteConfiguration = { filterFn: this.filterResearchers.bind(this), initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) =>{ try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) => { try{return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.Organizations: this.organisationsAutoCompleteConfiguration = { filterFn: this.filterOrganisations.bind(this), initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')), - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn:(item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) =>{ try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + subtitleFn: (item) =>{ try{return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))}catch{return''}}, + valueAssign: (item) =>{ try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.DatasetIdentifier: @@ -222,9 +224,9 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.currencyAutoCompleteConfiguration = { filterFn: this.searchCurrency.bind(this), initialItems: () => this.searchCurrency(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item) + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}} }; break; case DatasetProfileFieldViewStyle.Validation: @@ -251,14 +253,14 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.form.get('value').valueChanges .pipe(takeUntil(this._destroyed)) .subscribe(item => { - if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) { - item.forEach(element => { - this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, element); - }); + // if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) { + // item.forEach(element => { + // this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, element); + // }); - } else { + // } else { this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, item); - } + // } }); } @@ -280,10 +282,18 @@ export class FormFieldComponent extends BaseComponent implements OnInit { autocompleteRequestItem.criteria.fieldID = this.form.get('id').value; if (typeof this.datasetProfileId === 'string') { autocompleteRequestItem.criteria.profileID = this.datasetProfileId; - } else { + } else if (this.datasetProfileId != null) { autocompleteRequestItem.criteria.profileID = this.datasetProfileId.id; + } else if (this.autocompleteOptions != null) { + autocompleteRequestItem.criteria.autocompleteOptions = this.autocompleteOptions; + } else { + throw "Could not load autocomplete options."; } autocompleteRequestItem.criteria.like = query; + + if(this.autocompleteOptions){ + return this.datasetExternalAutocompleteService.queryApi(autocompleteRequestItem); + } return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem); } @@ -315,20 +325,20 @@ export class FormFieldComponent extends BaseComponent implements OnInit { this.singleAutoCompleteConfiguration = { filterFn: myfunc.bind(this), initialItems: (extraData) => myfunc(''), - displayFn: (item) => (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title], - titleFn: (item) => item[title], + displayFn: (item) => { try{return (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title]}catch{return''}}, + titleFn: (item) => { try{return item[title]}catch{return''}}, valueAssign: (item) => JSON.stringify(item), - subtitleFn: (item) => item[subtitle] + subtitleFn: (item) => { try{return item[subtitle]}catch{return''}} }; } else { this.multipleAutoCompleteConfiguration = { filterFn: myfunc.bind(this), initialItems: (extraData) => myfunc(''), - displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], - titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'], - valueAssign: (item) => typeof (item) == 'string' ? item : JSON.stringify(item), - subtitleFn: (item) => item[subtitle] + displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title]}catch{return''}}, + titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title]}catch{return''}}, + valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}, + subtitleFn: (item) => { try{return item[subtitle]}catch{return''}} } } } @@ -374,6 +384,9 @@ export class FormFieldComponent extends BaseComponent implements OnInit { } parseTags() { + try{ + + let stringValue = this.form.get('value').value; if (typeof stringValue === 'string') { stringValue = (stringValue).replace(new RegExp('{', 'g'), '{"').replace(new RegExp('=', 'g'), '":"').replace(new RegExp(',', 'g'), '",').replace(new RegExp(', ', 'g'), ', "').replace(new RegExp('}', 'g'), '"}'); @@ -387,6 +400,9 @@ export class FormFieldComponent extends BaseComponent implements OnInit { } const tagArray = JSON.parse(stringValue); this.form.patchValue({'value': tagArray}); + }catch(e){ + console.warn('Could not parse tags'); + } } filterTags(value: string): Observable { diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.html new file mode 100644 index 000000000..391794eaf --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.html @@ -0,0 +1,39 @@ + +
    + +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    + +
    + + + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMMENT-HINT' | translate}} + + +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.scss b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.scss new file mode 100644 index 000000000..e4523fbf3 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.scss @@ -0,0 +1,45 @@ +.dynamic-form-section { + .expansion-panel { + // background-color: #eeeeee54; + background-color: white; + margin-top: 1em; + margin-bottom: 1em; + // margin-bottom: 1em; + } + .addOneFieldButton { + margin-top: -15px; + margin-left: -11px; + color: #129d99; + } + .panel-title, + .panel-desc { + text-align: left; + font-weight: 700; + font-size: 1rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + margin-top: 1.625rem; + margin-bottom: 0.625rem; + } + + .panel-desc { + text-transform: capitalize; + font-weight: 400; + margin-top: .5rem; + } +} +.styleBorder { + border: 0.2em solid lightgray; + border-radius: 0.5em; + margin-bottom: 0.5em; +} +.mat-expansion-panel-header-description { + padding-bottom: 18px; + color: black; +} + +::ng-deep .mat-expansion-panel-header { + height: auto !important; + min-height: 48px; +} diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.ts new file mode 100644 index 000000000..b6298840a --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section-inner/form-section-inner.component.ts @@ -0,0 +1,85 @@ +import { AfterViewInit, Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { FormGroup, FormArray, AbstractControl } from '@angular/forms'; +import { FormFocusService } from '../../../form-focus/form-focus.service'; +import { VisibilityRulesService } from '../../../visibility-rules/visibility-rules.service'; +import { DatasetDescriptionSectionEditorModel, DatasetDescriptionCompositeFieldEditorModel } from '../../../dataset-description-form.model'; +import { FormCompositeFieldComponent } from '../../form-composite-field/form-composite-field.component'; +import { LinkToScroll } from '../../../tableOfContentsMaterial/table-of-contents'; + +@Component({ + selector: 'app-form-section-inner', + templateUrl: './form-section-inner.component.html', + styleUrls: ['./form-section-inner.component.scss'] +}) +export class FormSectionInnerComponent implements OnInit, OnChanges { + + //@Input() section: DatasetDescriptionSectionEditorModel; + @Input() datasetProfileId: String; + // @Input() compositeFieldFormGroup: FormGroup; + @Input() form:FormGroup; + @Input() pathName: string; + @Input() path: string; + // @Input() i: number; + @Input() linkToScroll: LinkToScroll; + //trackByFn = (index, item) => item ? item['id'] : null; + panelExpanded = true; + // sub = true; + subsectionLinkToScroll: LinkToScroll; + + constructor( + public visibilityRulesService: VisibilityRulesService, + private formFocusService: FormFocusService + ) { } + + ngOnInit() { + // if (this.section) { + // this.form = this.visibilityRulesService.getFormGroup(this.section.id); + // } + } + + ngOnChanges(changes: SimpleChanges) { + + // if (changes['linkToScroll']) { + // if (changes['linkToScroll'].currentValue && changes['linkToScroll'].currentValue.section) { + + // if (this.pathName === changes['linkToScroll'].currentValue.section) { + // this.panelExpanded = true; + // } else if (changes['linkToScroll'].currentValue.section.includes(this.pathName)) { + // this.subsectionLinkToScroll = changes['linkToScroll'].currentValue; + // this.panelExpanded = true; + // } + // } + // } + } + + // ngAfterViewInit() { + // this.visibilityRulesService.triggerVisibilityEvaluation(); + // } + + addMultipleField(fieldsetIndex: number) { + const compositeFieldToBeCloned = (this.form.get('compositeFields').get('' + fieldsetIndex) as FormGroup).getRawValue(); + const compositeField: DatasetDescriptionCompositeFieldEditorModel = new DatasetDescriptionCompositeFieldEditorModel().cloneForMultiplicity(compositeFieldToBeCloned); + ((this.form.get('compositeFields').get('' + fieldsetIndex).get('multiplicityItems'))).push(compositeField.buildForm()); + } + + deleteCompositeFieldFormGroup(compositeFildIndex: number) { + const numberOfItems = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').value.length; + for (let i = 0; i < numberOfItems; i++) { + const multiplicityItem = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').get('' + i).value; + this.form.get('compositeFields').get('' + compositeFildIndex).get('fields').get('' + i).patchValue(multiplicityItem); + } + ((this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))).removeAt(0); + } + + deleteMultipeFieldFromCompositeFormGroup(compositeFildIndex: number, fildIndex: number) { + ((this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))).removeAt(fildIndex); + } + + // isElementVisible(fieldSet: CompositeField): boolean { + // return fieldSet && fieldSet.fields && fieldSet.fields.length > 0 + // } + + // next(compositeField: CompositeField) { + // this.formFocusService.focusNext(compositeField); + // } +} diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.html index ee2dbc193..0290daa88 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.html @@ -3,12 +3,13 @@ -
    {{form.get('numbering').value}}. {{form.get('title').value}}
    +
    {{tocentry? tocentry.numbering :form.get('numbering').value}}. {{form.get('title').value}}
    {{form.get('description').value}}
    +
    @@ -54,6 +55,81 @@ [datasetProfileId]="datasetProfileId">
    +
    + + + + + + + + + + + + + + + + +
    + + +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    + +
    + + + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMMENT-HINT' | translate}} + + +
    +
    + +
    +
    + +
    + + + + +
    +
    + +
    +
    +
    + +
    + +
    \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts index 123801f1a..9862c2690 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts @@ -1,10 +1,12 @@ -import { AfterViewInit, Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { AfterViewInit, Component, Input, OnInit, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core'; import { FormGroup, FormArray, AbstractControl } from '@angular/forms'; import { FormFocusService } from '../../form-focus/form-focus.service'; import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; import { DatasetDescriptionSectionEditorModel, DatasetDescriptionCompositeFieldEditorModel } from '../../dataset-description-form.model'; import { FormCompositeFieldComponent } from '../form-composite-field/form-composite-field.component'; import { LinkToScroll } from '../../tableOfContentsMaterial/table-of-contents'; +import { ToCEntry, ToCEntryType } from '../../dataset-description.component'; + @Component({ selector: 'app-form-section', @@ -16,6 +18,7 @@ export class FormSectionComponent implements OnInit, OnChanges { //@Input() section: DatasetDescriptionSectionEditorModel; @Input() datasetProfileId: String; @Input() form: FormGroup; + @Input() tocentry: ToCEntry; @Input() pathName: string; @Input() path: string; @Input() linkToScroll: LinkToScroll; @@ -24,6 +27,12 @@ export class FormSectionComponent implements OnInit, OnChanges { // sub = true; subsectionLinkToScroll: LinkToScroll; + + @Output() askedToScroll = new EventEmitter(); + + tocentriesType = ToCEntryType; + @Input() TOCENTRY_ID_PREFIX=""; + constructor( public visibilityRulesService: VisibilityRulesService, private formFocusService: FormFocusService @@ -33,6 +42,10 @@ export class FormSectionComponent implements OnInit, OnChanges { // if (this.section) { // this.form = this.visibilityRulesService.getFormGroup(this.section.id); // } + + if(this.tocentry){//maybe not needed as well + this.form = this.tocentry.form as FormGroup; + } } ngOnChanges(changes: SimpleChanges) { @@ -80,4 +93,11 @@ export class FormSectionComponent implements OnInit, OnChanges { // next(compositeField: CompositeField) { // this.formFocusService.focusNext(compositeField); // } + + + + onAskedToScroll(id:string){ + this.panelExpanded = true; + this.askedToScroll.emit(id); + } } diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.model.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.model.ts index 1dc2c0923..c76550e26 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.model.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.model.ts @@ -64,6 +64,7 @@ export class DatasetDescriptionPageEditorModel extends BaseFormModel { }); formGroup.addControl('sections', this.formBuilder.array(sectionsFormArray)); formGroup.addControl('title', new FormControl({ value: this.title, disabled: true })); + formGroup.addControl('ordinal', new FormControl({value:this.ordinal, disabled:true})); return formGroup; } } @@ -115,6 +116,7 @@ export class DatasetDescriptionSectionEditorModel extends BaseFormModel { formGroup.addControl('numbering', new FormControl({ value: this.numbering, disabled: true })); formGroup.addControl('title', new FormControl({ value: this.title, disabled: true })); formGroup.addControl('id', new FormControl({ value: this.title, disabled: false })); + formGroup.addControl('ordinal', new FormControl({ value: this.ordinal, disabled: true })); return formGroup; } } diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.module.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.module.ts index 6dbc01fa1..cfc3ef0db 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.module.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description-form.module.ts @@ -13,6 +13,8 @@ import { FormCompositeTitleComponent } from './components/form-composite-title/f import { ExternalSourcesModule } from '../external-sources/external-sources.module'; import { DatasetDescriptionComponent } from './dataset-description.component'; import { FormProgressIndicationModule } from './components/form-progress-indication/form-progress-indication.module'; +import { FormSectionInnerComponent } from './components/form-section/form-section-inner/form-section-inner.component'; + @NgModule({ imports: [ @@ -26,13 +28,17 @@ import { FormProgressIndicationModule } from './components/form-progress-indicat DatasetDescriptionFormComponent, DatasetDescriptionComponent, FormSectionComponent, + FormSectionInnerComponent, FormCompositeFieldComponent, FormFieldComponent, FormCompositeTitleComponent ], exports: [ DatasetDescriptionFormComponent, - DatasetDescriptionComponent + DatasetDescriptionComponent, + FormCompositeFieldComponent, + FormFieldComponent, + FormSectionInnerComponent ], providers: [ VisibilityRulesService, diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.html index 9c7cbeeb1..9b163a65f 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.html @@ -5,15 +5,49 @@
    -
    -
    -
    - + +
    +
    +
    + +
    -
    + + + + + + +
    + + + + +

    + {{pageEntry.numbering}}. {{pageEntry.label |uppercase}} +

    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +
    diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts index 5ca786b8e..2a826fda5 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts @@ -1,7 +1,9 @@ import { AfterViewInit, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild, Output, EventEmitter } from '@angular/core'; -import { FormGroup } from '@angular/forms'; +import { AbstractControl, AbstractControlOptions, FormArray, FormGroup } from '@angular/forms'; +import { MatExpansionPanel } from '@angular/material'; import { MatHorizontalStepper } from '@angular/material/stepper'; import { Rule } from '@app/core/model/dataset-profile-definition/rule'; +import { DatasetProfileTableOfContentsInternalSection } from '@app/ui/admin/dataset-profile/table-of-contents/table-of-contents-internal-section/table-of-contents-internal-section'; import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; import { BaseComponent } from '@common/base/base.component'; @@ -16,16 +18,25 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit // @ViewChild('stepper', { static: false }) stepper: MatHorizontalStepper; @Input() path: string; - @Input() form: FormGroup; @Input() visibilityRules: Rule[] = []; @Input() datasetProfileId: String; @Input() linkToScroll: LinkToScroll; @Output() formChanged: EventEmitter = new EventEmitter(); + @Output() fieldsetFocusChange: EventEmitter = new EventEmitter(); + + tocentries: ToCEntry[]; + @Input() form: FormGroup; + + @Input() TOCENTRY_ID_PREFIX=""; + + + private _form: FormGroup; constructor( private visibilityRulesService: VisibilityRulesService, ) { super(); + } ngOnInit() { @@ -37,6 +48,8 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit // this.formChanged.emit(val); // }); // } + + this.tocentries = this.getTocEntries(); } ngOnChanges(changes: SimpleChanges) { @@ -54,4 +67,143 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit ngAfterViewInit() { } + + + + onAskedToScroll(panel: MatExpansionPanel, id?:string){ + panel.open(); + this.fieldsetFocusChange.emit(id); + } + + + + + private _buildRecursively(form: FormGroup,whatAmI:ToCEntryType):ToCEntry{ + if(!form) return null; + + switch(whatAmI){ + case ToCEntryType.Section: + const sections = form.get('sections') as FormArray; + const fieldsets = form.get('compositeFields') as FormArray; + + + const tempResult:ToCEntry[] = []; + + if(sections &§ions.length){ + sections.controls.forEach(section=>{ + tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); + }); + + }else if(fieldsets && fieldsets.length){ + fieldsets.controls.forEach(fieldset=>{ + tempResult.push(this._buildRecursively(fieldset as FormGroup, ToCEntryType.FieldSet)); + }); + } + return { + form: form, + id: form.get('id').value, + label: form.get('title').value, + numbering: '', + subEntries:tempResult, + subEntriesType: sections &§ions.length? ToCEntryType.Section: ToCEntryType.FieldSet, + type: ToCEntryType.Section, + ordinal: form.get('ordinal').value + } + case ToCEntryType.FieldSet: + return { + form: form, + label:form.get('title').value, + id: form.get('id').value, + numbering:'s', + subEntries:[], + subEntriesType: ToCEntryType.Field, + type: ToCEntryType.FieldSet, + ordinal: form.get('ordinal').value + } + } + } + + private _sortByOrdinal(tocentries: ToCEntry[]){ + + if(!tocentries || !tocentries.length) return; + + tocentries.sort(this._customCompare); + tocentries.forEach(entry=>{ + this._sortByOrdinal(entry.subEntries); + }); + } + + private _customCompare(a,b){ + return a.ordinal - b.ordinal; + } + + private _calculateNumbering(tocentries: ToCEntry[], depth:number[] = []){ + if(!tocentries || !tocentries.length){ + return; + } + + let prefixNumbering = depth.length? depth.join('.'): ''; + + if(depth.length) prefixNumbering = prefixNumbering+"."; + tocentries.forEach((entry,i)=>{ + entry.numbering = prefixNumbering + (i+1); + this._calculateNumbering(entry.subEntries, [...depth, i+1]) + }); + } + + + 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: i+'id', + label: pageElement.get('title').value, + type: ToCEntryType.Page, + form: pageElement, + numbering: (i + 1).toString(), + subEntriesType: ToCEntryType.Section, + subEntries:[], + ordinal: pageElement.get('ordinal').value + } as ToCEntry) + }); + + + + result.forEach((entry,i)=>{ + + const sections = entry.form.get('sections') as FormArray; + + sections.controls.forEach(section=>{ + const tempResults = this._buildRecursively(section as FormGroup,ToCEntryType.Section); + entry.subEntries.push(tempResults); + }); + + }); + + this._sortByOrdinal(result); + //calculate numbering + this._calculateNumbering(result); + return result; + + } + } +export interface ToCEntry { + id: string; + label: string; + subEntriesType: ToCEntryType; + subEntries: ToCEntry[]; + type: ToCEntryType; + form: AbstractControl; + numbering: string; + ordinal: number; +} +export enum ToCEntryType { + Page = 0, + Section = 1, + FieldSet = 2, + Field = 3 +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.html new file mode 100644 index 000000000..ea3a5c7ad --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.html @@ -0,0 +1,46 @@ +
    + + + + + + + + + {{entry.numbering}}. {{entry.label}} + + + priority_high + + + + +
    + + + +
    +
    + + + +
    + +
    \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.scss b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.scss new file mode 100644 index 000000000..91152786d --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.scss @@ -0,0 +1,33 @@ + +.internal-table{ + margin-left: 1em; + padding-left: 0.2rem; + +} +.table-entry{ + + text-overflow: ellipsis; + overflow: hidden; + padding-left: 0.2rem; + color: rgba(0, 0, 0, 0.54); + transition: color 100ms; + + display: block; + span{ + white-space: nowrap; + } +} + +.table-entry:hover{ + background-color: #ececec; + border-radius: 6px; +} +.selected { + color: #212121 !important; + font-weight: 700 !important; + opacity: 1 !important; +} + +.section{ + line-height: 1.7em; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts new file mode 100644 index 000000000..0e57e3849 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents-internal/table-of-contents-internal.ts @@ -0,0 +1,142 @@ +import { DOCUMENT } from '@angular/common'; +import { Component, EventEmitter, Inject, OnInit, Output, Input } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { interval, Subject, Subscription } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; +import { type } from 'os'; +import { SimpleChanges } from '@angular/core'; +import { ToCEntry, ToCEntryType } from '../../dataset-description.component'; +import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; + +@Component({ + selector: 'table-of-contents-internal', + styleUrls: ['./table-of-contents-internal.scss'], + templateUrl: './table-of-contents-internal.html' +}) +export class TableOfContentsInternal implements OnInit { + + @Input() tocentries: ToCEntry[] = null; + @Input() selected: ToCEntry = null; + // @Input() visibilityRules:Rule[] = []; + @Output() entrySelected = new EventEmitter(); + + expandChildren:boolean[]; + tocEntryTypeEnum = ToCEntryType; + @Input() TOCENTRY_ID_PREFIX=""; + @Input() showErrors: boolean = false; + + + constructor(public visibilityRulesService: VisibilityRulesService){ + + + } + ngOnInit(): void { + // console.log('component created'); + if(this.tocentries){ + this.expandChildren = this.tocentries.map(()=>false); + if(this.selected){ + for(let i=0; i 0) { + // this.links.forEach(link => { + // link.selected = false; + // }) + // this.links[0].selected = true; + // } + } + + toggleExpand(index){ + this.expandChildren[index] = !this.expandChildren[index]; + // console.log(this.expandChildren); + } + + navigateToFieldSet(entry:ToCEntry, event){ + if(entry.type === ToCEntryType.FieldSet){ + + const fieldSetId = entry.id; + const element = document.getElementById(this.TOCENTRY_ID_PREFIX+fieldSetId); + if(element){ + element.click();//open mat expansion panel + + //scroll asyn in 200 ms so the expansion panel is expanded and the element coordinates are updated + setTimeout(() => { + const element = document.getElementById(this.TOCENTRY_ID_PREFIX+fieldSetId); + if(element){ + element.scrollIntoView({behavior:'smooth'}); + } + }, 300); + } + + } + } + + + onEntrySelected(entry:ToCEntry){ + this.entrySelected.emit(entry); + } + + + calculateStyle(entry: ToCEntry){ + const style = {}; + style['font-size'] = entry.type ===this.tocEntryTypeEnum.FieldSet? '.9em': '1em'; + return style; + } + + calculateClass(entry:ToCEntry){ + const myClass= {}; + + if(this.selected && entry.id === this.selected.id){ + myClass['selected'] = true; + } + + if(entry.type != this.tocEntryTypeEnum.FieldSet){ + myClass['section'] = true; + } + + return myClass; + } + + private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry{ + if(!tocentries || !tocentries.length){ + 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; + } + } + + return tocEntryFound? tocEntryFound: null; + } +} diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.html index b91593ca0..75ae05935 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.html @@ -9,3 +9,31 @@
    + + + +
    + +
    + + + +
    +
    \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module.ts index b28ec7804..69a648f1a 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module.ts @@ -2,11 +2,15 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {TableOfContents} from './table-of-contents'; import {RouterModule} from '@angular/router'; +import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal'; +import { VisibilityRulesService } from '../visibility-rules/visibility-rules.service'; +import { MatIconModule } from '@angular/material'; @NgModule({ - imports: [CommonModule, RouterModule], - declarations: [TableOfContents], + imports: [CommonModule, RouterModule, MatIconModule], + declarations: [TableOfContents, TableOfContentsInternal], exports: [TableOfContents], entryComponents: [TableOfContents], + providers:[VisibilityRulesService] }) export class TableOfContentsModule { } diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.scss b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.scss index b346518fa..7dbc877af 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.scss +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.scss @@ -68,3 +68,13 @@ span { .docs-level-h5 { margin-left: 24px; } + +// .internal-table-outer{ +// padding-left: 1.1em; +// width: 100%; +// } + +.internal-table{ + max-width: 320px; + min-width: 320px; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts index 917a80f55..ce1616a93 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.ts @@ -1,10 +1,14 @@ import { DOCUMENT } from '@angular/common'; -import { Component, EventEmitter, Inject, OnInit, Output, Input } from '@angular/core'; +import { Component, EventEmitter, Inject, OnInit, Output, Input, OnChanges } from '@angular/core'; import { BaseComponent } from '@common/base/base.component'; import { interval, Subject, Subscription } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; import { type } from 'os'; import { SimpleChanges } from '@angular/core'; +import { ToCEntry, ToCEntryType } from '../dataset-description.component'; +import { FormArray, FormGroup } from '@angular/forms'; +import { VisibilityRulesService } from '../visibility-rules/visibility-rules.service'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; export interface Link { /* id of the section*/ @@ -28,7 +32,7 @@ export interface Link { styleUrls: ['./table-of-contents.scss'], templateUrl: './table-of-contents.html' }) -export class TableOfContents extends BaseComponent implements OnInit { +export class TableOfContents extends BaseComponent implements OnInit, OnChanges { @Input() links: Link[]; container: string; @@ -39,77 +43,112 @@ export class TableOfContents extends BaseComponent implements OnInit { linksSubject: Subject = new Subject(); @Input() isActive: boolean; + + tocentries: ToCEntry[] = null; + @Input() TOCENTRY_ID_PREFIX = ''; + // visibilityRules:Rule[] = []; + @Input() visibilityRules:Rule[] = []; + @Input() showErrors: boolean = false; + @Input() selectedFieldsetId:string; + + private _tocentrySelected:ToCEntry = null; + get tocentrySelected(){ + + return this.hasFocus?this._tocentrySelected: null; + } + set tocentrySelected(value){ + this._tocentrySelected = value; + } + + @Input() formGroup: FormGroup; + @Input() hasFocus: boolean = false; show: boolean = false; constructor( - @Inject(DOCUMENT) private _document: Document) { + @Inject(DOCUMENT) private _document: Document, + public visibilityRulesService: VisibilityRulesService + ) { super(); } ngOnInit(): void { - //emit value every 500ms - const source = interval(500); - this.subscription = source.subscribe(val => { - const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[]; - this.linksSubject.next(headers); - }); + + if(this.formGroup){ + this.tocentries = this.getTocEntries(this.formGroup.get('datasetProfileDefinition')); + const fg = this.formGroup.get('datasetProfileDefinition'); + this.visibilityRulesService.buildVisibilityRules(this.visibilityRules, fg); + + }else{ + + //emit value every 500ms + const source = interval(500); + this.subscription = source.subscribe(val => { + const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[]; + this.linksSubject.next(headers); + }); - if (!this.links || this.links.length === 0) { - this.linksSubject.asObservable() - .pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q))) - .subscribe(headers => { - const links: Array = []; + if (!this.links || this.links.length === 0) { + this.linksSubject.asObservable() + .pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q))) + .subscribe(headers => { + const links: Array = []; - if (headers.length) { - let page; - let section; - let show - for (const header of headers) { - let name; - let id; - if (header.classList.contains('toc-page-header')) { // deprecated after removing stepper - name = header.innerText.trim().replace(/^link/, ''); - id = header.id; - page = header.id.split('_')[1]; - section = undefined; - show = true; - } else if (header.classList.contains('toc-section-header')) { - name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue.trim().replace(/^link/, ''); - id = header.id; - page = header.id.split('.')[1]; - section = header.id; - if (header.id.split('.')[4]) { show = false; } - else { show = true; } - } else if (header.classList.contains('toc-compositeField-header')) { - name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, ''); - id = header.id; - // id = header.parentElement.parentElement.parentElement.id; - show = false; + if (headers.length) { + let page; + let section; + let show + for (const header of headers) { + let name; + let id; + if (header.classList.contains('toc-page-header')) { // deprecated after removing stepper + name = header.innerText.trim().replace(/^link/, ''); + id = header.id; + page = header.id.split('_')[1]; + section = undefined; + show = true; + } else if (header.classList.contains('toc-section-header')) { + name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue.trim().replace(/^link/, ''); + id = header.id; + page = header.id.split('.')[1]; + section = header.id; + if (header.id.split('.')[4]) { show = false; } + else { show = true; } + } else if (header.classList.contains('toc-compositeField-header')) { + name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, ''); + id = header.id; + // id = header.parentElement.parentElement.parentElement.id; + show = false; + } + const { top } = header.getBoundingClientRect(); + links.push({ + name, + id, + type: header.tagName.toLowerCase(), + top: top, + active: false, + page: page, + section: section, + show: show, + selected: false + }); } - const { top } = header.getBoundingClientRect(); - links.push({ - name, - id, - type: header.tagName.toLowerCase(), - top: top, - active: false, - page: page, - section: section, - show: show, - selected: false - }); } - } - this.links = links; - // Initialize selected for button next on dataset wizard component editor - this.links.length > 0 ? this.links[0].selected = true : null; - }) + this.links = links; + // Initialize selected for button next on dataset wizard component editor + this.links.length > 0 ? this.links[0].selected = true : null; + }) + } } } ngOnChanges(changes: SimpleChanges) { + + if(this.selectedFieldsetId){ + this.tocentrySelected = this._findTocEntryById(this.selectedFieldsetId,this.tocentries); + } + // if (!this.isActive && this.links && this.links.length > 0) { // this.links.forEach(link => { // link.selected = false; @@ -158,6 +197,153 @@ export class TableOfContents extends BaseComponent implements OnInit { // return +link.id.split("_", 2)[1]; // } + + private _buildRecursively(form: FormGroup,whatAmI:ToCEntryType):ToCEntry{ + if(!form) return null; + + switch(whatAmI){ + case ToCEntryType.Section: + const sections = form.get('sections') as FormArray; + const fieldsets = form.get('compositeFields') as FormArray; + + + const tempResult:ToCEntry[] = []; + + if(sections &§ions.length){ + sections.controls.forEach(section=>{ + tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); + }); + + }else if(fieldsets && fieldsets.length){ + fieldsets.controls.forEach(fieldset=>{ + tempResult.push(this._buildRecursively(fieldset as FormGroup, ToCEntryType.FieldSet)); + }); + } + return { + form: form, + id: form.get('id').value, + label: form.get('title').value, + numbering: '', + subEntries:tempResult, + subEntriesType: sections &§ions.length? ToCEntryType.Section: ToCEntryType.FieldSet, + type: ToCEntryType.Section, + ordinal: form.get('ordinal').value + } + case ToCEntryType.FieldSet: + return { + form: form, + label:form.get('title').value, + id: form.get('id').value, + numbering:'s', + subEntries:[], + subEntriesType: ToCEntryType.Field, + type: ToCEntryType.FieldSet, + ordinal: form.get('ordinal').value + } + } + } + + private _sortByOrdinal(tocentries: ToCEntry[]){ + + if(!tocentries || !tocentries.length) return; + + tocentries.sort(this._customCompare); + tocentries.forEach(entry=>{ + this._sortByOrdinal(entry.subEntries); + }); + } + + private _customCompare(a,b){ + return a.ordinal - b.ordinal; + } + + private _calculateNumbering(tocentries: ToCEntry[], depth:number[] = []){ + if(!tocentries || !tocentries.length){ + return; + } + + let prefixNumbering = depth.length? depth.join('.'): ''; + + if(depth.length) prefixNumbering = prefixNumbering+"."; + tocentries.forEach((entry,i)=>{ + entry.numbering = prefixNumbering + (i+1); + this._calculateNumbering(entry.subEntries, [...depth, i+1]) + }); + } + + + getTocEntries(form): ToCEntry[] { + if (form == null) { return []; } + const result: ToCEntry[] = []; + + //build parent pages + (form.get('pages') as FormArray).controls.forEach((pageElement, i) => { + result.push({ + id: i+'id', + label: pageElement.get('title').value, + type: ToCEntryType.Page, + form: pageElement, + numbering: (i + 1).toString(), + subEntriesType: ToCEntryType.Section, + subEntries:[], + ordinal: pageElement.get('ordinal').value + } as ToCEntry) + }); + + + + result.forEach((entry,i)=>{ + + const sections = entry.form.get('sections') as FormArray; + + sections.controls.forEach(section=>{ + const tempResults = this._buildRecursively(section as FormGroup,ToCEntryType.Section); + entry.subEntries.push(tempResults); + }); + + }); + + this._sortByOrdinal(result); + //calculate numbering + this._calculateNumbering(result); + return result; + + } + + onToCentrySelected(entry: ToCEntry){ + this.tocentrySelected = entry; + // console.log('entry selected', entry); + } + + + public seekToFirstElement(){//only on tocentry mode + if(this.tocentries && this.tocentries.length){ + this.tocentrySelected = this.tocentries[0]; + } + } + + private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry{ + if(!tocentries || !tocentries.length){ + 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; + } + } + + return tocEntryFound? tocEntryFound: null; + } + } export interface LinkToScroll { diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts index 7c77b16af..9460af83d 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts @@ -1,5 +1,6 @@ import { ApplicationRef, Injectable, NgZone } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms'; +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; import { isNumeric } from 'rxjs/internal/util/isNumeric'; import { Rule } from '../../../../core/model/dataset-profile-definition/rule'; import { VisibilityRule } from './models/visibility-rule'; @@ -38,6 +39,22 @@ export class VisibilityRulesService { } private evaluateVisibility(visibilityRule: VisibilityRule, value: any) { + + if (value instanceof Array){ + + const parsedSourceControlValues = visibilityRule.sourceVisibilityRules.map(e=>this.parseValue(e.sourceControlValue)); + const parsedValues = value.map(e=>this.parseValue(e)); + + const isVisible = parsedValues.map(v=>parsedSourceControlValues.includes(v)).reduce((acc,current)=> acc|| current, false); + + + if(isVisible){ + this.elementVisibilityMap.set(visibilityRule.targetControlId, true); + return; + } + + } + for (let i = 0; i < visibilityRule.sourceVisibilityRules.length; i++) { if (value != null && (this.parseValue(value) !== this.parseValue(visibilityRule.sourceVisibilityRules[i].sourceControlValue))) { this.elementVisibilityMap.set(visibilityRule.targetControlId, false); @@ -123,7 +140,13 @@ export class VisibilityRulesService { } private resetFieldFormGroup(formGroup: FormGroup) { - formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined); + const renderStyle = formGroup.getRawValue().viewStyle.renderStyle; + if(renderStyle ===DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier){ + formGroup.get('value').setValue({identifier:'',type:'' }); + }else{ + formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined); + } + } private resetCompositeFieldFormGroup(formGroup: FormGroup) { diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 4df4feb0c..d5f969740 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -2,7 +2,7 @@