error models and profile pages bug fixes

This commit is contained in:
Diamantis Tziotzios 2019-01-21 13:14:20 +02:00
parent 41fb94eee9
commit 9d11adbcbd
59 changed files with 386 additions and 438 deletions

View File

@ -60,5 +60,4 @@ public final class PrincipalArgumentResolver implements HandlerMethodArgumentRes
dt = c.getTime();
return dt;
}
}

View File

@ -80,6 +80,13 @@ const appRoutes: Routes = [
breadcrumb: true
},
},
{
path: 'profile',
loadChildren: './ui/user-profile/user-profile.module#UserProfileModule',
data: {
breadcrumb: true
},
},
{
path: 'login',
loadChildren: './ui/auth/login/login.module#LoginModule',

View File

@ -25,7 +25,9 @@ export class UnauthorizedResponseInterceptor extends BaseInterceptor {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 401:
return this.handle401Error(req, next);
this.logoutUser();
return throwError(error);
//return this.handle401Error(req, next);
default:
return throwError(error);
}
@ -35,20 +37,20 @@ export class UnauthorizedResponseInterceptor extends BaseInterceptor {
}));
}
private handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.accountRefresh$) {
// this.accountRefresh$ = this.idpService.refreshToken().pipe(
// tap(account => {
// this.accountRefresh$ = null;
// if (!account) { throw throwError('missing_authentication_token'); }
// }),
// catchError(error => {
// this.logoutUser();
// return throwError(error);
// }));
}
return this.accountRefresh$.pipe(mergeMap(account => this.repeatRequest(account, req, next)));
}
// private handle401Error(req: HttpRequest<any>, next: HttpHandler) {
// if (!this.accountRefresh$) {
// this.accountRefresh$ = this.authService.refreshToken().pipe(
// tap(account => {
// this.accountRefresh$ = null;
// if (!account) { throw throwError('missing_authentication_token'); }
// }),
// catchError(error => {
// this.logoutUser();
// return throwError(error);
// }));
// }
// return this.accountRefresh$.pipe(mergeMap(account => this.repeatRequest(account, req, next)));
// }
private repeatRequest(account: Account, originalRequest: HttpRequest<any>, next: HttpHandler) {
const newAuthenticationToken: String = this.authService.current().token;

View File

@ -8,6 +8,7 @@ import { CultureService } from './services/culture/culture-service';
import { DashboardService } from './services/dashboard/dashboard.service';
import { DatasetProfileService } from './services/dataset-profile/dataset-profile.service';
import { DatasetWizardService } from './services/dataset-wizard/dataset-wizard.service';
import { DatasetExternalAutocompleteService } from './services/dataset/dataset-external-autocomplete.service';
import { DatasetService } from './services/dataset/dataset.service';
import { DmpInvitationService } from './services/dmp/dmp-invitation.service';
import { DmpProfileService } from './services/dmp/dmp-profile.service';
@ -79,7 +80,8 @@ export class CoreServiceModule {
ExternalServiceService,
DatasetProfileService,
UserService,
DmpInvitationService
DmpInvitationService,
DatasetExternalAutocompleteService
],
};
}

View File

@ -1,6 +1,7 @@
import { DatePipe } from '@angular/common';
import { NgModule } from '@angular/core';
import { NgForLimitPipe } from './pipes/ng-for-limit.pipe';
import { TimezoneInfoDisplayPipe } from './pipes/timezone-info-display.pipe';
import { EnumUtils } from './services/utilities/enum-utils.service';
//
@ -11,15 +12,18 @@ import { EnumUtils } from './services/utilities/enum-utils.service';
@NgModule({
declarations: [
NgForLimitPipe
NgForLimitPipe,
TimezoneInfoDisplayPipe
],
exports: [
NgForLimitPipe
NgForLimitPipe,
TimezoneInfoDisplayPipe
],
providers: [
EnumUtils,
DatePipe,
NgForLimitPipe
NgForLimitPipe,
TimezoneInfoDisplayPipe
]
})
export class FormattingModule { }

View File

@ -1,7 +1,7 @@
import { AppRole } from "../../common/enum/app-role";
export interface Principal {
id: number;
id: string;
token: string;
name: string;
expiresAt: Date;

View File

@ -27,7 +27,7 @@ export interface DatasetProfileModel {
// createValidationContext(): ValidationContext {
// const baseContext: ValidationContext = new ValidationContext();
// //baseContext.validation.push({ key: 'id', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'id')] });
// //baseContext.validation.push({ key: 'id', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'id')] });
// return baseContext;
// }
// }

View File

@ -24,7 +24,7 @@ export interface DatasetModel {
// public registries: RegistryModel[] = [];
// public dataRepositories: DataRepositoryModel[] = [];
// public errorModel: ValidationErrorModel = new ValidationErrorModel();
// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
// fromJSONObject(item: any): DatasetModel {
// this.id = item.id;
@ -59,14 +59,14 @@ export interface DatasetModel {
// createValidationContext(): ValidationContext {
// const baseContext: ValidationContext = new ValidationContext();
// baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
// baseContext.validation.push({ key: 'profile', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'profile')] });
// baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.errorModel, 'uri')] });
// baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'status')] });
// baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.errorModel, 'description')] });
// baseContext.validation.push({ key: 'services', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'services')] });
// baseContext.validation.push({ key: 'registries', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'registries')] });
// baseContext.validation.push({ key: 'dataRepositories', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'dataRepositories')] });
// baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
// baseContext.validation.push({ key: 'profile', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'profile')] });
// baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.validationErrorModel, 'uri')] });
// baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] });
// baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] });
// baseContext.validation.push({ key: 'services', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'services')] });
// baseContext.validation.push({ key: 'registries', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'registries')] });
// baseContext.validation.push({ key: 'dataRepositories', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'dataRepositories')] });
// return baseContext;
// }

View File

@ -0,0 +1,6 @@
import { BaseCriteria } from "../base-criteria";
export class DatasetExternalAutocompleteCriteria extends BaseCriteria {
public profileID: String;
public fieldID: String;
}

View File

@ -0,0 +1,28 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } 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';
@Injectable()
export class DatasetExternalAutocompleteService {
private actionUrl: string;
constructor(
private httpClient: HttpClient,
private datasetProfileService: DatasetProfileService) {
this.actionUrl = environment.Server + 'datasetwizard/';
}
getDatasetProfileById(datasetProfileID) {
return this.datasetProfileService.getDatasetProfileById(datasetProfileID);
}
queryAutocomplete(lookUpItem: RequestItem<DatasetExternalAutocompleteCriteria>): Observable<any> {
return this.httpClient.post(environment.Server + 'search/autocomplete', lookUpItem);
}
}

View File

@ -22,23 +22,23 @@ export class EnumUtils {
convertFromPrincipalAppRole(status: AppRole): string {
switch (status) {
case AppRole.Admin: return 'TYPES.APP-ROLE.ADMIN';
case AppRole.User: return 'TYPES.APP-ROLE.USER';
case AppRole.Manager: return 'TYPES.APP-ROLE.MANAGER';
case AppRole.Admin: return this.language.instant('TYPES.APP-ROLE.ADMIN');
case AppRole.User: return this.language.instant('TYPES.APP-ROLE.USER');
case AppRole.Manager: return this.language.instant('TYPES.APP-ROLE.MANAGER');
}
}
toDmpProfileFieldDataTypeString(type: DmpProfileFieldDataType): string {
switch (type) {
case DmpProfileFieldDataType.Date: return 'TYPES.DMP-PROFILE-FIELD.DATA-TYPE.DATE';
case DmpProfileFieldDataType.Number: return 'TYPES.DMP-PROFILE-FIELD.DATA-TYPE.NUMBER';
case DmpProfileFieldDataType.Text: return 'TYPES.DMP-PROFILE-FIELD.DATA-TYPE.TEXT';
case DmpProfileFieldDataType.Date: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.DATE');
case DmpProfileFieldDataType.Number: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.NUMBER');
case DmpProfileFieldDataType.Text: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.TEXT');
}
}
toDmpProfileTypeString(type: DmpProfileType): string {
switch (type) {
case DmpProfileType.Input: return 'TYPES.DMP-PROFILE-FIELD.TYPE.INPUT';
case DmpProfileType.Input: return this.language.instant('TYPES.DMP-PROFILE-FIELD.TYPE.INPUT');
}
}

View File

@ -5,7 +5,6 @@
<mat-form-field>
<input matInput placeholder=" {{'CRITERIA.DATASET-PROFILE.LIKE'| translate}}" name="datasetProfileLike"
[(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['Criteria.like']}}</mat-error>
</mat-form-field>
</div>
</div>

View File

@ -4,9 +4,6 @@
<app-dataset-profile-criteria-component></app-dataset-profile-criteria-component>
<mat-card class="mat-card">
<mat-card-header>
<mat-progress-bar *ngIf="dataSource?.isLoadingResults" mode="query"></mat-progress-bar>
</mat-card-header>
<mat-table [dataSource]="dataSource" matSort (matSortChange)="refresh()">
<!-- Column Definition: Name -->

View File

@ -5,12 +5,12 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BaseComponent } from '../../../../core/common/base/base.component';
import { DataTableRequest } from '../../../../core/model/data-table/data-table-request';
import { DatasetListingModel } from '../../../../core/model/dataset/dataset-listing';
import { DmpModel } from '../../../../core/model/dmp/dmp';
import { DatasetProfileCriteria } from '../../../../core/query/dataset-profile/dataset-profile-criteria';
import { DatasetProfileService } from '../../../../core/services/dataset-profile/dataset-profile.service';
import { DmpService } from '../../../../core/services/dmp/dmp.service';
import { DataTableRequest } from '../../../../core/model/data-table/data-table-request';
import { DatasetProfileCriteriaComponent } from './criteria/dataset-profile.component';
@Component({
@ -89,7 +89,6 @@ export class DatasetProfileListingComponent extends BaseComponent implements OnI
export class DatasetDataSource extends DataSource<DatasetListingModel> {
totalCount = 0;
isLoadingResults = false;
constructor(
private _service: DatasetProfileService,
@ -110,9 +109,6 @@ export class DatasetDataSource extends DataSource<DatasetListingModel> {
return Observable.merge(...displayDataChanges)
.startWith(null)
.switchMap(() => {
setTimeout(() => {
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
let fields: Array<string> = new Array();
if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; }
@ -130,9 +126,6 @@ export class DatasetDataSource extends DataSource<DatasetListingModel> {
return Observable.of(null);
})*/
.map(result => {
setTimeout(() => {
this.isLoadingResults = false;
});
return result;
})
.map(result => {

View File

@ -13,7 +13,7 @@
<div class="row">
<mat-form-field class="col-12">
<input matInput placeholder="{{'DMP-PROFILE-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -23,7 +23,7 @@
<mat-form-field class="col">
<input matInput placeholder="{{'DMP-PROFILE-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" [formControl]="fieldFormGroup.get('label')" required>
<mat-error *ngIf="fieldFormGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('label').hasError('backendError')">{{fieldFormGroup.get('label').getError('backendError').message}}</mat-error>
</mat-form-field>
<mat-form-field class="col">
<mat-select placeholder="{{'DMP-PROFILE-EDITOR.FIELDS.TYPE' | translate}}" [formControl]="fieldFormGroup.get('type')" required>
@ -31,7 +31,7 @@
getDMPProfileFieldTypeWithLanguage(fieldType) | translate}}</mat-option>
</mat-select>
<mat-error *ngIf="fieldFormGroup.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('type').hasError('backendError')">{{baseErrorModel.type}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('type').hasError('backendError')">{{fieldFormGroup.get('type').getError('backendError').message}}</mat-error>
</mat-form-field>
<mat-form-field class="col">
<mat-select placeholder="{{'DMP-PROFILE-EDITOR.FIELDS.DATATYPE' | translate}}" [formControl]="fieldFormGroup.get('dataType')" required>
@ -39,7 +39,7 @@
getDMPProfileFieldDataTypeWithLanguage(fieldDataType) | translate}}</mat-option>
</mat-select>
<mat-error *ngIf="fieldFormGroup.get('dataType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('dataType').hasError('backendError')">{{baseErrorModel.dataType}}</mat-error>
<mat-error *ngIf="fieldFormGroup.get('dataType').hasError('backendError')">{{fieldFormGroup.get('dataType').getError('backendError').message}}</mat-error>
</mat-form-field>
<div class="centered-row-item col-auto">
<mat-checkbox [formControl]="fieldFormGroup.get('required')">{{'DMP-PROFILE-EDITOR.FIELDS.REQUIRED' | translate}}</mat-checkbox>

View File

@ -5,6 +5,7 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators';
import { environment } from '../../../../../environments/environment';
import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model';
import { BaseComponent } from '../../../../core/common/base/base.component';
import { DmpProfileFieldDataType } from '../../../../core/common/enum/dmp-profile-field-type';
import { DmpProfileType } from '../../../../core/common/enum/dmp-profile-type';
@ -25,7 +26,6 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
dmpProfileModel: DmpProfileEditorModel;
formGroup: FormGroup = null;
host = environment.Server;
baseErrorModel: BaseErrorModel;
constructor(
private dmpProfileService: DmpProfileService,
@ -50,13 +50,10 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.dmpProfileModel = new DmpProfileEditorModel().fromModel(data);
//this.baseErrorModel = this.dmpProfileModel.errorModel;
this.formGroup = this.dmpProfileModel.buildForm();
});
} else {
this.dmpProfileModel = new DmpProfileEditorModel();
//this.baseErrorModel = this.dmpProfileModel.errorModel;
setTimeout(() => {
this.formGroup = this.dmpProfileModel.buildForm();
});
@ -96,10 +93,10 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie
this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: BaseErrorModel) {
// Object.keys(errorModel).forEach(item => {
// (<any>this.dmpProfileModel.errorModel)[item] = (<any>errorModel)[item];
// });
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.dmpProfileModel.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}
public cancel(): void {

View File

@ -13,7 +13,7 @@ export class DmpProfileEditorModel {
public status: number;
public created: Date;
public modified: Date;
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: DmpProfile): DmpProfileEditorModel {
this.id = item.id;

View File

@ -3,7 +3,6 @@
<div class="row">
<mat-form-field class="col-md-6">
<input matInput placeholder=" {{'CRITERIA.DMP.LIKE'| translate}}" name="projectCriteriaLike" [(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['Criteria.like']}}</mat-error>
</mat-form-field>
</div>
</mat-card>

View File

@ -2,11 +2,11 @@
<mat-card class="mat-card">
<div class="row">
<mat-form-field class="col-sm-6 col-md-8">
<input matInput placeholder="{{'CRITERIA.USERS.LABEL'| translate}}" formControlName="like" (ngModelChange)="controlModified()">
<input matInput placeholder="{{'CRITERIA.USERS.LABEL'| translate}}" formControlName="like">
</mat-form-field>
<mat-form-field class="col-sm-6 col-md-4">
<mat-select placeholder="{{'CRITERIA.USERS.ROLE' | translate}}" formControlName="appRoles" (change)="controlModified()" multiple>
<mat-option *ngFor="let role of getPrincipalAppRoleValues()" [value]="role">{{getPrincipalAppRoleWithLanguage(role)}}</mat-option>
<mat-select placeholder="{{'CRITERIA.USERS.ROLE' | translate}}" formControlName="appRoles" multiple>
<mat-option *ngFor="let role of rolesEnum" [value]="role">{{enumUtils.convertFromPrincipalAppRole(role)}}</mat-option>
</mat-select>
</mat-form-field>
</div>

View File

@ -1,9 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { ValidationErrorModel } from '../../../../../common/forms/validation/error-model/validation-error-model';
import { Validation, ValidationContext } from '../../../../../common/forms/validation/validation-context';
import { AppRole } from '../../../../../core/common/enum/app-role';
import { UserCriteria } from '../../../../../core/query/user/user-criteria';
import { EnumUtils } from '../../../../../core/services/utilities/enum-utils.service';
@ -16,13 +14,12 @@ import { BaseCriteriaComponent } from '../../../../misc/criteria/base-criteria.c
})
export class UserCriteriaComponent extends BaseCriteriaComponent implements OnInit {
public role: AppRole;
public rolesEnum = this.enumUtils.getEnumValues(AppRole);
public criteria: UserCriteria = new UserCriteria();
constructor(
private language: TranslateService,
private formBuilder: FormBuilder,
private enumUtils: EnumUtils
public enumUtils: EnumUtils
) {
super(new ValidationErrorModel());
}
@ -31,13 +28,20 @@ export class UserCriteriaComponent extends BaseCriteriaComponent implements OnIn
super.ngOnInit();
if (this.criteria == null) { this.criteria = new UserCriteria(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
this.registerListeners();
}
setCriteria(criteria: UserCriteria): void {
this.criteria = criteria;
this.formGroup = this.buildForm();
this.registerListeners();
}
registerListeners() {
this.formGroup.valueChanges
.pipe(takeUntil(this._destroyed), debounceTime(300))
.subscribe(x => this.controlModified());
}
public fromJSONObject(item: any): UserCriteria {
this.criteria = new UserCriteria();
this.criteria.label = item.Label;
@ -46,40 +50,9 @@ export class UserCriteriaComponent extends BaseCriteriaComponent implements OnIn
}
buildForm(): FormGroup {
const context: ValidationContext = this.createValidationContext();
return this.formBuilder.group({
like: [this.criteria.label, context.getValidation('label').validators],
appRoles: [this.criteria.appRoles, context.getValidation('appRoles').validators],
like: [this.criteria.label, []],
appRoles: [this.criteria.appRoles, []],
});
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
validationArray.push({ key: 'label' });
validationArray.push({ key: 'appRoles' });
validationContext.validation = validationArray;
return validationContext;
}
getPrincipalAppRoleValues(): Number[] {
let keys: string[] = Object.keys(AppRole);
keys = keys.slice(0, keys.length / 2);
const values: Number[] = keys.map(Number);
return values;
}
getPrincipalAppRoleWithLanguage(role: AppRole): string {
let result = '';
this.language.get(this.enumUtils.convertFromPrincipalAppRole(role))
.pipe(takeUntil(this._destroyed))
.subscribe((value: string) => {
result = value;
});
return result;
}
}

View File

@ -21,7 +21,6 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit {
@Input() public item: UserListingModel;
public formGroup: FormGroup = null;
public nowEditing = false;
//public errorModel: UserErrorModel;
constructor(
private language: TranslateService,
@ -32,7 +31,6 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit {
) { super(); }
ngOnInit() {
// if (this.errorModel == null) { this.errorModel = new UserErrorModel(); }
if (this.formGroup == null) { this.formGroup = this.buildForm(); }
}
@ -55,7 +53,6 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit {
}
formSubmit(): void {
this.clearErrorModel();
const modifiedItem = this.item;
modifiedItem.appRoles = this.getFormControl('appRoles').value;
@ -118,18 +115,6 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit {
}
}
setErrorModel(errorModel: any) {
// Object.keys(errorModel).forEach(item => {
// (<any>this.errorModel)[item] = (<any>errorModel)[item];
// });
}
clearErrorModel() {
// Object.keys(this.errorModel).forEach(item => {
// (<any>this.errorModel)[item] = '';
// });
}
onCallbackSuccess() {
this.nowEditing = false;
this.formGroup.disable();
@ -139,7 +124,6 @@ export class UserRoleEditorComponent extends BaseComponent implements OnInit {
});
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
this.validateAllFormFields(this.formGroup);
this.snackBar.openFromComponent(SnackBarNotificationComponent, {
data: { message: 'GENERAL.SNACK-BAR.UNSUCCESSFUL-UPDATE', language: this.language },

View File

@ -16,7 +16,7 @@ import { AuthService } from '../../../core/services/auth/auth.service';
export class AdminLoginComponent extends BaseComponent implements OnInit {
public auth2: any;
public credential: Credential = new Credential();
public credential: Credential;
constructor(
private authService: AuthService,

View File

@ -9,6 +9,9 @@ import { LoginService } from './utilities/login.service';
/// <reference types="gapi" />
/// <reference types="facebook-js-sdk" />
declare const gapi: any;
declare const FB: any;
@Component({
selector: 'app-login',
templateUrl: './login.component.html',

View File

@ -68,9 +68,7 @@ export class DashboardComponent extends BaseComponent implements OnInit {
// filterFn: this.searchProject.bind(this),
// items: this.searchProject(''),
// displayFn: (item) => item['label'],
// titleFn: (item) => item['label'],
// //mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
// loadDataOnStart: true
// titleFn: (item) => item['label']
// };
if (!this.isAuthenticated()) {

View File

@ -1,17 +1,17 @@
<div class=" row dataset-editor" [formGroup]="formGroup">
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{baseErrorModel.uri}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<textarea matInput class="description-area" placeholder="{{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>

View File

@ -27,7 +27,7 @@ export class DatasetWizardEditorModel {
public externalDatasets: ExternalDatasetEditorModel[] = [];
public dmp: DmpModel;
public datasetProfileDefinition: DatasetDescriptionFormEditorModel;
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: DatasetWizardModel): DatasetWizardEditorModel {
this.id = item.id;
@ -122,20 +122,19 @@ export class DatasetWizardEditorModel {
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.errorModel, 'id')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
baseContext.validation.push({ key: 'profile', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'profile')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.errorModel, 'uri')] });
baseContext.validation.push({ key: 'status', validators: [BackendErrorValidator(this.errorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.errorModel, 'description')] });
baseContext.validation.push({ key: 'services', validators: [BackendErrorValidator(this.errorModel, 'services')] });
baseContext.validation.push({ key: 'registries', validators: [BackendErrorValidator(this.errorModel, 'registries')] });
baseContext.validation.push({ key: 'dataRepositories', validators: [BackendErrorValidator(this.errorModel, 'dataRepositories')] });
baseContext.validation.push({ key: 'externalDatasets', validators: [BackendErrorValidator(this.errorModel, 'externalDatasets')] });
baseContext.validation.push({ key: 'dmp', validators: [BackendErrorValidator(this.errorModel, 'dmp')] }); //TODO
baseContext.validation.push({ key: 'datasetProfileDefinition', validators: [BackendErrorValidator(this.errorModel, 'datasetProfileDefinition')] }); //TODO
baseContext.validation.push({ key: 'tags', validators: [BackendErrorValidator(this.errorModel, 'datasetProfileDefinition')] }); //TODO
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'profile', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'profile')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.validationErrorModel, 'uri')] });
baseContext.validation.push({ key: 'status', validators: [BackendErrorValidator(this.validationErrorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'services', validators: [BackendErrorValidator(this.validationErrorModel, 'services')] });
baseContext.validation.push({ key: 'registries', validators: [BackendErrorValidator(this.validationErrorModel, 'registries')] });
baseContext.validation.push({ key: 'dataRepositories', validators: [BackendErrorValidator(this.validationErrorModel, 'dataRepositories')] });
baseContext.validation.push({ key: 'externalDatasets', validators: [BackendErrorValidator(this.validationErrorModel, 'externalDatasets')] });
baseContext.validation.push({ key: 'dmp', validators: [BackendErrorValidator(this.validationErrorModel, 'dmp')] });
baseContext.validation.push({ key: 'datasetProfileDefinition', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] });
baseContext.validation.push({ key: 'tags', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] });
return baseContext;
}
}
@ -227,7 +226,7 @@ export class ExternalDatasetEditorModel {
public reference: String;
public type: ExternalDatasetType;
public info: String;
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
constructor(id?: string, abbreviation?: string, label?: string, reference?: string, info?: string, type?: ExternalDatasetType) {
this.id = id;

View File

@ -40,7 +40,7 @@
{{profile.label}}
</mat-option>
</mat-select>
<mat-error *ngIf="baseErrorModel?.status">{{baseErrorModel['Criteria.status']}}</mat-error>
<mat-error *ngIf="formGroup.get('profile').hasError('backendError')">{{formGroup.get('profile').getError('backendError').message}}</mat-error>
</mat-form-field>
<app-dataset-editor-component class="col-12" [formGroup]="formGroup"></app-dataset-editor-component>
<div class="col-12">

View File

@ -107,8 +107,7 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, Aft
filterFn: this.searchDmp.bind(this),
initialItems: (extraData) => this.searchDmp(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
loadDataOnStart: true
titleFn: (item) => item['label']
};
const params = this.route.snapshot.params;
@ -304,9 +303,9 @@ export class DatasetWizardComponent extends BaseComponent implements OnInit, Aft
this.setErrorModel(error.error);
}
public setErrorModel(errorModel: ValidationErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.datasetWizardModel.errorModel)[item] = (<any>errorModel)[item];
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.datasetWizardModel.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}

View File

@ -8,7 +8,6 @@
<div class="row">
<mat-form-field class="col-md-4">
<input matInput placeholder=" {{'CRITERIA.PROJECTS.LIKE'| translate}}" name="datasetCriteriaName" [(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel['name']">{{baseErrorModel['Criteria.like']}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-4">
<mat-select placeholder=" {{'CRITERIA.DATA-SETS.STATUS'| translate}}" name="datasetCriteriastatus" [(ngModel)]="criteria.status" (ngModelChange)="controlModified()">
@ -16,7 +15,6 @@
<mat-option [value]="statuses.Draft">{{enumUtils.toDatasetStatusString(statuses.Draft)}}</mat-option>
<mat-option [value]="statuses.Finalized">{{enumUtils.toDatasetStatusString(statuses.Finalized)}}</mat-option>
</mat-select>
<mat-error *ngIf="baseErrorModel['status']">{{baseErrorModel['Criteria.status']}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-4">
<app-multiple-auto-complete name="datasetCriteriaTags" [(ngModel)]="criteria.tags" (ngModelChange)="controlModified()" placeholder="{{'CRITERIA.DATA-SETS.TAGS' | translate}}" [configuration]="tagsAutoCompleteConfiguration"></app-multiple-auto-complete>

View File

@ -59,25 +59,25 @@
<div class="row">
<mat-form-field class="col-md-12">
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-12">
<textarea matInput class="description-area" placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description" required></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-single-auto-complete required='true' [formControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}" [configuration]="projectAutoCompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="formGroup.get('project').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('project').hasError('backendError')">{{formGroup.get('project').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('project').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<!-- <app-dynamic-fields-project [formGroup]="formGroup"></app-dynamic-fields-project> -->
<mat-form-field class="col-md-6">
<app-multiple-auto-complete required='true' [formControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}" [configuration]="profilesAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">{{formGroup.get('profiles').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button matSuffix mat-icon-button type="button" [disabled]="formGroup.get('profiles').disabled" (click)="availableProfiles()">
<mat-icon>view_list</mat-icon>
@ -89,13 +89,13 @@
<mat-form-field class="col-md-6">
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}" [configuration]="organisationsAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">{{formGroup.get('organisations').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-multiple-auto-complete [formControl]="formGroup.get('researchers')" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}" [configuration]="researchersAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('researchers').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('backendError')">{{formGroup.get('researchers').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button matSuffix mat-icon-button [disabled]="formGroup.get('researchers').disabled" type="button" (click)="addResearcher()">
<mat-icon>add_circle</mat-icon>

View File

@ -25,7 +25,6 @@ import { MultipleAutoCompleteConfiguration } from '../../../library/auto-complet
import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration';
import { SnackBarNotificationComponent } from '../../../library/notification/snack-bar/snack-bar-notification.component';
import { RequestItem } from '../../../core/query/request-item';
import { BaseErrorModel } from '../../../models/error/BaseErrorModel';
import { LanguageResolverService } from '../../../services/language-resolver/language-resolver.service';
import { BreadcrumbItem } from '../../misc/breadcrumb/definition/breadcrumb-item';
import { IBreadCrumbComponent } from '../../misc/breadcrumb/definition/IBreadCrumbComponent';
@ -33,6 +32,7 @@ import { AddResearcherComponent } from './add-researcher/add-researcher.componen
import { AvailableProfilesComponent } from './available-profiles/available-profiles.component';
import { DmpEditorModel } from './dmp-editor.model';
import { DmpFinalizeDialogComponent } from './dmp-finalize-dialog/dmp-finalize-dialog.component';
import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model';
@Component({
selector: 'app-dmp-editor-component',
@ -100,34 +100,28 @@ export class DmpEditorComponent extends BaseComponent implements AfterViewInit,
filterFn: this.searchProject.bind(this),
initialItems:(extraData) => this.searchProject(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
titleFn: (item) => item['label']
};
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
titleFn: (item) => item['label']
};
this.organisationsAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
loadDataOnStart: true
titleFn: (item) => item['name']
};
this.researchersAutoCompleteConfiguration = {
filterFn: this.filterResearchers.bind(this),
initialItems: (excludedItems: any[]) => this.filterResearchers('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
loadDataOnStart: true
titleFn: (item) => item['name']
};
if (itemId != null) {
@ -216,9 +210,9 @@ export class DmpEditorComponent extends BaseComponent implements AfterViewInit,
//this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: BaseErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.dmp.errorModel)[item] = (<any>errorModel)[item];
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.dmp.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}

View File

@ -30,7 +30,7 @@ export class DmpEditorModel {
public associatedUsers: UserModel[] = [];
public definition: DmpProfileDefinition;
public dynamicFields: Array<DmpDynamicFieldEditorModel> = [];
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: DmpModel): DmpEditorModel {
this.id = item.id;
@ -80,18 +80,18 @@ export class DmpEditorModel {
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.errorModel, 'id')] });
baseContext.validation.push({ key: 'profile', validators: [BackendErrorValidator(this.errorModel, 'profile')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
baseContext.validation.push({ key: 'groupId', validators: [BackendErrorValidator(this.errorModel, 'groupId')] });
baseContext.validation.push({ key: 'version', validators: [BackendErrorValidator(this.errorModel, 'version')] });
baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'description')] });
baseContext.validation.push({ key: 'project', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.errorModel, 'project')] });
baseContext.validation.push({ key: 'organisations', validators: [BackendErrorValidator(this.errorModel, 'organisations')] });
baseContext.validation.push({ key: 'researchers', validators: [BackendErrorValidator(this.errorModel, 'researchers')] });
baseContext.validation.push({ key: 'profiles', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.errorModel, 'profiles')] });
baseContext.validation.push({ key: 'associatedUsers', validators: [BackendErrorValidator(this.errorModel, 'associatedUsers')] });
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
baseContext.validation.push({ key: 'profile', validators: [BackendErrorValidator(this.validationErrorModel, 'profile')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'groupId', validators: [BackendErrorValidator(this.validationErrorModel, 'groupId')] });
baseContext.validation.push({ key: 'version', validators: [BackendErrorValidator(this.validationErrorModel, 'version')] });
baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'project', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'project')] });
baseContext.validation.push({ key: 'organisations', validators: [BackendErrorValidator(this.validationErrorModel, 'organisations')] });
baseContext.validation.push({ key: 'researchers', validators: [BackendErrorValidator(this.validationErrorModel, 'researchers')] });
baseContext.validation.push({ key: 'profiles', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'profiles')] });
baseContext.validation.push({ key: 'associatedUsers', validators: [BackendErrorValidator(this.validationErrorModel, 'associatedUsers')] });
return baseContext;
}

View File

@ -26,8 +26,7 @@ export class DmpInvitationDialogComponent extends BaseComponent implements OnIni
filterFn: this.filterUsers.bind(this),
initialItems: (excludedItems: any[]) => this.filterUsers('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item.name,
titleFn: (item) => item.name,
loadDataOnStart: true
titleFn: (item) => item.name
};
constructor(

View File

@ -8,7 +8,7 @@
<div class="row">
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="projectCriteriaLike" [formControl]="formGroup.get('like')" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['Criteria.like']}}</mat-error>
<mat-error *ngIf="formGroup.get('like').hasError('backendError')">{{formGroup.get('like').getError('backendError').message}}</mat-error>
</mat-form-field>
<mat-form-field *ngIf="showProject" class="col-md-6">
<app-multiple-auto-complete [formControl]="formGroup.get('projects')" placeholder="{{'CRITERIA.DMP.PROJECTS' | translate}}" [configuration]="projectAutoCompleteConfiguration">

View File

@ -29,9 +29,7 @@ export class DmpCriteriaComponent extends BaseCriteriaComponent implements OnIni
filterFn: this.filterProject.bind(this),
initialItems: (excludedItems: any[]) => this.filterProject('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
titleFn: (item) => item['label']
};
constructor(

View File

@ -30,7 +30,7 @@ export class DmpWizardEditorModel {
public associatedUsers: UserModel[] = [];
public definition: DmpProfileDefinition;
public dynamicFields: Array<DmpDynamicFieldEditorModel> = [];
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: DmpModel): DmpWizardEditorModel {
this.id = item.id;
@ -80,18 +80,18 @@ export class DmpWizardEditorModel {
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.errorModel, 'id')] });
baseContext.validation.push({ key: 'profile', validators: [BackendErrorValidator(this.errorModel, 'profile')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
baseContext.validation.push({ key: 'groupId', validators: [BackendErrorValidator(this.errorModel, 'groupId')] });
baseContext.validation.push({ key: 'version', validators: [BackendErrorValidator(this.errorModel, 'version')] });
baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'description')] });
baseContext.validation.push({ key: 'project', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.errorModel, 'project')] });
baseContext.validation.push({ key: 'organisations', validators: [BackendErrorValidator(this.errorModel, 'organisations')] });
baseContext.validation.push({ key: 'researchers', validators: [BackendErrorValidator(this.errorModel, 'researchers')] });
baseContext.validation.push({ key: 'profiles', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.errorModel, 'profiles')] });
baseContext.validation.push({ key: 'associatedUsers', validators: [BackendErrorValidator(this.errorModel, 'associatedUsers')] });
baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
baseContext.validation.push({ key: 'profile', validators: [BackendErrorValidator(this.validationErrorModel, 'profile')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'groupId', validators: [BackendErrorValidator(this.validationErrorModel, 'groupId')] });
baseContext.validation.push({ key: 'version', validators: [BackendErrorValidator(this.validationErrorModel, 'version')] });
baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'project', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'project')] });
baseContext.validation.push({ key: 'organisations', validators: [BackendErrorValidator(this.validationErrorModel, 'organisations')] });
baseContext.validation.push({ key: 'researchers', validators: [BackendErrorValidator(this.validationErrorModel, 'researchers')] });
baseContext.validation.push({ key: 'profiles', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'profiles')] });
baseContext.validation.push({ key: 'associatedUsers', validators: [BackendErrorValidator(this.validationErrorModel, 'associatedUsers')] });
return baseContext;
}

View File

@ -5,6 +5,7 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model';
import { BaseComponent } from '../../../core/common/base/base.component';
import { DmpModel } from '../../../core/model/dmp/dmp';
import { DmpService } from '../../../core/services/dmp/dmp.service';
@ -83,9 +84,9 @@ export class DmpWizardComponent extends BaseComponent implements OnInit, IBreadC
//this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: any) {
Object.keys(errorModel).forEach(item => {
// (<any>this.dmp.errorModel)[item] = (<any>errorModel)[item];
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.dmp.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}

View File

@ -5,25 +5,25 @@
<div class="row">
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required [attr.disabled]="labelDisabled">
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-single-auto-complete [formControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}" [configuration]="projectAutoCompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="formGroup.get('project').hasError('backendError')">{{baseErrorModel.project}}</mat-error>
<mat-error *ngIf="formGroup.get('project').hasError('backendError')">{{formGroup.get('project').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('project').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-12">
<textarea matInput class="description-area" placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description" required></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-multiple-auto-complete class="col-md-10" [formControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}" [configuration]="profilesAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">{{baseErrorModel.project}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">{{formGroup.get('profiles').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button mat-icon-button matSuffix type="button" (click)="availableProfiles()">
<mat-icon>view_list</mat-icon>
@ -32,14 +32,14 @@
<mat-form-field class="col-md-6">
<app-multiple-auto-complete [formControl]="formGroup.get('organisations')" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}" [configuration]="organisationsAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">{{baseErrorModel.organisations}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('backendError')">{{formGroup.get('organisations').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('organisations').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-multiple-auto-complete [formControl]="formGroup.get('researchers')" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}" [configuration]="researchersAutoCompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('profiles').hasError('backendError')">{{baseErrorModel.project}}</mat-error>
<mat-error *ngIf="formGroup.get('profiles').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('backendError')">{{formGroup.get('researchers').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('researchers').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<button mat-icon-button matSuffix type="button" (click)="addResearcher()">
<mat-icon>add_circle</mat-icon>
</button>

View File

@ -20,6 +20,7 @@ import { MultipleAutoCompleteConfiguration } from '../../../../library/auto-comp
import { SingleAutoCompleteConfiguration } from '../../../../library/auto-complete/single/single-auto-complete-configuration';
import { SnackBarNotificationComponent } from '../../../../library/notification/snack-bar/snack-bar-notification.component';
import { LanguageResolverService } from '../../../../services/language-resolver/language-resolver.service';
import { ValidationErrorModel } from '../../../../common/forms/validation/error-model/validation-error-model';
@Component({
selector: 'app-dmp-wizard-editor-component',
@ -68,33 +69,28 @@ export class DmpWizardEditorComponent extends BaseComponent implements OnInit {
filterFn: this.searchProject.bind(this.projectService),
initialItems: () => this.searchProject(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
loadDataOnStart: true
titleFn: (item) => item['label']
};
this.profilesAutoCompleteConfiguration = {
filterFn: this.filterProfiles.bind(this),
initialItems: (excludedItems: any[]) => this.filterProfiles('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
titleFn: (item) => item['label']
};
this.organisationsAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this),
initialItems: (excludedItems: any[]) => this.filterOrganisations('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
loadDataOnStart: true
titleFn: (item) => item['name']
};
this.researchersAutoCompleteConfiguration = {
filterFn: this.filterResearchers.bind(this),
initialItems: (excludedItems: any[]) => this.filterResearchers('').map(result => result.filter(resultItem => excludedItems.map(x => x.id).indexOf(resultItem.id) === -1)),
displayFn: (item) => item['name'],
titleFn: (item) => item['name'],
loadDataOnStart: true
titleFn: (item) => item['name']
};
const organisationRequestItem: RequestItem<BaseCriteria> = new RequestItem();
@ -145,15 +141,10 @@ export class DmpWizardEditorComponent extends BaseComponent implements OnInit {
}
onCallbackError(error: any) {
this.setErrorModel(error.error);
//this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: BaseErrorModel) {
Object.keys(errorModel).forEach(item => {
// (<any>this.dataManagementPlan.errorModel)[item] = (<any>errorModel)[item];
});
}
public cancel(): void {
this.router.navigate(['/plans']);

View File

@ -13,13 +13,13 @@ export class BaseCriteriaComponent extends BaseComponent implements OnInit {
public formGroup: FormGroup = null;
constructor(
public baseErrorModel?: ValidationErrorModel,
public validationErrorModel: ValidationErrorModel,
) {
super();
}
ngOnInit() {
if (this.baseErrorModel == null) { this.baseErrorModel = new ValidationErrorModel(); }
if (this.validationErrorModel == null) { this.validationErrorModel = new ValidationErrorModel(); }
}
controlModified(): void {
@ -85,15 +85,15 @@ export class BaseCriteriaComponent extends BaseComponent implements OnInit {
this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: any) {
Object.keys(errorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = (<any>errorModel)[item];
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}
public clearErrorModel() {
Object.keys(this.baseErrorModel).forEach(item => {
(<any>this.baseErrorModel)[item] = '';
Object.keys(this.validationErrorModel).forEach(item => {
(<any>this.validationErrorModel)[item] = '';
});
}
}

View File

@ -1,7 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormArray, FormGroup } from '@angular/forms';
import { CompositeField } from '../../../../../core/model/dataset-profile-definition/composite-field';
import { Field } from '../../../../../core/model/dataset-profile-definition/field';
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel } from '../../dataset-description-form.model';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
@Component({
@ -11,7 +10,7 @@ import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.
})
export class FormCompositeFieldComponent implements OnInit {
@Input() compositeField: CompositeField;
@Input() compositeField: DatasetDescriptionCompositeFieldEditorModel;
form: FormGroup;
trackByFn = (index, item) => item ? item['id'] : null;
@ -28,7 +27,7 @@ export class FormCompositeFieldComponent implements OnInit {
}
addMultipleField(fieldIndex: number) {
const field: Field = this.compositeField.fields[fieldIndex].cloneForMultiplicity(fieldIndex, '');
const field: DatasetDescriptionFieldEditorModel = this.compositeField.fields[fieldIndex].cloneForMultiplicity(fieldIndex, '');
this.compositeField.fields[fieldIndex].multiplicityItems.push(field);
(<FormArray>(this.form.get('fields').get('' + fieldIndex).get('multiplicityItems'))).push(field.buildForm());
}

View File

@ -6,30 +6,33 @@
<h5 *ngIf="field.description" class="col-12">{{field.description}}</h5>
<h5 *ngIf="field.extendedDescription" class="col-12"><i>{{field.extendedDescription}}</i></h5>
<mat-form-field *ngSwitchCase="'freetext'" class="col-12">
<mat-form-field *ngSwitchCase="datasetProfileFieldViewStyleEnum.FreeText" class="col-12">
<input matInput formControlName="value" placeholder="{{field.data.label}}" [required]="field.validationRequired">
<mat-error *ngIf="form.get('value')['errors'] && form.get('value')['errors']['required']">{{'GENERAL.VALIDATION.REQUIRED'
| translate}}</mat-error>
</mat-form-field>
<div *ngSwitchCase="'combobox'" class="col-12">
<!--TODO-->
<!-- <app-auto-complete *ngIf="this.field.data.type === 'autocomplete'" placeholder="{{ form.get('data').value.label | translate }}" [inputData]="autoCompleteConfiguration" titleKey="label" [formCtrl]="form.get('value')" [displayFunction]="displayWith.bind(this)" [assignValueFunction]="assign.bind(this)">
</app-auto-complete> -->
<mat-form-field *ngIf="this.field.data.type === 'wordlist'" class="full-width">
<mat-select [formControl]="form.get('value')" [required]="field.validationRequired">
<mat-option *ngFor="let opt of field.data.options" [value]="assignDropdownItem(opt)">{{opt.label}}</mat-option>
</mat-select>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.ComboBox" class="col-12">
<div class="row">
<mat-form-field class="col-md-12">
<app-single-auto-complete *ngIf="this.field.data.type === datasetProfileComboBoxTypeEnum.Autocomplete" placeholder="{{ form.get('data').value.label | translate }}" [formControl]="form.get('value')" [configuration]="singleAutoCompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field *ngIf="this.field.data.type === datasetProfileComboBoxTypeEnum.WordList" class="col-md-12">
<mat-select [formControl]="form.get('value')" [required]="field.validationRequired">
<mat-option *ngFor="let opt of field.data.options" [value]="assignDropdownItem(opt)">{{opt.label}}</mat-option>
</mat-select>
<mat-error *ngIf="form.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<div *ngSwitchCase="'checkBox'" class="col-12">
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.CheckBox" class="col-12">
<mat-checkbox [formControl]="form.get('value')" [required]="field.validationRequired">{{field.data.label}}</mat-checkbox>
</div>
<mat-form-field *ngSwitchCase="'textarea'" class="col-12">
<mat-form-field *ngSwitchCase="datasetProfileFieldViewStyleEnum.TextArea" class="col-12">
<textarea matInput formControlName="value" matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="10" [required]="field.validationRequired"></textarea>
<button mat-icon-button *ngIf="!form.get('value').disabled && form.get('value').value" matSuffix aria-label="Clear" (click)="this.form.patchValue({'value': ''})">
<mat-icon>close</mat-icon>
@ -37,7 +40,7 @@
<mat-error *ngIf="form.get('value')['errors'] && form.get('value')['errors']['required']">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<div *ngSwitchCase="'booleanDecision'" class="col-12">
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.BooleanDecision" class="col-12">
<mat-radio-group [formControl]="form.get('value')" [required]="field.validationRequired">
<mat-radio-button class="radio-button-item" name="{{field.id}}" value="true">Yes</mat-radio-button>
<!-- <br> -->
@ -45,11 +48,9 @@
</mat-radio-group>
</div>
<div *ngSwitchCase="'radiobox'" class="col-12">
<div *ngSwitchCase="datasetProfileFieldViewStyleEnum.RadioBox" class="col-12">
<mat-radio-group [formControl]="form.get('value')" [required]="field.validationRequired">
<mat-radio-button *ngFor="let option of field.data.options let index = index" class="radio-button-item" [value]="option.value">{{option.label}}</mat-radio-button>
</mat-radio-group>
</div>
<div *ngSwitchCase="'label'" class="col-12"> </div>
</div>

View File

@ -1,9 +1,15 @@
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BaseComponent } from '../../../../../core/common/base/base.component';
import { DatasetProfileComboBoxType } from '../../../../../core/common/enum/dataset-profile-combo-box-type';
import { DatasetProfileFieldViewStyle } from '../../../../../core/common/enum/dataset-profile-field-view-style';
import { Field } from '../../../../../core/model/dataset-profile-definition/field';
import { DatasetExternalAutocompleteCriteria } from '../../../../../core/query/dataset/daatset-external-autocomplete-criteria';
import { RequestItem } from '../../../../../core/query/request-item';
import { DatasetExternalAutocompleteService } from '../../../../../core/services/dataset/dataset-external-autocomplete.service';
import { SingleAutoCompleteConfiguration } from '../../../../../library/auto-complete/single/single-auto-complete-configuration';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
@Component({
@ -18,12 +24,28 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
change: Subscription;
trackByFn = (index, item) => item ? item['id'] : null;
public singleAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
datasetProfileFieldViewStyleEnum = DatasetProfileFieldViewStyle;
datasetProfileComboBoxTypeEnum = DatasetProfileComboBoxType;
constructor(
public visibilityRulesService: VisibilityRulesService
public visibilityRulesService: VisibilityRulesService,
private datasetExternalAutocompleteService: DatasetExternalAutocompleteService
) { super(); }
ngOnInit() {
if (this.field) {
// Setup autocomplete configuration if needed
if (this.field.viewStyle.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.field.data.type === DatasetProfileComboBoxType.Autocomplete) {
this.singleAutoCompleteConfiguration = {
filterFn: this.searchFromAutocomplete.bind(this),
initialItems: (extraData) => this.searchFromAutocomplete(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label']
};
}
this.form = this.visibilityRulesService.getFormGroup(this.field.id);
this.change = this.form.get('value').valueChanges
.pipe(takeUntil(this._destroyed))
@ -33,6 +55,15 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
}
}
searchFromAutocomplete(query: string) {
const autocompleteRequestItem: RequestItem<DatasetExternalAutocompleteCriteria> = new RequestItem();
autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria();
autocompleteRequestItem.criteria.fieldID = this.field.id;
//TODO: why do we need dataset id?
//autocompleteRequestItem.criteria.profileID = this.datasetId;
return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem);
}
assignDropdownItem(item: any) {
if (!item) { return null; }
return (typeof item === 'string') ? JSON.parse(item) : JSON.stringify(item);

View File

@ -1,7 +1,7 @@
import { AfterViewInit, Component, Input, OnInit } from '@angular/core';
import { FormArray, FormGroup } from '@angular/forms';
import { CompositeField } from '../../../../../core/model/dataset-profile-definition/composite-field';
import { Section } from '../../../../../core/model/dataset-profile-definition/section';
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionSectionEditorModel } from '../../dataset-description-form.model';
import { FormFocusService } from '../../form-focus/form-focus.service';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
@ -12,7 +12,7 @@ import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.
})
export class FormSectionComponent implements OnInit, AfterViewInit {
@Input() section: Section;
@Input() section: DatasetDescriptionSectionEditorModel;
form: FormGroup;
@Input() pathName: string;
@Input() path: string;
@ -33,7 +33,7 @@ export class FormSectionComponent implements OnInit, AfterViewInit {
}
addMultipleField(fieldsetIndex: number) {
const compositeField: CompositeField = this.section.compositeFields[fieldsetIndex].cloneForMultiplicity(fieldsetIndex);
const compositeField: DatasetDescriptionCompositeFieldEditorModel = this.section.compositeFields[fieldsetIndex].cloneForMultiplicity(fieldsetIndex);
this.section.compositeFields[fieldsetIndex].multiplicityItems.push(compositeField);
(<FormArray>(this.form.get('compositeFields').get('' + fieldsetIndex).get('multiplicityItems'))).push(compositeField.buildForm());
}

View File

@ -1,6 +1,7 @@
import { NgModule } from '@angular/core';
import { CommonFormsModule } from '../../../common/forms/common-forms.module';
import { CommonUiModule } from '../../../common/ui/common-ui.module';
import { AutoCompleteModule } from '../../../library/auto-complete/auto-complete.module';
import { FormCompositeFieldComponent } from './components/form-composite-field/form-composite-field.component';
import { FormFieldComponent } from './components/form-field/form-field.component';
import { FormProgressIndicationComponent } from './components/form-progress-indication/form-progress-indication.component';
@ -12,7 +13,8 @@ import { VisibilityRulesService } from './visibility-rules/visibility-rules.serv
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule
CommonFormsModule,
AutoCompleteModule
],
declarations: [
DatasetDescriptionFormComponent,

View File

@ -1,3 +0,0 @@
<app-auto-complete placeholder="{{ form.get('data').value.label | translate }}" [inputData]="autoCompleteConfiguration"
titleKey="label" [formCtrl]="form.get('value')" [displayFunction]="displayWith.bind(this)" [assignValueFunction]="assign.bind(this)">
</app-auto-complete>

View File

@ -1,53 +0,0 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-form-autocomplete',
templateUrl: './autocomplete-remote.component.html',
styleUrls: ['./autocomplete-remote.component.css']
})
export class AutocompleteRemoteComponent implements OnInit/* , ControlValueAccessor */ {
@Input() field: Field;
@Input() disabled = false;
@Input() form: FormGroup;
public autoCompleteConfiguration: AutoCompleteConfiguration;
public loading: boolean;
public datasetId;
public values: any[] = new Array();
public typeaheadMS = 1400;
constructor(private datasetProfileService: DatasetProfileService, route: ActivatedRoute) {
this.datasetId = route.snapshot.params['id'];
}
ngOnInit() {
const autocompleteRequestItem: RequestItem<AutocompleteLookupItem> = new RequestItem();
autocompleteRequestItem.criteria = new AutocompleteLookupItem();
autocompleteRequestItem.criteria.fieldID = this.field.id;
autocompleteRequestItem.criteria.profileID = this.datasetId;
this.autoCompleteConfiguration = new AutoCompleteConfiguration(this.datasetProfileService.queryAutocomplete.bind(this.datasetProfileService), autocompleteRequestItem);
}
displayWith(item: any) {
if (!item) { return null; }
if (typeof item === 'string') { item = this.transform(item); }
return item['label'];
}
assign(item: any) {
if (!item) { return null; }
return this.transform(item);
}
transform(item: any) {
if (typeof item === 'string') { return JSON.parse(item); } else { return JSON.stringify(item); }
}
}

View File

@ -58,9 +58,7 @@ export class NavigationComponent extends BaseComponent implements OnInit {
filterFn: this.searchProject.bind(this),
initialItems: (extraData) => this.searchProject(''),
displayFn: (item) => item['label'],
titleFn: (item) => item['label'],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
titleFn: (item) => item['label']
};
this.filteredOptions = this.searchControl.valueChanges.debounceTime(500).distinctUntilChanged().flatMap(x => {
@ -105,9 +103,10 @@ export class NavigationComponent extends BaseComponent implements OnInit {
openProfile() {
const dialogRef = this.dialog.open(UserDialogComponent, {
hasBackdrop: true,
autoFocus: false,
closeOnNavigation: true,
disableClose: false,
position: { top: '64px', left: '85%' }
position: { top: '64px', right: '1em' }
});
}

View File

@ -1,24 +1,21 @@
<form>
<div mat-dialog-title>
<img mat-card-avatar *ngIf="this.principalHasAvatar()" [src]="this.getPrincipalAvatar()">
<span class="user-label">{{this.getPrincipalName()}}</span>
</div>
<div mat-dialog-content>
<mat-divider></mat-divider>
{{'USER-DIALOG.USER-PROFILE' | translate}}
<button mat-icon-button (click)="navigateToProfile()">
<mat-icon>person</mat-icon>
</button>
<mat-divider></mat-divider>
</div>
<div mat-dialog-actions>
<div class="full-width">
{{'USER-DIALOG.EXIT' | translate}}
<button mat-icon-button (click)="logout()">
<mat-icon>exit_to_app</mat-icon>
</button>
<div class="row">
<div class="col-auto">
<img mat-card-avatar *ngIf="this.principalHasAvatar()" [src]="this.getPrincipalAvatar()">
</div>
<span class="user-label col">{{this.getPrincipalName()}}</span>
</div>
</div>
<div mat-dialog-content class="row">
<mat-divider class="col-12"></mat-divider>
<a mat-button (click)="navigateToProfile()" class="col-12">
{{'USER-DIALOG.USER-PROFILE' | translate}} <mat-icon>person</mat-icon>
</a>
<mat-divider class="col-12"></mat-divider>
<a mat-button (click)="logout()" class="col-12">
{{'USER-DIALOG.EXIT' | translate}} <mat-icon>exit_to_app</mat-icon>
</a>
</div>
</form>

View File

@ -44,6 +44,6 @@ export class UserDialogComponent implements OnInit {
public navigateToProfile() {
this.dialogRef.close();
this.router.navigate(['/users/' + this.authentication.current().id]);
this.router.navigate(['/profile']);
}
}

View File

@ -43,18 +43,18 @@
<div class="row">
<mat-form-field class="col-md-12">
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{baseErrorModel.label}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.ABBREVIATION' | translate}}" type="text" name="abbreviation" formControlName="abbreviation">
<mat-error *ngIf="formGroup.get('abbreviation').hasError('backendError')">{{baseErrorModel.abbreviation}}</mat-error>
<mat-error *ngIf="formGroup.get('abbreviation').hasError('backendError')">{{formGroup.get('abbreviation').getError('backendError').message}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-6">
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{baseErrorModel.uri}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -62,7 +62,7 @@
<input matInput (focus)="startDate.open()" (click)="startDate.open()" placeholder="{{'PROJECT-EDITOR.FIELDS.START' | translate}}" class="table-input" [matDatepicker]="startDate" formControlName="startDate">
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('startDate').hasError('backendError')">{{this.project.errorModel.startDate}}</mat-error>
<mat-error *ngIf="formGroup.get('startDate').hasError('backendError')">{{formGroup.get('startDate').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('startDate').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -70,13 +70,13 @@
<input matInput (focus)="endDate.open()" (click)="endDate.open()" placeholder="{{'PROJECT-EDITOR.FIELDS.END' | translate}}" class="table-input" [matDatepicker]="endDate" formControlName="endDate">
<mat-datepicker-toggle matSuffix [for]="endDate"></mat-datepicker-toggle>
<mat-datepicker #endDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('endDate').hasError('backendError')">{{baseErrorModel.endDate}}</mat-error>
<mat-error *ngIf="formGroup.get('endDate').hasError('backendError')">{{formGroup.get('endDate').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('endDate').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-12">
<textarea matInput class="description-area" placeholder="{{'PROJECT-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description" required></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>

View File

@ -6,6 +6,7 @@ import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { environment } from '../../../../environments/environment';
import { ValidationErrorModel } from '../../../common/forms/validation/error-model/validation-error-model';
import { BaseComponent } from '../../../core/common/base/base.component';
import { ProjectType } from '../../../core/common/enum/project-type';
import { ProjectModel } from '../../../core/model/project/project';
@ -103,9 +104,9 @@ export class ProjectEditorComponent extends BaseComponent implements OnInit, IBr
this.validateAllFormFields(this.formGroup);
}
public setErrorModel(errorModel: BaseErrorModel) {
Object.keys(errorModel).forEach(item => {
(<any>this.project.errorModel)[item] = (<any>errorModel)[item];
public setErrorModel(validationErrorModel: ValidationErrorModel) {
Object.keys(validationErrorModel).forEach(item => {
(<any>this.project.validationErrorModel)[item] = (<any>validationErrorModel)[item];
});
}

View File

@ -19,7 +19,7 @@ export class ProjectEditorModel {
public description: String;
public contentUrl: string;
public files: ContentFile[];
public errorModel: ValidationErrorModel = new ValidationErrorModel();
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
fromModel(item: ProjectModel): ProjectEditorModel {
this.id = item.id;
@ -59,15 +59,15 @@ export class ProjectEditorModel {
createValidationContext(): ValidationContext {
const baseContext: ValidationContext = new ValidationContext();
baseContext.validation.push({ key: 'id', validators: [] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
baseContext.validation.push({ key: 'abbreviation', validators: [BackendErrorValidator(this.errorModel, 'abbreviation')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.errorModel, 'uri')] });
baseContext.validation.push({ key: 'type', validators: [BackendErrorValidator(this.errorModel, 'type')] });
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
baseContext.validation.push({ key: 'abbreviation', validators: [BackendErrorValidator(this.validationErrorModel, 'abbreviation')] });
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.validationErrorModel, 'uri')] });
baseContext.validation.push({ key: 'type', validators: [BackendErrorValidator(this.validationErrorModel, 'type')] });
baseContext.validation.push({ key: 'status', validators: [] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'description')] });
baseContext.validation.push({ key: 'startDate', validators: [BackendErrorValidator(this.errorModel, 'startDate')] });
baseContext.validation.push({ key: 'endDate', validators: [BackendErrorValidator(this.errorModel, 'endDate')] });
baseContext.validation.push({ key: 'files', validators: [BackendErrorValidator(this.errorModel, 'files')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
baseContext.validation.push({ key: 'startDate', validators: [BackendErrorValidator(this.validationErrorModel, 'startDate')] });
baseContext.validation.push({ key: 'endDate', validators: [BackendErrorValidator(this.validationErrorModel, 'endDate')] });
baseContext.validation.push({ key: 'files', validators: [BackendErrorValidator(this.validationErrorModel, 'files')] });
return baseContext;
}

View File

@ -3,18 +3,15 @@
<!-- <h4 class="col-md-12">{{'CRITERIA.FILTERS'| translate}}</h4> -->
<mat-form-field class="col-md-3">
<input matInput placeholder=" {{'CRITERIA.PROJECTS.LIKE'| translate}}" name="projectCriteriaLike" [(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['criteria.like']}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-3">
<input matInput (focus)="periodStartPicker.open()" (click)="periodStartPicker.open()" placeholder=" {{this.languageResolver.getBy('criteriaStart')| translate}}" [matDatepicker]="periodStartPicker" name="projectCriteriaPeriodStart" [(ngModel)]="criteria.periodStart" (ngModelChange)="controlModified()">
<mat-datepicker-toggle matSuffix [for]="periodStartPicker"></mat-datepicker-toggle>
<mat-datepicker #periodStartPicker></mat-datepicker>
</mat-form-field>
<mat-error *ngIf="baseErrorModel['criteria.periodStart']">{{baseErrorModel['criteria.periodStart']}}</mat-error>
<mat-form-field class="col-md-3">
<input matInput (focus)="periodEndPicker.open()" (click)="periodEndPicker.open()" name="projectCriteriaPeriodEnd" placeholder=" {{this.languageResolver.getBy('criteriaEnd')| translate}}" [matDatepicker]="periodEndPicker" [(ngModel)]="criteria.periodEnd" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel['criteria.periodEnd']">{{baseErrorModel['criteria.periodEnd']}}</mat-error>
<mat-datepicker-toggle matSuffix [for]="periodEndPicker"></mat-datepicker-toggle>
<mat-datepicker #periodEndPicker></mat-datepicker>
</mat-form-field>

View File

@ -1,30 +1,36 @@
<div *ngIf="user | async as userProfile; else loading">
<mat-card class="example-card">
<div *ngIf="user | async as userProfile; else loading" class="row user-profile">
<mat-card class="col-12 profile-card">
<mat-card-content>
<div >
<div>
<img mat-card-avatar [src]="userProfile.additionalinfo.avatarUrl">
<div class="row">
<div class="col-12">
<div class="row profile-card-center-row">
<div class="col-auto"><img mat-card-avatar [src]="userProfile.additionalinfo.avatarUrl"></div>
</div>
<div class="row profile-card-center-row">
<mat-card-title class="col-auto">{{userProfile.name}}</mat-card-title>
</div>
<div class="row profile-card-center-row">
<mat-card-subtitle class="col-auto">{{userProfile.email}}</mat-card-subtitle>
</div>
</div>
<mat-card-title>{{userProfile.name}}</mat-card-title>
<mat-card-subtitle>{{userProfile.email}}</mat-card-subtitle>
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card class="col-12 profile-card">
<mat-card-content>
<div >
<div>
<div>
<h4>{{ 'USER-PROFILE.ASSOCIATED-DMPS' | translate}}</h4>
<h4>{{'USER-PROFILE.ASSOCIATED-DMPS' | translate}}</h4>
</div>
<div>
<mat-list>
<mat-list-item class="clickable" (click)="navigateToDmp(dmp)" *ngFor="let dmp of userProfile.associatedDmps">
<div>
{{ dmp.label }}
{{dmp.label}}
</div>
<div>
<mat-chip-list>
<mat-chip>{{ getUserRole(dmp) }}</mat-chip>
<mat-chip>{{getUserRole(dmp)}}</mat-chip>
</mat-chip-list>
</div>
</mat-list-item>
@ -34,52 +40,46 @@
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card class="col-12 profile-card">
<mat-card-header>
<mat-card-title>
<h4>{{ 'USER-PROFILE.SETTINGS.TITLE' | translate}}</h4>
<button *ngIf="!editMode" mat-icon-button (click)="unlock()">
<mat-icon class="mat-24">edit</mat-icon>
</button>
<button *ngIf="editMode" mat-icon-button (click)="lock()">
<mat-icon class="mat-24">lock</mat-icon>
</button>
<div class="row">
<h4 class="col-auto">{{ 'USER-PROFILE.SETTINGS.TITLE' | translate}}</h4>
<button class="col-auto" *ngIf="!editMode" mat-icon-button (click)="unlock()">
<mat-icon class="mat-24">edit</mat-icon>
</button>
<button class="col-auto" *ngIf="editMode" mat-icon-button (click)="lock()">
<mat-icon class="mat-24">lock</mat-icon>
</button>
</div>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="container">
<div class="row">
<div class="col-md-4">
<mat-form-field class="full-width">
<input type="text" placeholder="{{'USER-PROFILE.SETTINGS.TIMEZONE' | translate}}" [formControl]="this.formGroup.get('timezone')"
matInput [matAutocomplete]="timezone">
<mat-autocomplete #timezone="matAutocomplete">
<mat-option *ngFor="let timezone of timezones | async" [value]="timezone">
{{ timezone | timezoneInfoDisplay }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<input type="text" placeholder="{{'USER-PROFILE.SETTINGS.CULTURE' | translate}}" [formControl]="this.formGroup.get('culture')"
matInput [matAutocomplete]="culture">
<mat-autocomplete #culture="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let culture of cultures | async" [value]="culture">
{{ culture.displayName }} - {{ culture.nativeName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<mat-select placeholder="{{'USER-PROFILE.SETTINGS.LANGUAGE' | translate}}" [formControl]="this.formGroup.get('language')">
<mat-option *ngFor="let language of languages" [value]="language">
{{ language.label }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="row" [formGroup]="formGroup">
<mat-form-field class="col-md-4">
<input type="text" placeholder="{{'USER-PROFILE.SETTINGS.TIMEZONE' | translate}}" [formControl]="this.formGroup.get('timezone')" matInput [matAutocomplete]="timezone" required>
<mat-autocomplete #timezone="matAutocomplete">
<mat-option *ngFor="let timezone of timezones | async" [value]="timezone">
{{ timezone | timezoneInfoDisplay }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="col-md-4">
<input type="text" placeholder="{{'USER-PROFILE.SETTINGS.CULTURE' | translate}}" [formControl]="this.formGroup.get('culture')" matInput [matAutocomplete]="culture" required>
<mat-autocomplete #culture="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let culture of cultures | async" [value]="culture">
{{ culture.displayName }} - {{ culture.nativeName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="col-md-4">
<mat-select placeholder="{{'USER-PROFILE.SETTINGS.LANGUAGE' | translate}}" [formControl]="this.formGroup.get('language')" required>
<mat-option *ngFor="let language of languages" [value]="language">
{{ language.label }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</mat-card-content>

View File

@ -1,10 +1,19 @@
.clickable{
cursor: pointer;
}
.two-line-mat-option {
height: 3.5em;
line-height: 1.2em;
}
.full-width{
width: 100%
// .clickable{
// cursor: pointer;
// }
// .two-line-mat-option {
// height: 3.5em;
// line-height: 1.2em;
// }
// .full-width{
// width: 100%
// }
.user-profile {
.profile-card-center-row {
justify-content: center;
}
.profile-card {
margin-bottom: 1em;
}
}

View File

@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment-timezone';
@ -44,14 +44,14 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
this.route.params
.pipe(takeUntil(this._destroyed))
.subscribe((params: Params) => {
this.currentUserId = params['id'];
const userId = params['id'] === this.authService.current().id ? 'me' : params['id'];
this.currentUserId = this.authService.current().id;
const userId = !params['id'] ? 'me' : params['id'];
this.user = this.userService.getUser(userId).map(result => {
result['additionalinfo'] = JSON.parse(result['additionalinfo']);
this.formGroup = new FormBuilder().group({
language: new FormControl(result['additionalinfo']['language'] ? availableLanguages.filter(x => x.value === result['additionalinfo']['language']['value']).pop() : ''),
timezone: new FormControl(result['additionalinfo']['timezone']),
culture: new FormControl(result['additionalinfo']['culture'])
language: new FormControl(result['additionalinfo']['language'] ? availableLanguages.filter(x => x.value === result['additionalinfo']['language']['value']).pop() : '', [Validators.required]),
timezone: new FormControl(result['additionalinfo']['timezone'], [Validators.required]),
culture: new FormControl(result['additionalinfo']['culture'], [Validators.required])
});
//this.formGroup.get('language').valueChanges.pipe(takeUntil(this._destroyed)).subscribe(x => { if (x) this.translate.use(x.value) })
this.formGroup.get('timezone').valueChanges
@ -115,6 +115,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
}
public lock() {
if (!this.formGroup.valid) { return; }
this.userService.updateUserSettings(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(

View File

@ -16,4 +16,4 @@ import { UserProfileRoutingModule } from './user-profile.routing';
UserProfileComponent
]
})
export class ProjectModule { }
export class UserProfileModule { }