diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts
index beeb94565..9caca21d7 100644
--- a/dmp-frontend/src/app/app-routing.module.ts
+++ b/dmp-frontend/src/app/app-routing.module.ts
@@ -247,6 +247,14 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.SUPPORTIVE-MATERIAL'
},
},
+ {
+ path: 'references',
+ loadChildren: () => import('./ui/admin/reference/reference.module').then(m => m.ReferenceModule),
+ data: {
+ breadcrumb: true,
+ title: 'GENERAL.TITLES.REFERENCES'
+ },
+ },
{
path: 'reference-type',
loadChildren: () => import('./ui/admin/reference-type/reference-type.module').then(m => m.ReferenceTypeModule),
diff --git a/dmp-frontend/src/app/core/common/enum/permission.enum.ts b/dmp-frontend/src/app/core/common/enum/permission.enum.ts
index 6918b587c..d0072ab5a 100644
--- a/dmp-frontend/src/app/core/common/enum/permission.enum.ts
+++ b/dmp-frontend/src/app/core/common/enum/permission.enum.ts
@@ -28,5 +28,10 @@ export enum AppPermission {
BrowseTenant = "BrowseTenant",
EditTenant = "EditTenant",
DeleteTenant = "DeleteTenant",
+
+ //Reference
+ BrowseReference = "BrowseReference",
+ EditReference = "EditReference",
+ DeleteReference = "DeleteReference",
}
diff --git a/dmp-frontend/src/app/core/model/reference/reference.ts b/dmp-frontend/src/app/core/model/reference/reference.ts
index adf834699..f243d3cd5 100644
--- a/dmp-frontend/src/app/core/model/reference/reference.ts
+++ b/dmp-frontend/src/app/core/model/reference/reference.ts
@@ -1,12 +1,11 @@
-import { IsActive } from "@app/core/common/enum/is-active.enum";
import { ReferenceFieldDataType } from "@app/core/common/enum/reference-field-data-type";
import { ReferenceSourceType } from "@app/core/common/enum/reference-source-type";
import { ReferenceType } from "@app/core/common/enum/reference-type";
import { UUID } from "crypto";
import { DmpModel } from "../dmp/dmp";
+import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model";
-export interface Reference {
- id: UUID;
+export interface Reference extends BaseEntity{
label: string;
type: ReferenceType;
description: string;
@@ -15,9 +14,6 @@ export interface Reference {
abbreviation: string;
source: string;
sourceType: ReferenceSourceType;
- isActive: IsActive;
- createdAt: Date;
- updatedAt: Date;
dmpReferences: DmpReference[];
}
@@ -61,12 +57,11 @@ export interface FetcherReference {
// Persist
-export interface ReferencePersist {
- id: UUID;
+export interface ReferencePersist extends BaseEntityPersist {
label: string;
type: ReferenceType;
description: string;
- definition: DefinitionPersist;
+ definition?: DefinitionPersist;
reference: string;
abbreviation: string;
source: string;
@@ -74,7 +69,7 @@ export interface ReferencePersist {
}
export interface DefinitionPersist {
- fields?: FieldPersist[];
+ fields: FieldPersist[];
}
export interface FieldPersist {
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 2e1457ed2..979107814 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
@@ -22,6 +22,8 @@ import { ReferenceFieldDataType } from '@app/core/common/enum/reference-field-da
import { ReferenceTypeSourceType } from '@app/core/common/enum/reference-type-source-type';
import { ReferenceTypeExternalApiHTTPMethodType } from '@app/core/common/enum/reference-type-external-api-http-method-type';
import { UserDescriptionTemplateRole } from '@app/core/common/enum/user-description-template-role';
+import { ReferenceType } from '@app/core/common/enum/reference-type';
+import { ReferenceSourceType } from '@app/core/common/enum/reference-source-type';
@Injectable()
export class EnumUtils {
@@ -304,4 +306,32 @@ export class EnumUtils {
case UserDescriptionTemplateRole.Owner: return this.language.instant('TYPES.USER-DESCRIPTION-TEMPLATE-ROLE.OWNER');
}
}
+
+ toReferenceTypeString(status: ReferenceType): string {
+ switch (status) {
+ case ReferenceType.Taxonomies: return this.language.instant('TYPES.REFERENCE-TYPE.TAXONOMY');
+ case ReferenceType.Licenses: return this.language.instant('TYPES.REFERENCE-TYPE.LICENCE');
+ case ReferenceType.Publications: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Journals: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.PubRepositories: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.DataRepositories: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Registries: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Services: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Project: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Funder: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Datasets: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Organizations: return this.language.instant('TYPES.REFERENCE-TYPE.ORGANISATION');
+ case ReferenceType.Grants: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+ case ReferenceType.Researcher: return this.language.instant('TYPES.REFERENCE-TYPE.GET');
+
+ }
+ }
+
+ toReferenceSourceTypeString(status: ReferenceSourceType): string {
+ switch (status) {
+ case ReferenceSourceType.Internal: return this.language.instant('TYPES.REFERENCE-SOURCE-TYPE.INTERNAL');
+ case ReferenceSourceType.External: return this.language.instant('TYPES.REFERENCE-SOURCE-TYPE.EXTERNAL');
+ }
+ }
+
}
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.html b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.html
new file mode 100644
index 000000000..80e0cadbd
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.html
@@ -0,0 +1,157 @@
+
+
+
+
+
{{'REFERENCE-EDITOR.NEW' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.scss b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.scss
new file mode 100644
index 000000000..306d4650e
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.scss
@@ -0,0 +1,43 @@
+.reference-editor {
+ margin-top: 1.3rem;
+ margin-left: 1em;
+ margin-right: 3em;
+
+ .remove {
+ background-color: white;
+ color: black;
+ }
+
+ .add {
+ background-color: white;
+ color: #009700;
+ }
+}
+
+::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background, .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background {
+ background-color: var(--primary-color-3);
+ // background-color: #0070c0;
+}
+
+::ng-deep .mat-checkbox-disabled.mat-checkbox-checked .mat-checkbox-background, .mat-checkbox-disabled.mat-checkbox-indeterminate .mat-checkbox-background {
+ background-color: #b0b0b0;
+}
+
+.action-btn {
+ border-radius: 30px;
+ background-color: var(--secondary-color);
+ 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;
+ &:disabled{
+ background-color: #CBCBCB;
+ color: #FFF;
+ border: 0px;
+ }
+}
\ No newline at end of file
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.ts b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.ts
new file mode 100644
index 000000000..f18bb26e6
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.component.ts
@@ -0,0 +1,202 @@
+
+import { Component, OnInit } from '@angular/core';
+import { FormArray, UntypedFormGroup } from '@angular/forms';
+import { MatDialog } from '@angular/material/dialog';
+import { ActivatedRoute, Router } from '@angular/router';
+import { ReferenceService } from '@app/core/services/reference/reference.service';
+import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
+import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
+// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
+import { DatePipe } from '@angular/common';
+import { IsActive } from '@app/core/common/enum/is-active.enum';
+import { AppPermission } from '@app/core/common/enum/permission.enum';
+import { Reference, ReferencePersist } from '@app/core/model/reference/reference';
+import { AuthService } from '@app/core/services/auth/auth.service';
+import { LoggingService } from '@app/core/services/logging/logging-service';
+import { MatomoService } from '@app/core/services/matomo/matomo-service';
+import { FileUtils } from '@app/core/services/utilities/file-utils.service';
+import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
+import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
+import { BaseEditor } from '@common/base/base-editor';
+import { FormService } from '@common/forms/form-service';
+import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
+import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
+import { FilterService } from '@common/modules/text-filter/filter-service';
+import { Guid } from '@common/types/guid';
+import { TranslateService } from '@ngx-translate/core';
+import { map, takeUntil } from 'rxjs/operators';
+import { ReferenceEditorResolver } from './reference-editor.resolver';
+import { ReferenceEditorService } from './reference-editor.service';
+import { FieldEditorModel, ReferenceEditorModel } from './reference-editor.model';
+import { ReferenceType } from '@app/core/common/enum/reference-type';
+import { ReferenceSourceType } from '@app/core/common/enum/reference-source-type';
+import { ReferenceFieldDataType } from '@app/core/common/enum/reference-field-data-type';
+
+
+@Component({
+ selector: 'app-reference-editor-component',
+ templateUrl: 'reference-editor.component.html',
+ styleUrls: ['./reference-editor.component.scss'],
+ providers: [ReferenceEditorService]
+})
+export class ReferenceEditorComponent extends BaseEditor implements OnInit {
+
+ isNew = true;
+ isDeleted = false;
+ formGroup: UntypedFormGroup = null;
+ showInactiveDetails = false;
+ public referenceTypeEnum = this.enumUtils.getEnumValues(ReferenceType);
+ public referenceSourceTypeEnum = this.enumUtils.getEnumValues(ReferenceSourceType);
+ public referenceFieldDataTypeEnum = this.enumUtils.getEnumValues(ReferenceFieldDataType);
+
+ protected get canDelete(): boolean {
+ return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteReference);
+ }
+
+ protected get canSave(): boolean {
+ return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditReference);
+ }
+
+ protected get canFinalize(): boolean {
+ return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditReference);
+ }
+
+
+ private hasPermission(permission: AppPermission): boolean {
+ return this.authService.hasPermission(permission) || this.editorModel?.permissions?.includes(permission);
+ }
+
+ constructor(
+ // BaseFormEditor injected dependencies
+ protected dialog: MatDialog,
+ protected language: TranslateService,
+ protected formService: FormService,
+ protected router: Router,
+ protected uiNotificationService: UiNotificationService,
+ protected httpErrorHandlingService: HttpErrorHandlingService,
+ protected filterService: FilterService,
+ protected datePipe: DatePipe,
+ protected route: ActivatedRoute,
+ protected queryParamsService: QueryParamsService,
+ // Rest dependencies. Inject any other needed deps here:
+ public authService: AuthService,
+ public enumUtils: EnumUtils,
+ private referenceService: ReferenceService,
+ private logger: LoggingService,
+ private referenceEditorService: ReferenceEditorService,
+ private fileUtils: FileUtils,
+ private matomoService: MatomoService
+ ) {
+ super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService);
+ }
+
+ ngOnInit(): void {
+ this.matomoService.trackPageView('Admin: References');
+ super.ngOnInit();
+ }
+
+ getItem(itemId: Guid, successFunction: (item: Reference) => void) {
+ this.referenceService.getSingle(itemId, ReferenceEditorResolver.lookupFields())
+ .pipe(map(data => data as Reference), takeUntil(this._destroyed))
+ .subscribe(
+ data => successFunction(data),
+ error => this.onCallbackError(error)
+ );
+ }
+
+ prepareForm(data: Reference) {
+ try {
+ this.editorModel = data ? new ReferenceEditorModel().fromModel(data) : new ReferenceEditorModel();
+ this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
+ this.buildForm();
+ } catch (error) {
+ this.logger.error('Could not parse Reference item: ' + data + error);
+ this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error);
+ }
+ }
+
+ buildForm() {
+ this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditReference));
+ this.referenceEditorService.setValidationErrorModel(this.editorModel.validationErrorModel);
+ }
+
+ refreshData(): void {
+ this.getItem(this.editorModel.id, (data: Reference) => this.prepareForm(data));
+ }
+
+ refreshOnNavigateToData(id?: Guid): void {
+ this.formGroup.markAsPristine();
+ let route = [];
+
+ if (id === null) {
+ route.push('../..');
+ } else if (this.isNew) {
+ route.push('../' + id);
+ } else {
+ route.push('..');
+ }
+
+ this.router.navigate(route, { queryParams: { 'lookup': this.queryParamsService.serializeLookup(this.lookupParams), 'lv': ++this.lv }, replaceUrl: true, relativeTo: this.route });
+ }
+
+ persistEntity(onSuccess?: (response) => void): void {
+ const formData = this.formService.getValue(this.formGroup.value) as ReferencePersist;
+
+ this.referenceService.persist(formData)
+ .pipe(takeUntil(this._destroyed)).subscribe(
+ complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete),
+ error => this.onCallbackError(error)
+ );
+ }
+
+ formSubmit(): void {
+ this.formService.touchAllFormFields(this.formGroup);
+ if (!this.isFormValid()) {
+ return;
+ }
+
+ this.persistEntity();
+ }
+
+ public delete() {
+ const value = this.formGroup.value;
+ if (value.id) {
+ const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
+ maxWidth: '300px',
+ 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')
+ }
+ });
+ dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
+ if (result) {
+ this.referenceService.delete(value.id).pipe(takeUntil(this._destroyed))
+ .subscribe(
+ complete => this.onCallbackSuccess(),
+ error => this.onCallbackError(error)
+ );
+ }
+ });
+ }
+ }
+
+ clearErrorModel() {
+ this.editorModel.validationErrorModel.clear();
+ this.formService.validateAllFormFields(this.formGroup);
+ }
+
+ //
+ // fields
+ //
+ addField(): void {
+ const field: FieldEditorModel = new FieldEditorModel();
+ (this.formGroup.get('definition').get('fields') as FormArray).push(field.buildForm());
+ }
+
+ removeField(fieldIndex: number): void {
+ (this.formGroup.get('definition').get('fields') as FormArray).removeAt(fieldIndex);
+ }
+
+
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.model.ts b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.model.ts
new file mode 100644
index 000000000..215f3f824
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.model.ts
@@ -0,0 +1,195 @@
+import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
+import { ReferenceFieldDataType } from "@app/core/common/enum/reference-field-data-type";
+import { ReferenceSourceType } from "@app/core/common/enum/reference-source-type";
+import { ReferenceType } from "@app/core/common/enum/reference-type";
+import { Definition, DefinitionPersist, Field, FieldPersist, Reference, ReferencePersist } from "@app/core/model/reference/reference";
+import { BaseEditorModel } from "@common/base/base-form-editor-model";
+import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
+import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
+import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
+
+export class ReferenceEditorModel extends BaseEditorModel implements ReferencePersist {
+ label: string;
+ type: ReferenceType;
+ description: string;
+ definition: DefinitionEditorModel = new DefinitionEditorModel();
+ reference: string;
+ abbreviation: string;
+ source: string;
+ sourceType: ReferenceSourceType;
+
+ permissions: string[];
+
+ public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
+ protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
+
+ constructor() { super(); }
+
+ public fromModel(item: Reference): ReferenceEditorModel {
+ if (item) {
+ super.fromModel(item);
+ this.label = item.label;
+ this.type = item.type;
+ this.description = item.description;
+ if (item.definition) this.definition = new DefinitionEditorModel().fromModel(item.definition);
+ this.reference = item.reference;
+ this.abbreviation = item.abbreviation;
+ this.source = item.source;
+ this.sourceType = item.sourceType;
+ }
+ return this;
+ }
+
+ buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
+ if (context == null) { context = this.createValidationContext(); }
+
+ return this.formBuilder.group({
+ id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
+ label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
+ type: [{ value: this.type, disabled: disabled }, context.getValidation('type').validators],
+ description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
+ definition: this.definition.buildForm({
+ rootPath: `definition.`
+ }),
+ reference: [{ value: this.reference, disabled: disabled }, context.getValidation('reference').validators],
+ abbreviation: [{ value: this.abbreviation, disabled: disabled }, context.getValidation('abbreviation').validators],
+ source: [{ value: this.source, disabled: disabled }, context.getValidation('source').validators],
+ sourceType: [{ value: this.sourceType, disabled: disabled }, context.getValidation('sourceType').validators],
+
+ hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators]
+ });
+ }
+
+ createValidationContext(): ValidationContext {
+ const baseContext: ValidationContext = new ValidationContext();
+ const baseValidationArray: Validation[] = new Array();
+ baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
+ baseValidationArray.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
+ baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'type')] });
+ baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] });
+ baseValidationArray.push({ key: 'reference', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'reference')] });
+ baseValidationArray.push({ key: 'abbreviation', validators: [BackendErrorValidator(this.validationErrorModel, 'abbreviation')] });
+ baseValidationArray.push({ key: 'source', validators: [BackendErrorValidator(this.validationErrorModel, 'source')] });
+ baseValidationArray.push({ key: 'sourceType', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'sourceType')] });
+ baseValidationArray.push({ key: 'hash', validators: [] });
+
+ baseContext.validation = baseValidationArray;
+ return baseContext;
+ }
+}
+
+export class DefinitionEditorModel implements DefinitionPersist {
+ fields: FieldEditorModel[]= [];
+
+ protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
+
+ constructor(
+ public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
+ ) { }
+
+ public fromModel(item: Definition): DefinitionEditorModel {
+ if (item) {
+ if (item.fields) { item.fields.map(x => this.fields.push(new FieldEditorModel().fromModel(x))); }
+ }
+ return this;
+ }
+
+ buildForm(params?: {
+ context?: ValidationContext,
+ disabled?: boolean,
+ rootPath?: string
+ }): UntypedFormGroup {
+ let { context = null, disabled = false, rootPath } = params ?? {}
+ if (context == null) {
+ context = DefinitionEditorModel.createValidationContext({
+ validationErrorModel: this.validationErrorModel,
+ rootPath
+ });
+ }
+
+ return this.formBuilder.group({
+ fields: this.formBuilder.array(
+ (this.fields ?? []).map(
+ (item, index) => new FieldEditorModel(
+ this.validationErrorModel
+ ).fromModel(item).buildForm({
+ rootPath: `fields[${index}].`
+ }), context.getValidation('fields')
+ )
+ ),
+ });
+ }
+
+ static createValidationContext(params: {
+ rootPath?: string,
+ validationErrorModel: ValidationErrorModel
+ }): ValidationContext {
+ const { rootPath = '', validationErrorModel } = params;
+
+ const baseContext: ValidationContext = new ValidationContext();
+ const baseValidationArray: Validation[] = new Array();
+ baseValidationArray.push({ key: 'fields', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}fields`)] });
+
+ baseContext.validation = baseValidationArray;
+ return baseContext;
+ }
+}
+
+export class FieldEditorModel implements FieldPersist {
+ code: string;
+ dataType: ReferenceFieldDataType;
+ value: string;
+
+ protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
+
+ constructor(
+ public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
+ ) { }
+
+ public fromModel(item: Field): FieldEditorModel {
+ if (item) {
+ this.code = item.code;
+ this.dataType = item.dataType;
+ this.value = item.value;
+ }
+ return this;
+ }
+
+ buildForm(params?: {
+ context?: ValidationContext,
+ disabled?: boolean,
+ rootPath?: string
+ }): UntypedFormGroup {
+ let { context = null, disabled = false, rootPath } = params ?? {}
+ if (context == null) {
+ context = FieldEditorModel.createValidationContext({
+ validationErrorModel: this.validationErrorModel,
+ rootPath
+ });
+ }
+
+ return this.formBuilder.group({
+ code: [{ value: this.code, disabled: disabled }, context.getValidation('code').validators],
+ dataType: [{ value: this.dataType, disabled: disabled }, context.getValidation('dataType').validators],
+ value: [{ value: this.value, disabled: disabled }, context.getValidation('value').validators],
+ });
+ }
+
+ static createValidationContext(params: {
+ rootPath?: string,
+ validationErrorModel: ValidationErrorModel
+ }): ValidationContext {
+ const { rootPath = '', validationErrorModel } = params;
+
+ const baseContext: ValidationContext = new ValidationContext();
+ const baseValidationArray: Validation[] = new Array();
+
+ baseValidationArray.push({ key: 'code', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}code`)] });
+ baseValidationArray.push({ key: 'dataType', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}dataType`)] });
+ baseValidationArray.push({ key: 'value', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}value`)] });
+
+ baseContext.validation = baseValidationArray;
+ return baseContext;
+ }
+}
+
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.resolver.ts b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.resolver.ts
new file mode 100644
index 000000000..3a2465f6f
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.resolver.ts
@@ -0,0 +1,47 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { Reference } from '@app/core/model/reference/reference';
+import { ReferenceService } from '@app/core/services/reference/reference.service';
+import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
+import { BaseEditorResolver } from '@common/base/base-editor.resolver';
+import { Guid } from '@common/types/guid';
+import { takeUntil, tap } from 'rxjs/operators';
+import { nameof } from 'ts-simple-nameof';
+
+@Injectable()
+export class ReferenceEditorResolver extends BaseEditorResolver {
+
+ constructor(private referenceService: ReferenceService, private breadcrumbService: BreadcrumbService) {
+ super();
+ }
+
+ public static lookupFields(): string[] {
+ return [
+ ...BaseEditorResolver.lookupFields(),
+ nameof(x => x.id),
+ nameof(x => x.label),
+ nameof(x => x.type),
+ nameof(x => x.description),
+ nameof(x => x.reference),
+ nameof(x => x.abbreviation),
+ nameof(x => x.source),
+ nameof(x => x.sourceType),
+ nameof(x => x.createdAt),
+ nameof(x => x.updatedAt),
+ nameof(x => x.hash),
+ nameof(x => x.isActive)
+ ]
+ }
+
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+
+ const fields = [
+ ...ReferenceEditorResolver.lookupFields()
+ ];
+ const id = route.paramMap.get('id');
+
+ if (id != null) {
+ return this.referenceService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
+ }
+ }
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.service.ts b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.service.ts
new file mode 100644
index 000000000..0f94d946e
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/editor/reference-editor.service.ts
@@ -0,0 +1,15 @@
+import { Injectable } from "@angular/core";
+import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
+
+@Injectable()
+export class ReferenceEditorService {
+ private validationErrorModel: ValidationErrorModel;
+
+ public setValidationErrorModel(validationErrorModel: ValidationErrorModel): void {
+ this.validationErrorModel = validationErrorModel;
+ }
+
+ public getValidationErrorModel(): ValidationErrorModel {
+ return this.validationErrorModel;
+ }
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.html b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.html
new file mode 100644
index 000000000..f129c7105
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
{{'REFERENCE-LISTING.FILTER.TITLE' | translate}}
+
+
+
+
+ {{'REFERENCE-LISTING.FILTER.IS-ACTIVE' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.scss b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.scss
new file mode 100644
index 000000000..ea00a215c
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.scss
@@ -0,0 +1,21 @@
+::ng-deep.mat-mdc-menu-panel {
+ max-width: 100% !important;
+ height: 100% !important;
+}
+
+:host::ng-deep.mat-mdc-menu-content:not(:empty) {
+ padding-top: 0 !important;
+}
+
+
+.filter-button{
+ padding-top: .6rem;
+ padding-bottom: .6rem;
+ // .mat-icon{
+ // font-size: 1.5em;
+ // width: 1.2em;
+ // height: 1.2em;
+ // }
+}
+
+
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.ts b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.ts
new file mode 100644
index 000000000..609bc8186
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/filters/reference-listing-filters.component.ts
@@ -0,0 +1,94 @@
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
+import { IsActive } from '@app/core/common/enum/is-active.enum';
+import { TenantFilter } from '@app/core/query/tenant.lookup';
+import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
+import { BaseComponent } from '@common/base/base.component';
+import { nameof } from 'ts-simple-nameof';
+
+@Component({
+ selector: 'app-reference-listing-filters',
+ templateUrl: './reference-listing-filters.component.html',
+ styleUrls: ['./reference-listing-filters.component.scss']
+})
+export class ReferenceListingFiltersComponent extends BaseComponent implements OnInit, OnChanges {
+
+ @Input() readonly filter: TenantFilter;
+ @Output() filterChange = new EventEmitter();
+
+ // * State
+ internalFilters: ReferenceListingFilters = this._getEmptyFilters();
+
+ protected appliedFilterCount: number = 0;
+ constructor(
+ public enumUtils: EnumUtils,
+ ) { super(); }
+
+ ngOnInit() {
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ const filterChange = changes[nameof(x => x.filter)]?.currentValue as TenantFilter;
+ if (filterChange) {
+ this.updateFilters()
+ }
+ }
+
+
+ onSearchTermChange(searchTerm: string): void {
+ this.applyFilters()
+ }
+
+
+ protected updateFilters(): void {
+ this.internalFilters = this._parseToInternalFilters(this.filter);
+ this.appliedFilterCount = this._computeAppliedFilters(this.internalFilters);
+ }
+
+ protected applyFilters(): void {
+ const { isActive, like } = this.internalFilters ?? {}
+ this.filterChange.emit({
+ ...this.filter,
+ like,
+ isActive: isActive ? [IsActive.Active] : [IsActive.Inactive]
+ })
+ }
+
+
+ private _parseToInternalFilters(inputFilter: TenantFilter): ReferenceListingFilters {
+ if (!inputFilter) {
+ return this._getEmptyFilters();
+ }
+
+ let { excludedIds, ids, isActive, like } = inputFilter;
+
+ return {
+ isActive: (isActive ?? [])?.includes(IsActive.Active) || !isActive?.length,
+ like: like
+ }
+
+ }
+
+ private _getEmptyFilters(): ReferenceListingFilters {
+ return {
+ isActive: true,
+ like: null,
+ }
+ }
+
+ private _computeAppliedFilters(filters: ReferenceListingFilters): number {
+ let count = 0;
+ if (filters?.isActive) {
+ count++
+ }
+ return count;
+ }
+
+ clearFilters() {
+ this.internalFilters = this._getEmptyFilters();
+ }
+}
+
+interface ReferenceListingFilters {
+ isActive: boolean;
+ like: string;
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.html b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.html
new file mode 100644
index 000000000..c1a42cc4b
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
{{'REFERENCE-LISTING.TITLE' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item?.name | nullifyValue}}
+
+
+
+
+
+ {{'REFERENCE-LISTING.FIELDS.CREATED-AT' | translate}}:
+
+ {{item?.createdAt | dateTimeFormatter : 'short' | nullifyValue}}
+
+
+
+
+
+
+ {{'REFERENCE-LISTING.FIELDS.UPDATED-AT' | translate}}:
+
+ {{item?.updatedAt | dateTimeFormatter : 'short' | nullifyValue}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.scss b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.scss
new file mode 100644
index 000000000..6e1b48814
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.scss
@@ -0,0 +1,60 @@
+.description-template-type-listing {
+ margin-top: 1.3rem;
+ margin-left: 1rem;
+ margin-right: 2rem;
+
+ .mat-header-row{
+ background: #f3f5f8;
+ }
+ .mat-card {
+ margin: 16px 0;
+ padding: 0px;
+ }
+
+ .mat-row {
+ cursor: pointer;
+ min-height: 4.5em;
+ }
+
+ mat-row:hover {
+ background-color: #eef5f6;
+ }
+ .mat-fab-bottom-right {
+ float: right;
+ z-index: 5;
+ }
+}
+.create-btn {
+ border-radius: 30px;
+ background-color: var(--secondary-color);
+ padding-left: 2em;
+ padding-right: 2em;
+ // color: #000;
+
+ .button-text{
+ display: inline-block;
+ }
+}
+
+.dlt-btn {
+ color: rgba(0, 0, 0, 0.54);
+}
+
+.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;
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.ts b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.ts
new file mode 100644
index 000000000..f1250d2c5
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/listing/reference-listing.component.ts
@@ -0,0 +1,175 @@
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { ActivatedRoute, Router } from '@angular/router';
+import { IsActive } from '@app/core/common/enum/is-active.enum';
+import { Reference } from '@app/core/model/reference/reference';
+import { ReferenceLookup } from '@app/core/query/reference.lookup';
+import { AuthService } from '@app/core/services/auth/auth.service';
+import { ReferenceService } from '@app/core/services/reference/reference.service';
+import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
+import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
+import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
+import { BaseListingComponent } from '@common/base/base-listing-component';
+import { PipeService } from '@common/formatting/pipe.service';
+import { DataTableDateTimeFormatPipe } from '@common/formatting/pipes/date-time-format.pipe';
+import { QueryResult } from '@common/model/query-result';
+import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
+import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
+import { ColumnDefinition, ColumnsChangedEvent, HybridListingComponent, PageLoadEvent } from '@common/modules/hybrid-listing/hybrid-listing.component';
+import { Guid } from '@common/types/guid';
+import { TranslateService } from '@ngx-translate/core';
+import { Observable } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { nameof } from 'ts-simple-nameof';
+
+@Component({
+ templateUrl: './REFERENCE-LISTING.component.html',
+ styleUrls: ['./REFERENCE-LISTING.component.scss']
+})
+export class ReferenceListingComponent extends BaseListingComponent implements OnInit {
+ publish = false;
+ userSettingsKey = { key: 'ReferenceListingUserSettings' };
+ propertiesAvailableForOrder: ColumnDefinition[];
+
+ @ViewChild('actions', { static: true }) actions?: TemplateRef;
+ @ViewChild(HybridListingComponent, { static: true }) hybridListingComponent: HybridListingComponent;
+
+ private readonly lookupFields: string[] = [
+ nameof(x => x.id),
+ nameof(x => x.label),
+ nameof(x => x.source),
+ nameof(x => x.type),
+ nameof(x => x.updatedAt),
+ nameof(x => x.createdAt),
+ nameof(x => x.hash),
+ nameof(x => x.isActive)
+ ];
+
+ rowIdentity = x => x.id;
+
+ constructor(
+ protected router: Router,
+ protected route: ActivatedRoute,
+ protected uiNotificationService: UiNotificationService,
+ protected httpErrorHandlingService: HttpErrorHandlingService,
+ protected queryParamsService: QueryParamsService,
+ private ReferenceService: ReferenceService,
+ public authService: AuthService,
+ private pipeService: PipeService,
+ public enumUtils: EnumUtils,
+ private language: TranslateService,
+ private dialog: MatDialog
+ ) {
+ super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService);
+ // Lookup setup
+ // Default lookup values are defined in the user settings class.
+ this.lookup = this.initializeLookup();
+ }
+
+ ngOnInit() {
+ super.ngOnInit();
+ }
+
+ protected initializeLookup(): ReferenceLookup {
+ const lookup = new ReferenceLookup();
+ lookup.metadata = { countAll: true };
+ lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE };
+ lookup.isActive = [IsActive.Active];
+ lookup.order = { items: [this.toDescSortField(nameof(x => x.createdAt))] };
+ this.updateOrderUiFields(lookup.order);
+
+ lookup.project = {
+ fields: this.lookupFields
+ };
+
+ return lookup;
+ }
+
+ protected setupColumns() {
+ this.gridColumns.push(...[{
+ prop: nameof(x => x.label),
+ sortable: true,
+ languageName: 'REFERENCE-LISTING.FIELDS.LABEL'
+ },
+ {
+ prop: nameof(x => x.source),
+ sortable: true,
+ languageName: 'REFERENCE-LISTING.FIELDS.SOURCE',
+ },
+ {
+ prop: nameof(x => x.type),
+ sortable: true,
+ languageName: 'REFERENCE-LISTING.FIELDS.TYPE',
+ },
+ {
+ prop: nameof(x => x.createdAt),
+ sortable: true,
+ languageName: 'REFERENCE-LISTING.FIELDS.CREATED-AT',
+ pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short')
+ },
+ {
+ prop: nameof(x => x.updatedAt),
+ sortable: true,
+ languageName: 'REFERENCE-LISTING.FIELDS.UPDATED-AT',
+ pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short')
+ },
+ {
+ alwaysShown: true,
+ cellTemplate: this.actions,
+ maxWidth: 120
+ }
+ ]);
+ this.propertiesAvailableForOrder = this.gridColumns.filter(x => x.sortable);
+ }
+
+ //
+ // Listing Component functions
+ //
+ onColumnsChanged(event: ColumnsChangedEvent) {
+ super.onColumnsChanged(event);
+ this.onColumnsChangedInternal(event.properties.map(x => x.toString()));
+ }
+
+ private onColumnsChangedInternal(columns: string[]) {
+ // Here are defined the projection fields that always requested from the api.
+ const fields = new Set(this.lookupFields);
+ this.gridColumns.map(x => x.prop)
+ .filter(x => !columns?.includes(x as string))
+ .forEach(item => {
+ fields.delete(item as string)
+ });
+ this.lookup.project = { fields: [...fields] };
+ this.onPageLoad({ offset: 0 } as PageLoadEvent);
+ }
+
+ protected loadListing(): Observable> {
+ return this.ReferenceService.query(this.lookup);
+ }
+
+ public deleteType(id: Guid) {
+ if (id) {
+ const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
+ data: {
+ isDeleteConfirmation: true,
+ 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')
+ }
+ });
+ dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
+ if (result) {
+ this.ReferenceService.delete(id).pipe(takeUntil(this._destroyed))
+ .subscribe(
+ complete => this.onCallbackSuccess(),
+ error => this.onCallbackError(error)
+ );
+ }
+ });
+ }
+ }
+
+ onCallbackSuccess(): void {
+ this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success);
+ this.ngOnInit();
+ }
+}
diff --git a/dmp-frontend/src/app/ui/admin/reference/reference.module.ts b/dmp-frontend/src/app/ui/admin/reference/reference.module.ts
new file mode 100644
index 000000000..8bcc715e9
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/reference.module.ts
@@ -0,0 +1,41 @@
+import { DragDropModule } from '@angular/cdk/drag-drop';
+import { NgModule } from "@angular/core";
+import { AutoCompleteModule } from "@app/library/auto-complete/auto-complete.module";
+import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
+import { CommonFormattingModule } from '@common/formatting/common-formatting.module';
+import { CommonFormsModule } from '@common/forms/common-forms.module';
+import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
+import { HybridListingModule } from "@common/modules/hybrid-listing/hybrid-listing.module";
+import { TextFilterModule } from "@common/modules/text-filter/text-filter.module";
+import { UserSettingsModule } from "@common/modules/user-settings/user-settings.module";
+import { CommonUiModule } from '@common/ui/common-ui.module';
+import { NgxDropzoneModule } from "ngx-dropzone";
+import { ReferenceRoutingModule } from './reference.routing';
+import { ReferenceEditorComponent } from './editor/reference-editor.component';
+import { ReferenceListingComponent } from './listing/reference-listing.component';
+import { ReferenceListingFiltersComponent } from './listing/filters/reference-listing-filters.component';
+import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
+
+@NgModule({
+ imports: [
+ CommonUiModule,
+ CommonFormsModule,
+ UrlListingModule,
+ ConfirmationDialogModule,
+ ReferenceRoutingModule,
+ NgxDropzoneModule,
+ DragDropModule,
+ AutoCompleteModule,
+ HybridListingModule,
+ TextFilterModule,
+ UserSettingsModule,
+ CommonFormattingModule,
+ RichTextEditorModule
+ ],
+ declarations: [
+ ReferenceEditorComponent,
+ ReferenceListingComponent,
+ ReferenceListingFiltersComponent
+ ]
+})
+export class ReferenceModule { }
diff --git a/dmp-frontend/src/app/ui/admin/reference/reference.routing.ts b/dmp-frontend/src/app/ui/admin/reference/reference.routing.ts
new file mode 100644
index 000000000..758a54610
--- /dev/null
+++ b/dmp-frontend/src/app/ui/admin/reference/reference.routing.ts
@@ -0,0 +1,58 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { AdminAuthGuard } from '@app/core/admin-auth-guard.service';
+import { ReferenceEditorComponent } from './editor/reference-editor.component';
+import { ReferenceListingComponent } from './listing/reference-listing.component';
+import { AppPermission } from '@app/core/common/enum/permission.enum';
+import { AuthGuard } from '@app/core/auth-guard.service';
+import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
+import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service';
+import { ReferenceEditorResolver } from './editor/reference-editor.resolver';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ReferenceListingComponent,
+ canActivate: [AuthGuard]
+ },
+ {
+ path: 'new',
+ canActivate: [AuthGuard],
+ component: ReferenceEditorComponent,
+ canDeactivate: [PendingChangesGuard],
+ data: {
+ authContext: {
+ permissions: [AppPermission.EditReference]
+ },
+ ...BreadcrumbService.generateRouteDataConfiguration({
+ title: 'BREADCRUMBS.NEW-TENANT'
+ })
+ }
+ },
+ {
+ path: ':id',
+ canActivate: [AuthGuard],
+ component: ReferenceEditorComponent,
+ canDeactivate: [PendingChangesGuard],
+ resolve: {
+ 'entity': ReferenceEditorResolver
+ },
+ data: {
+ ...BreadcrumbService.generateRouteDataConfiguration({
+ title: 'BREADCRUMBS.EDIT-TENANT'
+ }),
+ authContext: {
+ permissions: [AppPermission.EditReference]
+ }
+ }
+
+ },
+ { path: '**', loadChildren: () => import('@common/modules/page-not-found/page-not-found.module').then(m => m.PageNotFoundModule) },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: [ReferenceEditorResolver]
+})
+export class ReferenceRoutingModule { }
diff --git a/dmp-frontend/src/app/ui/admin/tenant/listing/tenant-listing.component.html b/dmp-frontend/src/app/ui/admin/tenant/listing/tenant-listing.component.html
index 827f5421f..93669a2f5 100644
--- a/dmp-frontend/src/app/ui/admin/tenant/listing/tenant-listing.component.html
+++ b/dmp-frontend/src/app/ui/admin/tenant/listing/tenant-listing.component.html
@@ -9,7 +9,7 @@
@@ -78,15 +75,6 @@
-
-
@@ -101,7 +89,6 @@
delete
{{'TENANT-LISTING.ACTIONS.DELETE' | translate}}
-
diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts
index 3de6e9d34..a0a54b546 100644
--- a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts
+++ b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts
@@ -53,6 +53,7 @@ export const ADMIN_ROUTES: RouteInfo[] = [
{ path: '/dmp-blueprints', title: 'SIDE-BAR.DMP-BLUEPRINTS', icon: 'library_books' },
{ path: '/description-templates', title: 'SIDE-BAR.DESCRIPTION-TEMPLATES', icon: 'library_books' },
{ path: '/description-template-type', title: 'SIDE-BAR.DESCRIPTION-TEMPLATE-TYPES', icon: 'library_books' },
+ { path: '/references', title: 'SIDE-BAR.REFERENCES', icon: 'library_books' },
{ path: '/reference-type', title: 'SIDE-BAR.REFERENCE-TYPES', icon: 'library_books' },
{ path: '/tenants', title: 'SIDE-BAR.TENANTS', icon: 'library_books' },
{ path: '/users', title: 'SIDE-BAR.USERS', icon: 'people' },
diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json
index 60414cdc1..114d55643 100644
--- a/dmp-frontend/src/assets/i18n/en.json
+++ b/dmp-frontend/src/assets/i18n/en.json
@@ -173,7 +173,8 @@
"LANGUAGE": "Language",
"SIGN-IN": "Sign in to account",
"REFERENCE-TYPES": "Reference Types",
- "TENANTS": "Tenants"
+ "TENANTS": "Tenants",
+ "REFERENCES": "References"
},
"FILE-TYPES": {
"PDF": "PDF",
@@ -340,7 +341,8 @@
"FEEDBACK": "Send feedback",
"SUPPORTIVE-MATERIAL": "Supportive Material",
"REFERENCE-TYPES":"Reference Types",
- "TENANTS": "Tenants"
+ "TENANTS": "Tenants",
+ "REFERENCES": "References"
},
"DESCRIPTION-TEMPLATE-EDITOR": {
"TITLE": {
@@ -1109,6 +1111,34 @@
"SUCCESSFUL-DELETE": "Successful Delete",
"UNSUCCESSFUL-DELETE": "This item could not be deleted."
},
+ "REFERENCE-LISTING": {
+ "TITLE": "References",
+ "CREATE": "Create Reference",
+ "FIELDS": {
+ "LABEL": "Label",
+ "SOURCE": "Source",
+ "TYPE": "Type",
+ "UPDATED-AT": "Updated",
+ "CREATED-AT": "Created"
+ },
+ "FILTER": {
+ "TITLE": "Filters",
+ "IS-ACTIVE": "Is Active",
+ "CANCEL": "Cancel",
+ "APPLY-FILTERS": "Apply filters"
+ },
+ "CONFIRM-DELETE-DIALOG": {
+ "MESSAGE": "Would you like to delete this Reference?",
+ "CONFIRM-BUTTON": "Yes, delete",
+ "CANCEL-BUTTON": "No"
+ },
+ "ACTIONS": {
+ "DELETE": "Delete",
+ "EDIT": "Edit"
+ },
+ "SUCCESSFUL-DELETE": "Successful Delete",
+ "UNSUCCESSFUL-DELETE": "This item could not be deleted."
+ },
"DATASET-UPLOAD": {
"TITLE": "Import Dataset",
"UPLOAD-BUTTON": "Upload",
@@ -1233,6 +1263,36 @@
"CANCEL-BUTTON": "No"
}
},
+ "REFERENCE-EDITOR": {
+ "NEW": "New Reference",
+ "FIELDS": {
+ "LABEL": "Label",
+ "TYPE": "Type",
+ "DESCRIPTION": "Description",
+ "DESCRIPTION-PLACEHOLDER": "Reference description",
+ "REFERENCE":"reference",
+ "ABBREVIATION": "abbreviation",
+ "SOURCE": "source",
+ "SOURCE-TYPE":"Source Type",
+ "FIELDS":"Fields",
+ "FIELD":"Field",
+ "CODE":"Code",
+ "DATA-TYPE":"Data Type",
+ "VALUE":"Value"
+ },
+ "ACTIONS": {
+ "SAVE": "Save",
+ "CANCEL": "Cancel",
+ "DELETE": "Delete",
+ "ADD-FIELD": "Add Field",
+ "REMOVE-FIELD": "Remove Field"
+ },
+ "CONFIRM-DELETE-DIALOG": {
+ "MESSAGE": "Would you like to delete this Rederence?",
+ "CONFIRM-BUTTON": "Yes, delete",
+ "CANCEL-BUTTON": "No"
+ }
+ },
"DMP-BLUEPRINT-EDITOR": {
"TITLE": {
"NEW": "New DMP Blueprint",
@@ -1869,6 +1929,15 @@
"REFERENCE-TYPE-EXTERNAL-API-HTTP-METHOD-TYPE":{
"GET": "GET",
"POST": "POST"
+ },
+ "REFERENCE-TYPE":{
+ "TAXONOMY": "Taxonomy",
+ "LICENCE": "License",
+ "ORGANISATION": "Organization"
+ },
+ "REFERENCE-SOURCE-TYPE":{
+ "INTERNAL": "Internal",
+ "EXTERNAL": "External"
}
},
"ADDRESEARCHERS-EDITOR": {