diff --git a/dmp-backend/web/src/main/resources/config/permissions.yml b/dmp-backend/web/src/main/resources/config/permissions.yml index 75a32ef8f..84d4ebdc3 100644 --- a/dmp-backend/web/src/main/resources/config/permissions.yml +++ b/dmp-backend/web/src/main/resources/config/permissions.yml @@ -613,3 +613,24 @@ permissions: clients: [ ] allowAnonymous: false allowAuthenticated: false + + # DescriptionReference Permissions + BrowseDescriptionTag: + roles: + - Admin + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + EditDescriptionTag: + roles: + - Admin + clients: [ ] + allowAnonymous: false + allowAuthenticated: false + DeleteDescriptionTag: + roles: + - Admin + claims: [ ] + clients: [ ] + allowAnonymous: false + allowAuthenticated: false 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 376e14a99..e3b7fb10a 100644 --- a/dmp-frontend/src/app/core/common/enum/permission.enum.ts +++ b/dmp-frontend/src/app/core/common/enum/permission.enum.ts @@ -9,6 +9,11 @@ export enum AppPermission { EditDmpBlueprint = "EditDmpBlueprint", DeleteDmpBlueprint = "DeleteDmpBlueprint", + //DmpBlueprint + BrowseDescription = "BrowseDescription", + EditDescription = "EditDescription", + DeleteDescription= "DeleteDescription", + //DescriptionTemplateType BrowseDescriptionTemplate = "BrowseDescriptionTemplate", EditDescriptionTemplate = "EditDescriptionTemplate", @@ -39,7 +44,7 @@ export enum AppPermission { EditUser = "EditUser", DeleteUser = "DeleteUser", ExportUsers = "ExportUsers", - + //Reference BrowseReference = "BrowseReference", EditReference = "EditReference", diff --git a/dmp-frontend/src/app/core/model/description/description-reference.ts b/dmp-frontend/src/app/core/model/description/description-reference.ts deleted file mode 100644 index f63a3c8e2..000000000 --- a/dmp-frontend/src/app/core/model/description/description-reference.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model"; -import { Guid } from "@common/types/guid"; -import { Reference } from "../reference/reference"; -import { Description } from "./description"; - - - -export interface DescriptionReference extends BaseEntity { - description?: Description; - reference?: Reference; - data: String; -} - -// -// Persist -// -export interface DescriptionPersist extends BaseEntityPersist { - descriptionId: Guid; - referenceId: Guid; - data: String; -} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/description/description.ts b/dmp-frontend/src/app/core/model/description/description.ts index 522385e32..84723774c 100644 --- a/dmp-frontend/src/app/core/model/description/description.ts +++ b/dmp-frontend/src/app/core/model/description/description.ts @@ -1,11 +1,11 @@ import { DescriptionStatus } from "@app/core/common/enum/description-status"; import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model"; import { Guid } from "@common/types/guid"; -import { Dmp, DmpDescriptionTemplatePersist } from "../dmp/dmp"; import { DescriptionTemplate } from "../description-template/description-template"; -import { User } from "../user/user"; +import { Dmp, DmpDescriptionTemplatePersist } from "../dmp/dmp"; import { Reference, ReferencePersist } from "../reference/reference"; import { Tag } from "../tag/tag"; +import { User } from "../user/user"; @@ -13,7 +13,7 @@ export interface Description extends BaseEntity { label: string; properties: PropertyDefinition; status: DescriptionStatus; - description?: String; + description?: string; createdBy: User; finalizedAt: Date; descriptionReferences: DescriptionReference[]; @@ -60,7 +60,7 @@ export interface DescriptionPersist extends BaseEntityPersist { references: DescriptionReferencePersist[]; } -export interface PropertyDefinitionPersist{ +export interface PropertyDefinitionPersist { fields: DescriptionFieldPersist[]; } @@ -69,6 +69,14 @@ export interface DescriptionFieldPersist { value: string; } -export interface DescriptionReferencePersist extends BaseEntity { +export interface DescriptionReferencePersist { + id: Guid; reference?: ReferencePersist; + hash: string; +} + +export interface DescriptionStatusPersist { + id: Guid; + status: DescriptionStatus; + hash: string; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index 3d5a18cf6..29966f13d 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -1,24 +1,24 @@ +import { DmpAccessType } from '@app/core/common/enum/dmp-access-type'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; +import { DmpVersionStatus } from '@app/core/common/enum/dmp-version-status'; +import { BaseEntity, BaseEntityPersist } from '@common/base/base-entity.model'; +import { Guid } from '@common/types/guid'; import { DatasetWizardModel } from '../dataset/dataset-wizard'; +import { DescriptionTemplate } from '../description-template/description-template'; +import { Description } from '../description/description'; +import { EntityDoi } from '../entity-doi/entity-doi'; import { FunderModel } from "../funder/funder"; import { GrantListingModel } from "../grant/grant-listing"; import { OrganizationModel } from "../organisation/organization"; import { ProjectModel } from "../project/project"; +import { DmpReference, ReferencePersist } from '../reference/reference'; import { ResearcherModel } from "../researcher/researcher"; import { User, UserModel } from "../user/user"; import { UserInfoListingModel } from "../user/user-info-listing"; import { DmpDatasetProfile } from "./dmp-dataset-profile/dmp-dataset-profile"; import { DmpDynamicField } from "./dmp-dynamic-field"; import { DmpExtraField } from "./dmp-extra-field"; -import { BaseEntity, BaseEntityPersist } from '@common/base/base-entity.model'; -import { Description } from '../description/description'; -import { DmpReference, ReferencePersist } from '../reference/reference'; -import { DmpVersionStatus } from '@app/core/common/enum/dmp-version-status'; -import { DmpAccessType } from '@app/core/common/enum/dmp-access-type'; -import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; -import { Guid } from '@common/types/guid'; -import { DescriptionTemplate } from '../description-template/description-template'; -import { EntityDoi } from '../entity-doi/entity-doi'; export interface DmpModel { //TODO: Delete id: string; @@ -73,7 +73,7 @@ export interface Dmp extends BaseEntity { descriptions: Description[]; entityDois: EntityDoi[]; - + // TODO: delete // grant: GrantListingModel; // project: ProjectModel; @@ -153,4 +153,10 @@ export interface NewVersionDmpPersist { export interface DmpUserPersist { user: Guid; role: DmpUserRole; +} + +export interface DmpUserRemovePersist { + id: Guid; + dmpId: Guid; + role: DmpUserRole; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/query/dmp.lookup.ts b/dmp-frontend/src/app/core/query/dmp.lookup.ts index db95b39d7..454d077c7 100644 --- a/dmp-frontend/src/app/core/query/dmp.lookup.ts +++ b/dmp-frontend/src/app/core/query/dmp.lookup.ts @@ -16,7 +16,7 @@ export class DmpLookup extends Lookup implements DmpFilter { accessTypes: DmpAccessType[]; versions: Number[]; dmpDescriptionTemplateSubQuery: DmpDescriptionTemplateLookup; - + groupIds: Guid[]; constructor() { super(); @@ -32,4 +32,5 @@ export interface DmpFilter { statuses: DmpStatus[]; accessTypes: DmpAccessType[]; versions: Number[] + groupIds: Guid[]; } diff --git a/dmp-frontend/src/app/core/services/description/description.service.ts b/dmp-frontend/src/app/core/services/description/description.service.ts index 0a1b90308..aa82928f0 100644 --- a/dmp-frontend/src/app/core/services/description/description.service.ts +++ b/dmp-frontend/src/app/core/services/description/description.service.ts @@ -1,7 +1,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { Description, DescriptionPersist, PublicDescription } from '@app/core/model/description/description'; +import { Description, DescriptionPersist, DescriptionStatusPersist, PublicDescription } from '@app/core/model/description/description'; import { DescriptionLookup } from '@app/core/query/description.lookup'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; @@ -60,6 +60,14 @@ export class DescriptionService { catchError((error: any) => throwError(error))); } + persistStatus(item: DescriptionStatusPersist, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/persist-status`; + + return this.http + .post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + delete(id: Guid): Observable { const url = `${this.apiBase}/${id}`; diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 1bc4b9bbd..958f64d48 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -21,7 +21,7 @@ import { DataTableRequest } from '../../model/data-table/data-table-request'; import { DatasetListingModel } from '../../model/dataset/dataset-listing'; import { DatasetProfileModel } from '../../model/dataset/dataset-profile'; import { DatasetsToBeFinalized } from '../../model/dataset/datasets-toBeFinalized'; -import { CloneDmpPersist, Dmp, DmpModel, DmpPersist, DmpUser, DmpUserPersist, NewVersionDmpPersist } from '../../model/dmp/dmp'; +import { CloneDmpPersist, Dmp, DmpModel, DmpPersist, DmpUser, DmpUserPersist, DmpUserRemovePersist, NewVersionDmpPersist } from '../../model/dmp/dmp'; import { DmpListingModel } from '../../model/dmp/dmp-listing'; import { DmpOverviewModel } from '../../model/dmp/dmp-overview'; import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria'; @@ -117,6 +117,14 @@ export class DmpServiceNew { catchError((error: any) => throwError(error))); } + removeUser(item: DmpUserRemovePersist, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/remove-user`; + + return this.http + .post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + downloadXML(id: Guid): Observable> { const url = `${this.apiBase}/xml/export/${id}`; let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml'); diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard-editor.model.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard-editor.model.ts deleted file mode 100644 index 47ec72a17..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard-editor.model.ts +++ /dev/null @@ -1,382 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; -import { ExternalDatasetType } from '@app/core/common/enum/external-dataset-type'; -import { DataRepositoryModel } from '@app/core/model/data-repository/data-repository'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; -import { DmpModel } from '@app/core/model/dmp/dmp'; -import { ExternalDatasetModel } from '@app/core/model/external-dataset/external-dataset'; -import { RegistryModel } from '@app/core/model/registry/registry'; -import { ServiceModel } from '@app/core/model/service/service'; -import { TagModel } from '@app/core/model/tag/tag'; -import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; -import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { ValidationContext } from '@common/forms/validation/validation-context'; - -export class DatasetWizardEditorModel { - public id: string; - public label: string; - public profile: DatasetProfileModel; - public uri: String; - public status: number; - public description: String; - public services: ExternalServiceEditorModel[] = []; - public registries: ExternalRegistryEditorModel[] = []; - public dataRepositories: ExternalDataRepositoryEditorModel[] = []; - public tags: ExternalTagEditorModel[] = []; - public externalDatasets: ExternalDatasetEditorModel[] = []; - public dmp: DmpModel; - public dmpSectionIndex: number; - public datasetProfileDefinition: DatasetDescriptionFormEditorModel; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - public isProfileLatestVersion: Boolean; - public modified: Date; - - fromModel(item: DatasetWizardModel): DatasetWizardEditorModel { - this.id = item.id; - this.label = item.label; - this.profile = item.profile; - this.uri = item.uri; - this.status = item.status; - this.description = item.description; - if (item.services) { this.services = item.services.map(x => new ExternalServiceEditorModel().fromModel(x)); } - if (item.registries) { this.registries = item.registries.map(x => new ExternalRegistryEditorModel().fromModel(x)); } - if (item.dataRepositories) { this.dataRepositories = item.dataRepositories.map(x => new ExternalDataRepositoryEditorModel().fromModel(x)); } - if (item.externalDatasets) { this.externalDatasets = item.externalDatasets.map(x => new ExternalDatasetEditorModel().fromModel(x)); } - this.dmp = item.dmp; - this.dmpSectionIndex = item.dmpSectionIndex; - if (item.datasetProfileDefinition) { this.datasetProfileDefinition = new DatasetDescriptionFormEditorModel().fromModel(item.datasetProfileDefinition); } - if (item.tags) { this.tags = item.tags.map(x => new ExternalTagEditorModel().fromModel(x)); } - this.isProfileLatestVersion = item.isProfileLatestVersion; - this.modified = new Date(item.modified); - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - const formBuilder = new UntypedFormBuilder(); - const formGroup = formBuilder.group({ - id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], - label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], - uri: [{ value: this.uri, disabled: disabled }, context.getValidation('uri').validators], - status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], - description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], - dmp: [{ value: this.dmp, disabled: disabled }, context.getValidation('dmp').validators], - dmpSectionIndex: [{ value: this.dmpSectionIndex, disabled: disabled }, context.getValidation('dmpSectionIndex').validators], - //externalDatasets: [{ value: this.externalDatasets, disabled: disabled }, context.getValidation('externalDatasets').validators], - tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators], - //registries: [{ value: this.registries, disabled: disabled }, context.getValidation('registries').validators], - //dataRepositories: [{ value: this.dataRepositories, disabled: disabled }, context.getValidation('dataRepositories').validators], - //services: [{ value: this.services, disabled: disabled }, context.getValidation('services').validators], - profile: [{ value: this.profile, disabled: disabled }, context.getValidation('profile').validators], - modified: [{value: this.modified, disabled: disabled}, context.getValidation('modified').validators] - }); - - const externalDatasetsFormArray = new Array(); - //if (this.externalDatasets && this.externalDatasets.length > 0) { - this.externalDatasets.forEach(item => { - externalDatasetsFormArray.push(item.buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - }); - // } else { - // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - // } - formGroup.addControl('externalDatasets', formBuilder.array(externalDatasetsFormArray)); - - // const tagsFormArray = new Array(); - // if (this.tags && this.tags.length > 0) { - // this.tags.forEach(item => { - // tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled)); - // }); - // } else { - // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - // } - // formGroup.addControl('tags', formBuilder.array(tagsFormArray)); - - const registriesFormArray = new Array(); - //if (this.registries && this.registries.length > 0) { - this.registries.forEach(item => { - registriesFormArray.push(item.buildForm(context.getValidation('registries').descendantValidations, disabled)); - }); - // } else { - // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - // } - formGroup.addControl('registries', formBuilder.array(registriesFormArray)); - - const dataRepositoriesFormArray = new Array(); - //if (this.dataRepositories && this.dataRepositories.length > 0) { - this.dataRepositories.forEach(item => { - dataRepositoriesFormArray.push(item.buildForm(context.getValidation('dataRepositories').descendantValidations, disabled)); - }); - // } else { - // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - // } - formGroup.addControl('dataRepositories', formBuilder.array(dataRepositoriesFormArray)); - - const servicesFormArray = new Array(); - // if (this.services && this.services.length > 0) { - this.services.forEach(item => { - servicesFormArray.push(item.buildForm(context.getValidation('services').descendantValidations, disabled)); - }); - // } else { - // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); - // } - formGroup.addControl('services', formBuilder.array(servicesFormArray)); - - // const tagsFormArray = new Array(); - // this.tags.forEach(item => { - // tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled)); - // }); - // formGroup.addControl('tags', formBuilder.array(tagsFormArray)); - - if (this.datasetProfileDefinition) { formGroup.addControl('datasetProfileDefinition', this.datasetProfileDefinition.buildForm()); } - // formGroup.addControl('profile', this.profile.buildForm()); - return formGroup; - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - 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: 'dmpSectionIndex', validators: [BackendErrorValidator(this.validationErrorModel, 'dmpSectionIndex')] }); - baseContext.validation.push({ key: 'datasetProfileDefinition', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] }); - baseContext.validation.push({ key: 'tags', validators: [BackendErrorValidator(this.validationErrorModel, 'datasetProfileDefinition')] }); - baseContext.validation.push({ key: 'modified', validators: []}); - return baseContext; - } -} - -export class ExternalTagEditorModel { - public abbreviation: String; - public definition: String; - public id: String; - public name: String; - public reference: String; - public uri: String; - - constructor(id?: String, name?: String) { - this.id = id; - this.name = name; - } - - fromModel(item: TagModel): ExternalTagEditorModel { - this.id = item.id; - this.name = item.name; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - return new UntypedFormBuilder().group({ - id: [this.id], - name: [this.name] - }); - } -} - -export class ExternalServiceEditorModel { - public id: String; - public abbreviation: String; - public definition: String; - public uri: String; - public label: String; - public reference: String; - public source: String; - - constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) { - this.id = id; - this.abbreviation = abbreviation; - this.definition = definition; - this.uri = uri; - this.label = label; - this.reference = reference; - this.source = source; - } - - fromModel(item: ServiceModel): ExternalServiceEditorModel { - this.id = item.id; - this.abbreviation = item.abbreviation; - this.definition = item.definition; - this.uri = item.uri; - this.label = item.label; - this.reference = item.reference; - this.source = item.source; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - return new UntypedFormBuilder().group({ - id: [this.id], - abbreviation: [this.abbreviation], - label: [this.label, Validators.required], - reference: [this.reference], - uri: [this.uri, Validators.required], - definition: [this.definition], - source: [this.source] - }); - } -} - -export class ExternalRegistryEditorModel { - public abbreviation: String; - public definition: String; - public id: String; - public label: String; - public reference: String; - public uri: String; - public source: String - - constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) { - this.abbreviation = abbreviation; - this.definition = definition; - this.id = id; - this.label = label; - this.reference = reference; - this.uri = uri; - this.source = source; - } - - fromModel(item: RegistryModel): ExternalRegistryEditorModel { - this.abbreviation = item.abbreviation; - this.definition = item.definition; - this.id = item.id; - this.label = item.label; - this.reference = item.pid ? item.pid : item.reference; - this.uri = item.uri; - this.source = item.source - - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - return new UntypedFormBuilder().group({ - id: [this.id], - abbreviation: [this.abbreviation], - label: [this.label, Validators.required], - reference: [this.reference], - uri: [this.uri, Validators.required], - definition: [this.definition], - source: [this.source] - }); - } -} - -export class ExternalDatasetEditorModel { - - public abbreviation: String; - public id: String; - public name: String; - public reference: String; - public type: ExternalDatasetType; - public info: String; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - public source: String; - - constructor(id?: string, abbreviation?: string, name?: string, reference?: string, source?: String, info?: string, type?: ExternalDatasetType) { - this.id = id; - this.name = name; - this.abbreviation = abbreviation; - this.reference = reference; - this.info = info; - this.type = type; - this.source = source; - } - - fromModel(item: ExternalDatasetModel): ExternalDatasetEditorModel { - this.abbreviation = item.abbreviation; - this.id = item.id; - this.name = item.name; - this.reference = item.reference; - this.type = item.type; - this.info = item.info; - this.source = item.source; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - return new UntypedFormBuilder().group({ - id: [this.id], - abbreviation: [this.abbreviation], - name: [this.name, Validators.required], - reference: [this.reference], - type: [this.type], - info: [this.info], - source: [this.source] - }); - } -} - -export class ExternalDataRepositoryEditorModel { - public id: string; - public name: string; - public abbreviation: string; - public uri: string; - public reference: string; - public info: string; - public created: Date; - public modified: Date; - public source: string; - - constructor(id?: string, name?: string, abbreviation?: string, uri?: string, reference?: string, source?: string) { - this.id = id; - this.name = name; - this.abbreviation = abbreviation; - this.uri = uri; - this.reference = reference; - this.source = source; - } - - fromModel(item: DataRepositoryModel): ExternalDataRepositoryEditorModel { - this.id = item.id; - this.name = item.name; - this.abbreviation = item.abbreviation; - this.uri = item.uri; - this.info = item.info; - this.reference = item.pid; - this.source = item.source; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - return new UntypedFormBuilder().group({ - id: [this.id], - name: [this.name, [Validators.required]], - abbreviation: [this.abbreviation], - uri: [this.uri, [Validators.required]], - info: [this.info], - reference: [this.reference], - source: [this.source] - }); - } -} - -// export class TagModel implements Serializable { - -// public id: string; -// public name: string; - -// constructor(id?: string, name?: string) { -// this.id = id; -// this.name = name; -// } - -// fromJSONObject(item: any): TagModel { -// this.id = item.id; -// this.name = item.name; -// return this; -// } - -// buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { -// return new FormBuilder().group({ -// id: [this.id], -// name: [this.name] -// }); -// } -// } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.html b/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.html deleted file mode 100644 index 6f65a8697..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.html +++ /dev/null @@ -1,288 +0,0 @@ -
-
-
- - -
-
-
-
-
- -
{{'DMP-EDITOR.TITLE.ADD-DATASET' | translate}}
-
{{'DMP-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}
-
{{ formGroup.get('label').value }} ({{'DMP-EDITOR.CHANGES' | translate}})
-
- -
{{'DMP-EDITOR.TITLE.PREVIEW-DATASET' | translate}}
-
-
-
{{'DATASET-LISTING.TOOLTIP.TO-DMP' | translate}}
-
: {{ formGroup.get('dmp').value.label }}
- -
-
-
-
- - - - - - -
- - - -
- -
-
- - - - - - - - - - - - -
-
-
-
-
-
-
-
-
-
- chevron_left - {{'DATASET-WIZARD.ACTIONS.BACK-TO' | translate}} -
-
{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}
-
-
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
-
-
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
-
-
- -
-
-
-
- - -
-
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
- chevron_right -
-
-
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
- chevron_right -
- -
-
- -
-
-
- - -
-
-
-
-
- - - - - - diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.ts deleted file mode 100644 index bc71343f0..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.ts +++ /dev/null @@ -1,1507 +0,0 @@ -import { Location } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; -import { Component, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { ActivatedRoute, Router } from '@angular/router'; -import { DatasetStatus } from '@app/core/common/enum/dataset-status'; -import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { SaveType } from '@app/core/common/enum/save-type'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; -import { DmpModel } from '@app/core/model/dmp/dmp'; -import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; -import { LockModel } from '@app/core/model/lock/lock.model'; -import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; -import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; -import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; -import { RequestItem } from '@app/core/query/request-item'; -import { AuthService } from '@app/core/services/auth/auth.service'; -import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; -import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; -import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { - ExternalSourcesConfigurationService -} from '@app/core/services/external-sources/external-sources-configuration.service'; -import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; -import { LockService } from '@app/core/services/lock/lock.service'; -import { MatomoService } from '@app/core/services/matomo/matomo-service'; -import { - SnackBarNotificationLevel, - UiNotificationService -} from '@app/core/services/notification/ui-notification-service'; -import { FileUtils } from '@app/core/services/utilities/file-utils.service'; -import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; -import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; -import { - DatasetCopyDialogueComponent -} from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; -import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; -import { PrefillDatasetComponent } from "@app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component"; -// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; -// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; -import { ToCEntry, ToCEntryType } from "@app/ui/misc/dataset-description-form/dataset-description.component"; -import { - Link, - LinkToScroll, - TableOfContents -} from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; -import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; -import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { FormService } from '@common/forms/form-service'; -import { - FormValidationErrorsDialogComponent -} from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; -import { Guid } from '@common/types/guid'; -import { TranslateService } from '@ngx-translate/core'; -import * as FileSaver from 'file-saver'; -import { Observable, interval, of as observableOf } from 'rxjs'; -import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators'; - -@Component({ - selector: 'app-dataset-wizard-component', - templateUrl: 'dataset-wizard.component.html', - styleUrls: ['./dataset-wizard.component.scss'] -}) -export class DatasetWizardComponent extends CheckDeactivateBaseComponent implements OnInit {//IBreadCrumbComponent - canDeactivate(): boolean { - return !this.isDirty(); - } - - // breadCrumbs: Observable; - viewOnly = false; - editMode = false; - publicMode = false; - hasChanges = false; - isDiscarded = false; - formGroupRawValue: any; - saving = false; - - DatasetStatus = DatasetStatus; - dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - - datasetWizardModel: DatasetWizardEditorModel; - isNew = true; - isCopy = false; - formGroup: UntypedFormGroup = null; - datasetProfileDefinitionModel: DatasetDescriptionFormEditorModel; - - availableProfiles: DatasetProfileModel[] = []; - finalize: boolean = false; - itemId: string; - dmpId: string; - dmpSectionIndex: number; - availableDescriptionTemplates: DatasetProfileModel[] = []; - newDmpId: string; - publicId: string; - profileUpdateId: string; - downloadDocumentId: string; - isLinear = false; - lock: LockModel; - lockStatus: Boolean; - - step: number = 0; - stepOffset: number = 1; - - saveAnd = SaveType; - datasetSavedLinks: any = null; - - scrollTop: number; - tocScrollTop: number; - links: Link[] = []; - //the table seraches for elements to scroll on page with id (TOCENTRY_ID_PREFIX+fieldsetId) - TOCENTRY_ID_PREFIX = "TocEntRy"; - showtocentriesErrors = false; - @ViewChild('table0fContents') table0fContents: TableOfContents; - hintErrors: boolean = false; - datasetIsOnceSaved = false; - - fieldsetIdWithFocus: string; - visRulesService: VisibilityRulesService; - - constructor( - private datasetWizardService: DatasetWizardService, - private route: ActivatedRoute, - public snackBar: MatSnackBar, - public router: Router, - public language: TranslateService, - public externalSourcesService: ExternalSourcesService, - public dmpService: DmpService, - public dialog: MatDialog, - public externalSourcesConfigurationService: ExternalSourcesConfigurationService, - private uiNotificationService: UiNotificationService, - private formService: FormService, - private lockService: LockService, - private location: Location, - private authService: AuthService, - private configurationService: ConfigurationService, - private httpClient: HttpClient, - private matomoService: MatomoService, - private fileUtils: FileUtils - ) { - super(); - } - - ngOnInit() { - this.matomoService.trackPageView('Dataset Editor'); - this.route - .data - .pipe(takeUntil(this._destroyed)) - .subscribe(v => { - this.viewOnly = v['public']; - }); - - const dmpRequestItem: RequestItem = new RequestItem(); - dmpRequestItem.criteria = new DmpCriteria(); - - this.dmpAutoCompleteConfiguration = { - filterFn: this.searchDmp.bind(this), - initialItems: (extraData) => this.searchDmp(''), - displayFn: (item) => this.getDatasetDisplay(item), - titleFn: (item) => item['label'], - subtitleFn: (item) => this.language.instant('DATASET-WIZARD.FIRST-STEP.SUB-TITLE') + new Date(item['creationTime']).toISOString() - // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), - // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] - }; - - const params = this.route.snapshot.params; - const queryParams = this.route.snapshot.queryParams; - const data: any = this.route.snapshot.data; - this.itemId = params['id']; - this.dmpId = params['dmpId']; - this.dmpSectionIndex = parseInt(params['dmpSectionIndex']); - this.newDmpId = queryParams['newDmpId']; - this.publicId = params['publicId']; - this.profileUpdateId = params['updateId']; - this.finalize = data.finalize; - this.itemId ? this.downloadDocumentId = this.itemId : this.downloadDocumentId = this.publicId - - this.init(); - // this.route.params - // .pipe(takeUntil(this._destroyed)) - // .subscribe((params: Params) => { - // const itemId = params['id']; - // if (itemId != null) { setTimeout(() => this.stepper.selectedIndex = 2); } - // }); - } - - init() { - if (this.itemId != null && this.newDmpId == null) { - this.isNew = false; - this.datasetWizardService.getSingle(this.itemId) - .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { - this.lockStatus = lockStatus; - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); - this.dmpSectionIndex = this.datasetWizardModel.dmpSectionIndex; - this.needsUpdate(); - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: null, - // label: this.datasetWizardModel.label, - // url: '/datasets/edit/' + this.datasetWizardModel.id, - // notFoundResolver: [ - // { - // parentComponentName: null, - // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(), - // url: '/datasets' - // }, - // ] - // }]); - this.formGroup = this.datasetWizardModel.buildForm(); - let profiles = this.datasetWizardModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.datasetWizardModel.dmpSectionIndex)); - for (var profile of profiles) { - this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) - } - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) { - this.formGroup.disable(); - this.viewOnly = true; - } - if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { - const lockedBy: UserInfoListingModel = { - email: this.authService.getUserProfileEmail(), - id: this.authService.userId()?.toString(), - name: this.authService.getPrincipalName(), - role: 0 //TODO - //role: this.authService.getRoles()?.at(0) - } - this.lock = new LockModel(data.id, lockedBy); - - this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { - this.lock.id = Guid.parse(result); - interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); - }); - } - // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. - this.loadDatasetProfiles(); - this.registerFormListeners(); - - if (lockStatus) { - this.dialog.open(PopupNotificationDialogComponent, { - data: { - title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'), - message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE') - }, maxWidth: '30em' - }); - } - if (this.finalize && !this.lockStatus && !this.viewOnly) { - setTimeout(() => { - this.saveFinalize(); - }, 0); - } - // this.availableProfiles = this.datasetWizardModel.dmp.profiles; - }); - }, - error => { - switch (error.status) { - case 403: - this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-ALLOWED'), SnackBarNotificationLevel.Error); - break; - case 404: - this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error); - break; - default: - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.ERRORS.HTTP-REQUEST-ERROR'), SnackBarNotificationLevel.Error); - } - this.router.navigate(['/datasets/']); - return observableOf(null); - }); - } else if (this.dmpId != null) { - this.isNew = true; - this.dmpService.getSingle(this.dmpId).pipe(map(data => data as DmpModel)) - .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - this.datasetWizardModel = new DatasetWizardEditorModel(); - setTimeout(() => { - this.datasetWizardModel.dmp = data; - this.datasetWizardModel.dmpSectionIndex = this.dmpSectionIndex; - this.formGroup = this.datasetWizardModel.buildForm(); - let profiles = this.datasetWizardModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.dmpSectionIndex)); - for (var profile of profiles) { - this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) - } - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - this.formGroup.get('dmp').disable(); - const dialogRef = this.dialog.open(PrefillDatasetComponent, { - width: '590px', - minHeight: '200px', - restoreFocus: false, - data: { - availableProfiles: this.availableDescriptionTemplates, - datasetFormGroup: this.formGroup - }, - panelClass: 'custom-modalbox' - }); - dialogRef.afterClosed().subscribe(result => { - if (result) { - this.datasetWizardModel = this.datasetWizardModel.fromModel(result); - this.datasetWizardModel.dmp = data; - this.datasetWizardModel.dmpSectionIndex = this.dmpSectionIndex; - this.formGroup = this.datasetWizardModel.buildForm(); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - this.formGroup.get('dmp').disable(); - this.loadDatasetProfiles(); - this.registerFormListeners(); - } - }) - this.loadDatasetProfiles(); - this.registerFormListeners(); - // this.availableProfiles = data.profiles; - - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: null, - // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - // url: '/datasets', - // notFoundResolver: [ - // // { - // // parentComponentName: null, - // // label: this.datasetWizardModel.dmp.grant.label, - // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // // }, - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.label, - // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - // }] - // }]); - }); - }); - } else if (this.newDmpId != null) { - this.isNew = false; - this.isCopy = true; - this.datasetWizardService.getSingle(this.itemId) - .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { - this.lockStatus = lockStatus; - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); - this.dmpSectionIndex = this.datasetWizardModel.dmpSectionIndex; - this.datasetWizardModel.status = 0; - this.formGroup = this.datasetWizardModel.buildForm(); - this.formGroup.get('id').setValue(null); - this.dmpService.getSingleNoDatasets(this.newDmpId).pipe(map(data => data as DmpModel)) - .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - setTimeout(() => { - this.datasetWizardModel.dmp = data; - this.formGroup.get('dmp').setValue(this.datasetWizardModel.dmp); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - - this.loadDatasetProfiles(); - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: null, - // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - // url: '/datasets', - // notFoundResolver: [ - // // { - // // parentComponentName: null, - // // label: this.datasetWizardModel.dmp.grant.label, - // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // // }, - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.label, - // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - // } - // ] - // }]); - }); - }); - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) { - this.formGroup.disable(); - this.viewOnly = true; - } - if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { - const lockedBy: UserInfoListingModel = { - email: this.authService.getUserProfileEmail(), - id: this.authService.userId()?.toString(), - name: this.authService.getPrincipalName(), - role: 0 //TODO - //role: this.authService.getRoles()?.at(0) - } - this.lock = new LockModel(data.id, lockedBy); - - this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { - this.lock.id = Guid.parse(result); - interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); - }); - } - // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. - this.loadDatasetProfiles(); - // this.availableProfiles = data.dmp.profiles; - }) - }); - } else if (this.publicId != null) { // For Finalized -> Public Datasets - this.isNew = false; - this.datasetWizardService.getSinglePublic(this.publicId) - .pipe(takeUntil(this._destroyed)).pipe( - catchError((error: any) => { - this.uiNotificationService.snackBarNotification(error.error.message, SnackBarNotificationLevel.Error); - this.router.navigate(['/datasets/publicEdit/' + this.publicId]); - return observableOf(null); - })) - .subscribe(data => { - if (data) { - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); - this.formGroup = this.datasetWizardModel.buildForm(); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - this.formGroup.disable(); - this.viewOnly = true; - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - this.formGroup.get('dmp').setValue(this.datasetWizardModel.dmp); - const breadcrumbs = []; - breadcrumbs.push({ - parentComponentName: null, - label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), - url: '/explore-descriptions' - }); - breadcrumbs.push({ - parentComponentName: null, - label: this.datasetWizardModel.label, - url: '/datasets/publicEdit/' + this.datasetWizardModel.id - }); - // this.breadCrumbs = observableOf(breadcrumbs); - } - }); - this.publicMode = true; - } else if (this.profileUpdateId != null) { - this.datasetWizardService.updateDatasetProfile(this.profileUpdateId) - .pipe(takeUntil(this._destroyed)) - .subscribe(data => { - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - - this.needsUpdate(); - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: null, - // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - // url: '/datasets', - // notFoundResolver: [ - // // { - // // parentComponentName: null, - // // label: this.datasetWizardModel.dmp.grant.label, - // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // // }, - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.label, - // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - // }, - // ] - // }]); - this.formGroup = this.datasetWizardModel.buildForm(); - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - if (this.datasetWizardModel.status === DatasetStatus.Finalized) { - this.formGroup.disable(); - this.viewOnly = true; - } - // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. - this.loadDatasetProfiles(); - }); - - } else { - this.datasetWizardModel = new DatasetWizardEditorModel(); - this.formGroup = this.datasetWizardModel.buildForm(); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - if (this.datasetWizardModel.status === DatasetStatus.Finalized) { - this.formGroup.disable(); - this.viewOnly = true; - } - //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. - this.registerFormListeners(); - this.dmpValueChanged(null); - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: null, - // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), - // url: '/datasets/new/' - // }]); - } - } - - // private _listenersSubscription:Subscription = new Subscription(); - registerFormListeners() { - // const dmpSubscription = - this.formGroup.get('dmp').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.dmpValueChanged(x); - }); - // const profileSubscription = - this.formGroup.get('profile').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - if (x) { - this.showtocentriesErrors = false; - this.datasetProfileValueChanged(x.id); - this.formChanged(); - } - }); - // const labelSubscription = - this.formGroup.get('label').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - // const descriptionSubscription = - this.formGroup.get('description').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - // const uriSubscription = - this.formGroup.get('uri').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - // const tagsSubscription = - this.formGroup.get('tags').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - if (this.formGroup.get('datasetProfileDefinition')) { - // const datasetProfileDefinitionSubscription = - this.formGroup.get('datasetProfileDefinition').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - // this._listenersSubscription.add(datasetProfileDefinitionSubscription); - } - - // this._listenersSubscription.add(dmpSubscription); - // this._listenersSubscription.add(profileSubscription); - // this._listenersSubscription.add(labelSubscription); - // this._listenersSubscription.add(descriptionSubscription); - // this._listenersSubscription.add(uriSubscription); - // this._listenersSubscription.add(tagsSubscription); - } - - // private _unregisterFormListeners(){ - // this._listenersSubscription.unsubscribe(); - // this._listenersSubscription = new Subscription(); - // } - - dmpValueChanged(dmp: DmpListingModel) { - if (dmp) { - this.formGroup.get('profile').enable(); - this.loadDatasetProfiles(); - } else { - this.availableProfiles = []; - this.formGroup.get('profile').reset(); - this.formGroup.get('profile').disable(); - this.formGroup.removeControl('datasetProfileDefinition'); - } - } - - datasetProfileValueChanged(profiledId: string) { - if (profiledId && profiledId.length > 0) { - this.formGroup.removeControl('datasetProfileDefinition'); - this.getDefinition(profiledId); - } - } - - searchDmp(query: string): Observable { - const fields: Array = new Array(); - fields.push('-created'); - const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); - dmpDataTableRequest.criteria = new DmpCriteria(); - dmpDataTableRequest.criteria.like = query; - dmpDataTableRequest.criteria.status = DmpStatus.Draft; - return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(map(x => x.data)); - } - - loadDatasetProfiles() { - const datasetProfileRequestItem: RequestItem = new RequestItem(); - datasetProfileRequestItem.criteria = new DatasetProfileCriteria(); - datasetProfileRequestItem.criteria.id = this.formGroup.get('dmp').value.id; - if (datasetProfileRequestItem.criteria.id) { - this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem) - .pipe(takeUntil(this._destroyed)) - .subscribe(items => { - this.availableProfiles = items; - }); - } - } - - public formChanged() { - if (!this.isDiscarded) { - this.hasChanges = true; - } - } - - public cancel(): void { - if (!isNullOrUndefined(this.lock)) { - this.lockService.unlockTarget(this.datasetWizardModel.id).pipe(takeUntil(this._destroyed)).subscribe( - complete => { - this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/datasets']); - }, - error => { - this.formGroup.get('status').setValue(DmpStatus.Draft); - this.onCallbackError(error); - } - ) - } else { - this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/datasets']); - } - - } - - getDatasetDisplay(item: any): string { - if (!this.publicMode) { - return (item['status'] ? this.language.instant('TYPES.DATASET-STATUS.FINALISED').toUpperCase() : this.language.instant('TYPES.DATASET-STATUS.DRAFT').toUpperCase()) + ': ' + item['label']; - } else { - return item['label']; - } - } - - getDefinition(profileId: string) { - // if (this.formGroup.invalid) { setTimeout(() => this.stepper.selectedIndex = 0); return; } - this.datasetWizardService.getDefinition(profileId) - .pipe(takeUntil(this._destroyed)) - .subscribe(item => { - this.datasetWizardModel.datasetProfileDefinition = new DatasetDescriptionFormEditorModel().fromModel(item); - this.datasetProfileDefinitionModel = this.datasetWizardModel.datasetProfileDefinition; - this.formGroup.addControl('datasetProfileDefinition', this.datasetProfileDefinitionModel.buildForm()); - - // const datasetProfileDefinitionForm = this.datasetProfileDefinitionModel.buildForm(); - - // let profId = null; - // try{ - // profId = this.formGroup.get('profile').value.id; - // }catch{ - - // } - // if(this.formGroupRawValue && this.formGroupRawValue.datasetProfileDefinition && (this.formGroupRawValue.profile.id === profId)){ - // // this.formGroup.get('datasetProfileDefinition').patchValue( this.formGroupRawValue.datasetProfileDefinition); - // datasetProfileDefinitionForm.patchValue(this.formGroupRawValue.datasetProfileDefinition); - // } - - // this.formGroup.addControl('datasetProfileDefinition', datasetProfileDefinitionForm); - this.formGroup.get('datasetProfileDefinition').valueChanges - .pipe(debounceTime(600)) - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.formChanged(); - }); - }); - } - - // formSubmit(): void { - // if (!this.isFormValid()) { return; } - // this.onSubmit(); - // } - - public isFormValid() { - return this.formGroup.valid; - } - - public isSemiFormValid(formGroup: UntypedFormGroup): boolean { - var isValid: boolean = true; - Object.keys(formGroup.controls).forEach(controlName => { - if (controlName != 'datasetProfileDefinition' && !formGroup.get(controlName).disabled && !(formGroup.get(controlName).valid)) { - isValid = false; - } - }); - return isValid; - } - - // onSubmit(): void { - // this.datasetWizardService.createDataset(this.formGroup.value) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => { - // this.datasetWizardService.getSingle(complete.id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // result => { - // this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(result); - // } - // ); - // this.onCallbackSuccess(); - // }, - // error => this.onCallbackError(error) - // ); - // } - - - submit(saveType?: SaveType, onSuccess: Function = null, onError: Function = null) { - this.scrollTop = document.getElementById('dataset-editor-form').scrollTop; - this.tocScrollTop = document.getElementById('stepper-options').scrollTop; - this.datasetWizardService.createDataset(this.formGroup.getRawValue()) - .pipe(takeUntil(this._destroyed)) - .subscribe( - data => { - this.hasChanges = false; - this.datasetIsOnceSaved = true; - this.onCallbackSuccess(data, saveType); - if (onSuccess) { - onSuccess(); - } - }, - error => { - if (onError) { - onError(); - } - this.onCallbackError(error) - }); - } - - - private _getErrorMessage(formControl: AbstractControl, name: string): string[] { - const errors: string[] = []; - Object.keys(formControl.errors).forEach(key => { - if (key === 'required') { - errors.push(this.language.instant(name + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED'))); - } - // if (key === 'required') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + this.getPlaceHolder(formControl) + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')); } - else if (key === 'email') { - errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.EMAIL')); - } else if (key === 'min') { - errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MIN-VALUE', { 'min': formControl.getError('min').min })); - } else if (key === 'max') { - errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MAX-VALUE', { 'max': formControl.getError('max').max })); - } else { - errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + formControl.errors[key].message); - } - }); - return errors; - } - - private _getPlaceHolder(formControl: any): string { - if (formControl.nativeElement.localName === 'input' || formControl.nativeElement.localName === 'textarea' - || formControl.nativeElement.localName === 'richTextarea') { - return formControl.nativeElement.getAttribute('placeholder'); - } else if (formControl.nativeElement.localName === 'mat-select') { - return formControl.nativeElement.getAttribute('placeholder'); - } else if (formControl.nativeElement.localName === 'app-single-auto-complete') { - return (Array.from(formControl.nativeElement.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); - } else if (formControl.nativeElement.localName === 'app-multiple-auto-complete') { - return (Array.from(formControl.nativeElement.firstChild.firstChild.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); - } - } - - - private _buildSemiFormErrorMessages(): string[] {//not including datasetProfileDefinition - const errmess: string[] = []; - Object.keys(this.formGroup.controls).forEach(controlName => { - if (controlName != 'datasetProfileDefinition' && this.formGroup.get(controlName).invalid) { - errmess.push(...this._buildErrorMessagesForAbstractControl(this.formGroup.get(controlName), controlName)); - } - }) - - return errmess; - } - - // takes as an input an abstract control and gets its error messages[] - private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string): string[] { - const errmess: string[] = []; - - if (aControl.invalid) { - - if (aControl.errors) { - //check if has placeholder - if ((aControl).nativeElement !== undefined && (aControl).nativeElement !== null) { - const placeholder = this._getPlaceHolder(aControl); - if (placeholder) { - controlName = placeholder; - } - } - const errorMessage = this._getErrorMessage(aControl, controlName); - - errmess.push(...errorMessage); - } - - /*in case the aControl is FormControl then the it should have provided its error messages above. - No need to check case of FormControl below*/ - - if (aControl instanceof UntypedFormGroup) { - - const fg = aControl as UntypedFormGroup; - //check children - Object.keys(fg.controls).forEach(controlName => { - errmess.push(...this._buildErrorMessagesForAbstractControl(fg.get(controlName), controlName)); - }); - } else if (aControl instanceof UntypedFormArray) { - - const fa = aControl as UntypedFormArray; - - fa.controls.forEach((control, index) => { - errmess.push(...this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index + 1}`)); - }); - - } - } - - return errmess; - } - - save(saveType?: SaveType) { - this.saving = true; - Object.keys(this.formGroup.controls).forEach(controlName => { - if (controlName == 'datasetProfileDefinition') { - return; - } - this.formService.touchAllFormFields(this.formGroup.get(controlName)); - }) - - - // this.formService.touchAllFormFields(this.formGroup); - if (!this.isSemiFormValid(this.formGroup)) { - //build messages - const errorMessages = this._buildSemiFormErrorMessages(); - this.showValidationErrorsDialog(undefined, errorMessages); - this.hintErrors = true; - this.saving = false; - return; - } - this.submit(saveType); - } - - private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) { - if (errmess) { - const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { - disableClose: true, - autoFocus: false, - restoreFocus: false, - data: { - errorMessages: errmess, - projectOnly: projectOnly - }, - }); - } else { - - const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { - disableClose: true, - autoFocus: false, - restoreFocus: false, - data: { - formGroup: this.formGroup, - projectOnly: projectOnly - }, - }); - } - - } - - hasReversableStatus(): boolean { - if (this.formGroup.get('dmp').value) { - return (this.formGroup.get('dmp').value.status == DmpStatus.Draft && this.formGroup.get('status').value == DatasetStatus.Finalized); - } else { - return false; - } - } - - hasNotReversableStatus(): boolean { - if (this.formGroup.get('dmp').value && !this.publicMode) { - return (this.formGroup.get('dmp').value.status == DmpStatus.Finalized && this.formGroup.get('status').value == DatasetStatus.Finalized); - } else { - return false; - } - } - - reverse() { - - this.dialog.open(ConfirmationDialogComponent, { - data: { - message: this.language.instant('DATASET-WIZARD.ACTIONS.UNDO-FINALIZATION-QUESTION'), - confirmButton: this.language.instant('DATASET-WIZARD.ACTIONS.CONFIRM'), - cancelButton: this.language.instant('DATASET-WIZARD.ACTIONS.REJECT'), - }, - maxWidth: '30em' - }) - .afterClosed() - .pipe( - filter(x => x), - takeUntil(this._destroyed) - ).subscribe(result => { - if (result) { - // if (!this.isFormValid()) { return; } - this.formGroup.get('status').setValue(DatasetStatus.Draft); - this.submit(SaveType.finalize, () => { - this.viewOnly = false; - this.datasetWizardModel.status = DatasetStatus.Draft; - setTimeout(x => { - this.formGroup = null; - }); - setTimeout(x => { - this.formGroup = this.datasetWizardModel.buildForm(); - this.registerFormListeners(); - }); - }, () => { - this.formGroup.get('status').setValue(DatasetStatus.Finalized); - this.viewOnly = true; - }); - } else { - this.saving = false; - } - }); - - - } - - saveFinalize() { - // this.formService.touchAllFormFields(this.formGroup); - this.saving = true; - if (!this.isSemiFormValid(this.formGroup) || (this.table0fContents && this.table0fContents.hasVisibleInvalidFields())) { - // this.showValidationErrorsDialog(); - this.dialog.open(FormValidationErrorsDialogComponent, { - data: { - errorMessages: [this.language.instant('DATASET-WIZARD.MESSAGES.MISSING-FIELDS')] - } - }) - - - this.touchForm(); - this.hintErrors = true; - this.saving = false; - return; - } - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - restoreFocus: false, - data: { - message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'), - confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'), - cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'), - isDeleteConfirmation: false - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - // if (!this.isFormValid()) { return; } - this.formGroup.get('status').setValue(DatasetStatus.Finalized); - this.submit(SaveType.finalize, null, () => { - this.formGroup.get('status').setValue(DatasetStatus.Draft); - }); - } else { - this.saving = false; - } - }); - } - - onCallbackSuccess(data?: DatasetWizardModel, saveType?: SaveType): void { - this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - if (data) { - if (saveType === this.saveAnd.addNew) { - this.router.navigate(['/reload']).then(() => { - this.router.navigate(['/datasets', 'new', this.formGroup.get('dmp').value.id, this.dmpSectionIndex]); - }) - } else if (saveType === this.saveAnd.close) { - this.router.navigate(['/reload']).then(() => { - this.router.navigate(['/plans', 'edit', this.formGroup.get('dmp').value.id]); - }); - } else if (saveType === SaveType.finalize) { - this.router.navigate(['/reload']).then(() => { - this.router.navigate(['/datasets', 'edit', data.id]); - }); - } else { - this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); - this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; - // setTimeout(() => { this.formGroup = null; }); - setTimeout(() => { - this.formGroup.get('id').patchValue(data.id); - this.formGroup.get('modified').patchValue(data.modified); - this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); - this.hasChanges = false; - - // this.formGroup = this.datasetWizardModel.buildForm(); - // if (this.formGroup.get('datasetProfileDefinition')) { - // this.formGroup.removeControl('datasetProfileDefinition'); - // this.getDefinition(data.profile.id); - // this.maxStep = 1; - // } else { - // this.getDefinition(data.profile.id); - // this.maxStep = 1; - // } - }); - - setTimeout(() => { - document.getElementById('dataset-editor-form').scrollTop = this.scrollTop; - document.getElementById('stepper-options').scrollTop = this.tocScrollTop; - }, 500); - this.saving = false; - if (this.isNew) { - this.reloadDateset(this.datasetWizardModel.id); - } - // this.router.navigate(['/reload']).then(() => { this.router.navigate(['/datasets', 'edit', data.id]); }); - } - } else { - this.router.navigate(['/datasets']); - } - } - - onCallbackError(error: any) { - const errmes = error && error.message ? error.message as string : null; - let feedbackMessage = this.language.instant('DATASET-EDITOR.ERRORS.ERROR-OCCURED'); - if (errmes) { - feedbackMessage += errmes; - } - this.uiNotificationService.snackBarNotification(feedbackMessage, SnackBarNotificationLevel.Warning); - this.setErrorModel(error.error); - this.saving = false; - } - - public setErrorModel(validationErrorModel: ValidationErrorModel) { - Object.keys(validationErrorModel).forEach(item => { - (this.datasetWizardModel.validationErrorModel)[item] = (validationErrorModel)[item]; - }); - } - - downloadPDF(id: string): void { - this.datasetWizardService.downloadPDF(id) - .pipe(takeUntil(this._destroyed)) - .subscribe(response => { - const blob = new Blob([response.body], { type: 'application/pdf' }); - const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - - FileSaver.saveAs(blob, filename); - this.matomoService.trackDownload('datasets', "pdf", id); - }); - } - - downloadDOCX(id: string): void { - this.datasetWizardService.downloadDOCX(id) - .pipe(takeUntil(this._destroyed)) - .subscribe(response => { - const blob = new Blob([response.body], { type: 'application/msword' }); - const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - - FileSaver.saveAs(blob, filename); - this.matomoService.trackDownload('datasets', "docx", id); - }); - - } - - downloadXML(id: string): void { - this.datasetWizardService.downloadXML(id) - .pipe(takeUntil(this._destroyed)) - .subscribe(response => { - const blob = new Blob([response.body], { type: 'application/xml' }); - const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - - FileSaver.saveAs(blob, filename); - this.matomoService.trackDownload('datasets', "xml", id); - }); - } - - // advancedClicked() { - // const dialogRef = this.dialog.open(ExportMethodDialogComponent, { - // maxWidth: '500px', - // data: { - // message: "Download as:", - // XMLButton: "XML", - // documentButton: "Document", - // pdfButton: "PDF" - // } - // }); - // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - // if (result == "pdf") { - // this.downloadPDF(); - // } else if (result == "xml") { - // this.downloadXML(); - // } else if (result == "doc") { - // this.downloadDOCX(); - // } - // }); - // } - - public redirectToGrant() { - this.router.navigate(['grants/edit/' + this.datasetWizardModel.dmp.grant.id]); - } - - public redirectToDmp() { - this.router.navigate(['plans/edit/' + this.datasetWizardModel.dmp.id]); - } - - public enableForm() { - if (this.formGroup.get('status').value !== DatasetStatus.Finalized) { - this.editMode = true; - this.viewOnly = false; - this.formGroup.enable(); - } else { - this.datasetWizardService.unlock(this.formGroup.get('id').value) - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.editMode = true; - this.viewOnly = false; - this.datasetWizardModel.status = DatasetStatus.Draft; - this.formGroup.get('status').patchValue(DatasetStatus.Draft); - this.formGroup.enable(); - }); - } - } - - public disableForm() { - this.editMode = false; - //this.viewOnly = true; - this.formGroup.disable(); - } - - openConfirm(dmpLabel, id): void { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - maxWidth: '300px', - restoreFocus: false, - data: { - message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), - confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), - isDeleteConfirmation: true - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - this.datasetWizardService.delete(id) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(), - error => this.onCallbackError(error) - ); - } - }); - } - - openDmpSearchDialogue() { - const formControl = new UntypedFormControl(); - const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, { - width: '500px', - restoreFocus: false, - data: { - formControl: formControl, - datasetId: this.formGroup.value.id, - datasetProfileId: this.formGroup.value.profile, - datasetProfileExist: false, - confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'), - cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL') - } - }); - - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)) - .subscribe(result => { - if (result && result.datasetProfileExist) { - const newDmpId = result.formControl.value.id - this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } }); - } - }); - } - - needsUpdate() { - if (this.datasetWizardModel.isProfileLatestVersion || (this.datasetWizardModel.status === DatasetStatus.Finalized) - || (this.datasetWizardModel.isProfileLatestVersion == undefined && this.datasetWizardModel.status == undefined)) { - return false; - } else { - return true; - } - } - - linkToScroll: LinkToScroll; - - onStepFound(linkToScroll: LinkToScroll) { - this.linkToScroll = linkToScroll; - } - - private pumpLock() { - this.lock.touchedAt = new Date(); - this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { - if (!isNullOrUndefined(result)) { - this.lock.id = Guid.parse(result); - } else { - this.location.back(); - } - }); - } - - getEntryVisibleFieldSets(entry: ToCEntry): ToCEntry[] { - let fieldSets = []; - if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)) { - fieldSets.push(entry); - } else if (entry.type !== ToCEntryType.FieldSet) { - entry.subEntries.forEach(subEntry => { - fieldSets = fieldSets.concat(this.getEntryVisibleFieldSets(subEntry)); - }); - } - return fieldSets; - } - - get visibleFieldSets(): ToCEntry[] { - let fieldSets = []; - let arrays = this.table0fContents ? this.table0fContents.tocentries. - filter(entry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)).map(entry => { - return this.getEntryVisibleFieldSets(entry); - }) - : []; - arrays.forEach(array => { - fieldSets = fieldSets.concat(array); - }); - return fieldSets; - } - - getFirstFieldSet(entry: ToCEntry): ToCEntry { - if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)) { - return entry; - } else { - let subEntries = entry.subEntries.filter(subEntry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === subEntry.id)); - if (subEntries.length > 0) { - return this.getFirstFieldSet(subEntries[0]); - } else { - return null; - } - } - } - - public changeStep(selected: ToCEntry = null, execute: boolean = true) { - if (execute) { - if (selected) { - let fieldSet = this.getFirstFieldSet(selected); - let index = this.visibleFieldSets.findIndex(entry => entry.id === fieldSet.id); - this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5); - } else { - this.step = 0; - this.resetScroll(); - } - } - } - - get maxStep() { - return this.visibleFieldSets.length; - } - - public nextStep() { - if (this.step < this.maxStep) {//view is changing - this.step = Math.floor(this.step + 1); - let entry = this.visibleFieldSets[this.step - 1]; - this.table0fContents.onToCentrySelected(entry, false); - this.scroll(entry); - } - } - - public previousStep() { - if (this.step > 0) { - this.step = Math.ceil(this.step - 1); - if (this.step >= 1) { - let entry = this.visibleFieldSets[this.step - 1]; - this.table0fContents.onToCentrySelected(entry, false); - this.scroll(entry); - } else { - this.table0fContents.onToCentrySelected(null, false); - this.resetScroll(); - } - } - } - - private resetScroll() { - document.getElementById('dataset-editor-form').scrollTop = 0; - } - - private scroll(entry: ToCEntry) { - document.getElementById(entry.id).scrollIntoView(); - } - - isDirty() { - return this.formGroup.dirty && this.hasChanges; // do we need this.formGroup.dirty - } - - discardChanges() { - // this.isDiscarded = true; - // this.hasChanges = false; - // this.hintErrors = false; - let messageText = ""; - let confirmButtonText = ""; - let cancelButtonText = ""; - let isDeleteConfirmation = false; - - if (this.isNew && !this.datasetIsOnceSaved) { - - messageText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-MESSAGE'); - confirmButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-CONFIRM'); - cancelButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-DENY'); - isDeleteConfirmation = true; - - // Object.keys(this.formGroup['controls']).forEach((key: string) => { - // if (key !== 'dmp' && (key!== 'profile')) { - // if(key === 'datasetProfileDefinition'){ - // this.formGroup.get(key).patchValue(this.datasetProfileDefinitionModel.buildForm().getRawValue); - // }else{ - // this.formGroup.get(key).reset(); - // } - - // } - // }); - } else { - - messageText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-MESSAGE'); - confirmButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-CONFIRM'); - cancelButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-DENY'); - isDeleteConfirmation = false; - - // this.isDiscarded = true; - // this.hasChanges = false; - // this.hintErrors = false; - // // this._unregisterFormListeners(); - // this.formGroup.patchValue(JSON.parse(JSON.stringify(this.formGroupRawValue))); - // // this.registerFormListeners(); - // this.isDiscarded = false; - - - } - - - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - restoreFocus: false, - data: { - message: messageText, - confirmButton: confirmButtonText, - cancelButton: cancelButtonText, - isDeleteConfirmation: true - }, - maxWidth: '40em' - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - // this.backToDmp(this.formGroup.get('dmp').value.id) - setTimeout(x => { - this.init(); - }); - } - }); - - - // this.isDiscarded = false; - } - - addDataset(dmpId: string) { - this.router.navigate(['/datasets', 'new', dmpId]); - } - - reloadDateset(datasetId: string) { - let url = this.router.createUrlTree(['/datasets', 'edit', datasetId]).toString(); - this.location.go(url); - } - - backToDmp(id: string) { - this.router.navigate(['/plans', 'edit', id]); - } - - datasetInfoValid(): boolean { - return this.formGroup.get('label') && this.formGroup.get('label').valid && this.formGroup.get('profile') && this.formGroup.get('profile').valid; - } - - getLinks(currentLinks: Link[]) { - this.links = currentLinks; - } - - printForm() { - console.log(this.formGroup); - } - - printFormValue() { - console.log(this.formGroup.value); - } - - touchForm() { - this.formGroup.markAllAsTouched(); - this.showtocentriesErrors = true; - } - - // tocentries; - // this.tocentries = this.getTocEntries(this.formGroup.get('datasetProfileDefinition')); //TODO - - - // get tocentries(){ - // const form = this.formGroup.get('datasetProfileDefinition') - // if(!form) return null; - - // return this.getTocEntries(this.formGroup.get('datasetProfileDefinition')); - // } - - - // private _buildRecursively(form: FormGroup,whatAmI:ToCEntryType):ToCEntry{ - // if(!form) return null; - - // switch(whatAmI){ - // case ToCEntryType.Section: - // const sections = form.get('sections') as FormArray; - // const fieldsets = form.get('compositeFields') as FormArray; - - - // const tempResult:ToCEntry[] = []; - - // if(sections &§ions.length){ - // sections.controls.forEach(section=>{ - // tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); - // }); - - // }else if(fieldsets && fieldsets.length){ - // fieldsets.controls.forEach(fieldset=>{ - // tempResult.push(this._buildRecursively(fieldset as FormGroup, ToCEntryType.FieldSet)); - // }); - // } - // return { - // form: form, - // id: form.get('id').value, - // label: form.get('title').value, - // numbering: '', - // subEntries:tempResult, - // subEntriesType: sections &§ions.length? ToCEntryType.Section: ToCEntryType.FieldSet, - // type: ToCEntryType.Section, - // ordinal: form.get('ordinal').value - // } - // case ToCEntryType.FieldSet: - // return { - // form: form, - // label:form.get('title').value, - // id: form.get('id').value, - // numbering:'s', - // subEntries:[], - // subEntriesType: ToCEntryType.Field, - // type: ToCEntryType.FieldSet, - // ordinal: form.get('ordinal').value - // } - // } - // } - - // private _sortByOrdinal(tocentries: ToCEntry[]){ - - // if(!tocentries || !tocentries.length) return; - - // tocentries.sort(this._customCompare); - // tocentries.forEach(entry=>{ - // this._sortByOrdinal(entry.subEntries); - // }); - // } - - // private _customCompare(a,b){ - // return a.ordinal - b.ordinal; - // } - - // private _calculateNumbering(tocentries: ToCEntry[], depth:number[] = []){ - // if(!tocentries || !tocentries.length){ - // return; - // } - - // let prefixNumbering = depth.length? depth.join('.'): ''; - - // if(depth.length) prefixNumbering = prefixNumbering+"."; - // tocentries.forEach((entry,i)=>{ - // entry.numbering = prefixNumbering + (i+1); - // this._calculateNumbering(entry.subEntries, [...depth, i+1]) - // }); - // } - - - // getTocEntries(form): ToCEntry[] { - // if (form == null) { return []; } - // const result: ToCEntry[] = []; - - // //build parent pages - // (form.get('pages') as FormArray).controls.forEach((pageElement, i) => { - // result.push({ - // id: i+'id', - // label: pageElement.get('title').value, - // type: ToCEntryType.Page, - // form: pageElement, - // numbering: (i + 1).toString(), - // subEntriesType: ToCEntryType.Section, - // subEntries:[], - // ordinal: pageElement.get('ordinal').value - // } as ToCEntry) - // }); - - - // result.forEach((entry,i)=>{ - - // const sections = entry.form.get('sections') as FormArray; - - // sections.controls.forEach(section=>{ - // const tempResults = this._buildRecursively(section as FormGroup,ToCEntryType.Section); - // entry.subEntries.push(tempResults); - // }); - - // }); - - // this._sortByOrdinal(result); - // //calculate numbering - // this._calculateNumbering(result); - // return result; - - // } - - -} diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html new file mode 100644 index 000000000..33a12bf33 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html @@ -0,0 +1,150 @@ +
+
+
+ + +
+
+
+
+
+ +
{{'DMP-EDITOR.TITLE.ADD-DATASET' | translate}}
+
{{'DMP-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}
+
{{ formGroup.get('label').value }} ({{'DMP-EDITOR.CHANGES' | translate}})
+
+ +
{{'DMP-EDITOR.TITLE.PREVIEW-DATASET' | translate}}
+
+
+
{{'DATASET-LISTING.TOOLTIP.TO-DMP' | translate}}
+
: {{ formGroup.get('dmp').value.label }}
+ +
+
+
+
+ + + + + + +
+ + + +
+ +
+
+ + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ chevron_left + {{'DATASET-WIZARD.ACTIONS.BACK-TO' | translate}} +
+
{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}
+
+
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
+
+
+
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
+
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
+
+
+ +
+
+
+
+ + +
+
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
+ chevron_right +
+
+
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
+ chevron_right +
+ +
+
+ +
+
+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.scss b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.scss similarity index 96% rename from dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.scss rename to dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.scss index 246e7ad8b..2391b8b1a 100644 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-wizard.component.scss +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.scss @@ -3,7 +3,7 @@ margin-top: -80px; } -.dataset-wizard { +.description-editor { .toc-pane-container { &.is-sticky ~ .nav-spacer { height: 500px; // the container size } @@ -81,7 +81,7 @@ margin-right: 15px; } - .updateDatasetProfile { + .updateDescriptionProfile { margin-top: 15px; margin-bottom: 15px; margin-right: 15px; @@ -107,7 +107,7 @@ color: var(--primary-color-3); } - .new-dataset { + .new-description { height: 3.5em; } @@ -118,7 +118,7 @@ background-color: whitesmoke; } - .dataset-editor-header { + .description-editor-header { height: 113px; background: var(--unnamed-color-var(--primary-color)) 0% 0% no-repeat padding-box; background: var(--secondary-color) 0% 0% no-repeat padding-box; @@ -136,7 +136,7 @@ } } - .dataset-title { + .description-title { text-align: left; letter-spacing: 0px; color: #212121; @@ -156,7 +156,7 @@ white-space: nowrap; } - .dataset-subtitle { + .description-subtitle { text-align: left; letter-spacing: 0px; color: #212121; @@ -195,7 +195,7 @@ color: var(--primary-color); } - .dataset-discard-btn { + .description-discard-btn { border: 1px solid #212121; border-radius: 30px; opacity: 1; @@ -208,7 +208,7 @@ align-items: center; } - .dataset-save-btn, .dataset-export-btn { + .description-save-btn, .description-export-btn { background: #ffffff 0% 0% no-repeat padding-box; border-radius: 30px; opacity: 1; @@ -220,7 +220,7 @@ align-items: center; } - .dataset-to-dmp { + .description-to-dmp { display: flex; align-items: center; padding: 0; @@ -267,7 +267,7 @@ color: var(--primary-color); } - .dataset-stepper { + .description-stepper { position: fixed; // height: 100%; display: flex; @@ -339,7 +339,7 @@ opacity: 1; } - .stepper-list .active-dataset { + .stepper-list .active-description { color: #212121; font-weight: 700; opacity: 1; @@ -422,7 +422,7 @@ cursor: pointer; } - .add-dataset-btn { + .add-description-btn { background: var(--secondary-color) 0% 0% no-repeat padding-box; box-shadow: 0px 3px 6px #1e202029; font-weight: 500; @@ -439,7 +439,7 @@ cursor: pointer; } - .dataset-next { + .description-next { background: var(--secondary-color) 0% 0% no-repeat padding-box; color: #212121; box-shadow: 0px 3px 6px #1e202029; diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts new file mode 100644 index 000000000..371c917b2 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts @@ -0,0 +1,1687 @@ +import { Location } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DescriptionStatus } from '@app/core/common/enum/description-status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { SaveType } from '@app/core/common/enum/save-type'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; +import { LockModel } from '@app/core/model/lock/lock.model'; +import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { + ExternalSourcesConfigurationService +} from '@app/core/services/external-sources/external-sources-configuration.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { LockService } from '@app/core/services/lock/lock.service'; +import { MatomoService } from '@app/core/services/matomo/matomo-service'; +import { + SnackBarNotificationLevel, + UiNotificationService +} from '@app/core/services/notification/ui-notification-service'; +import { FileUtils } from '@app/core/services/utilities/file-utils.service'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; +import { FormService } from '@common/forms/form-service'; +import { + FormValidationErrorsDialogComponent +} from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import * as FileSaver from 'file-saver'; +import { Observable, interval, of as observableOf } from 'rxjs'; +import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators'; +import { DescriptionEditorService } from './description-editor.service'; +import { BaseEditor } from '@common/base/base-editor'; +import { DescriptionEditorModel } from './description-editor.model'; +import { Description, DescriptionPersist } from '@app/core/model/description/description'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; +import { FilterService } from '@common/modules/text-filter/filter-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { DescriptionService } from '@app/core/services/description/description.service'; +import { LoggingService } from '@app/core/services/logging/logging-service'; +import { DescriptionEditorResolver } from './description-editor.resolver'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DatePipe } from '@angular/common'; + +@Component({ + selector: 'app-description-editor-component', + templateUrl: 'description-editor.component.html', + styleUrls: ['./description-editor.component.scss'], + providers: [DescriptionEditorService] +}) +export class DescriptionEditorComponent extends BaseEditor implements OnInit { + + isNew = true; + isDeleted = false; + formGroup: UntypedFormGroup = null; + // showInactiveDetails = false; + // selectedSystemFields: Array = []; + // DescriptionSectionFieldCategory = DescriptionSectionFieldCategory; + // DescriptionSystemFieldType = DescriptionSystemFieldType; + // public DescriptionSystemFieldTypeEnum = this.enumUtils.getEnumValues(DescriptionSystemFieldType); + // DescriptionExtraFieldDataType = DescriptionExtraFieldDataType; + // public DescriptionExtraFieldDataTypeEnum = this.enumUtils.getEnumValues(DescriptionExtraFieldDataType); + + // blueprintsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { + // filterFn: this.filterDescriptionTempaltes.bind(this), + // initialItems: (excludedItems: any[]) => this.filterDescriptionTempaltes('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), + // displayFn: (item: DatasetProfileModel) => item.label, + // titleFn: (item: DatasetProfileModel) => item.label, + // subtitleFn: (item: DatasetProfileModel) => item.description, + // popupItemActionIcon: 'visibility' + // }; + + protected get canDelete(): boolean { + return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDescription); + } + + protected get canSave(): boolean { + return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescription); + } + + protected get canFinalize(): boolean { + return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescription); + } + + + 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 descriptionService: DescriptionService, + private logger: LoggingService, + private descriptionEditorService: DescriptionEditorService, + private fileUtils: FileUtils, + private matomoService: MatomoService, + private dmpService: DmpService + ) { + super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService); + } + + ngOnInit(): void { + this.matomoService.trackPageView('Admin: DMP Blueprints'); + super.ngOnInit(); + } + + getItem(itemId: Guid, successFunction: (item: Description) => void) { + this.descriptionService.getSingle(itemId, DescriptionEditorResolver.lookupFields()) + .pipe(map(data => data as Description), takeUntil(this._destroyed)) + .subscribe( + data => successFunction(data), + error => this.onCallbackError(error) + ); + } + + prepareForm(data: Description) { + try { + this.editorModel = data ? new DescriptionEditorModel().fromModel(data) : new DescriptionEditorModel(); + this.isDeleted = data ? data.isActive === IsActive.Inactive : false; + this.buildForm(); + } catch (error) { + this.logger.error('Could not parse Description 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.EditDescription)); + // this.selectedSystemFields = this.selectedSystemFieldDisabled(); + this.descriptionEditorService.setValidationErrorModel(this.editorModel.validationErrorModel); + if (this.editorModel.status == DescriptionStatus.Finalized) { + this.formGroup.disable(); + } + } + + refreshData(): void { + this.getItem(this.editorModel.id, (data: Description) => 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 DescriptionPersist; + + this.descriptionService.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.descriptionService.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); + } + + // // + // // + // // Sections + // // + // // + // addSection(): void { + // const section: DescriptionDefinitionSectionEditorModel = new DescriptionDefinitionSectionEditorModel(); + // section.id = Guid.create(); + // section.ordinal = (this.formGroup.get('definition').get('sections') as FormArray).controls.length + 1; + // section.hasTemplates = false; + // (this.formGroup.get('definition').get('sections') as FormArray).push(section.buildForm()); //TODO: dtziotzios validation path + // } + + // removeSection(sectionIndex: number): void { + // (this.formGroup.get('definition').get('sections') as FormArray).removeAt(sectionIndex); + // (this.formGroup.get('definition').get('sections') as FormArray).controls.forEach((section, index) => { + // section.get('ordinal').setValue(index + 1); + // }); + // } + + // dropSections(event: CdkDragDrop) { + // const sectionsFormArray = (this.formGroup.get('definition').get('sections') as FormArray); + + // moveItemInArray(sectionsFormArray.controls, event.previousIndex, event.currentIndex); + // sectionsFormArray.updateValueAndValidity(); + // sectionsFormArray.controls.forEach((section, index) => { + // section.get('ordinal').setValue(index + 1); + // }); + // } + + + // // + // // + // // Fields + // // + // // + // systemFieldDisabled(systemField: DescriptionSystemFieldType) { + // return (this.formGroup.get('definition').get('sections') as FormArray)?.controls.some(x => (x.get('fields') as FormArray).controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === systemField)); + // // for (let section in (this.formGroup.get('definition').get('sections')as FormArray)?.controls) { + // // if (i != sectionIndex) { + // // for (let f of this.fieldsArray(i).controls) { + // // if ((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == DescriptionSectionFieldCategory.SYSTEM) && f.get('type').value == systemField) { + // // return true; + // // } + // // } + // // } + // // i++; + // // } + // // return false; + // } + + // selectedSystemFieldDisabled(): Array { + // return (this.formGroup.get('definition').get('sections') as FormArray)?.controls.flatMap(x => (x.get('fields') as FormArray).controls.map(y => (y as UntypedFormGroup).get('systemFieldType')?.value as DescriptionSystemFieldType)); + // } + + // addSystemField(sectionIndex: number, systemFieldType: DescriptionSystemFieldType): void { + // const field: FieldInSectionEditorModel = new FieldInSectionEditorModel(); + // field.id = Guid.create(); + // field.ordinal = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length + 1; + // field.category = DescriptionSectionFieldCategory.SYSTEM; + // field.systemFieldType = systemFieldType; + // field.required = (systemFieldType == DescriptionSystemFieldType.TEXT || systemFieldType == DescriptionSystemFieldType.HTML_TEXT) ? true : false; + // ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).push(field.buildForm()); //TODO: dtziotzios validation path + // } + + // removeSystemField(sectionIndex: number, fieldIndex: number): void { + // const formArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray); + // formArray.removeAt(fieldIndex); + // formArray.controls.forEach((section, index) => { + // section.get('ordinal').setValue(index + 1); + // }); + // } + + // addExtraField(sectionIndex: number): void { + // const field: FieldInSectionEditorModel = new FieldInSectionEditorModel(); + // field.id = Guid.create(); + // field.ordinal = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length + 1; + // field.category = DescriptionSectionFieldCategory.EXTRA; + // ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).push(field.buildForm()); //TODO: dtziotzios validation path + // } + + // removeExtraField(sectionIndex: number, fieldIndex: number): void { + // const formArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray); + // formArray.removeAt(fieldIndex); + // formArray.controls.forEach((section, index) => { + // section.get('ordinal').setValue(index + 1); + // }); + // } + + + // dropFields(event: CdkDragDrop, sectionIndex: number) { + // const fieldsFormArray = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray); + + // moveItemInArray(fieldsFormArray.controls, event.previousIndex, event.currentIndex); + // fieldsFormArray.updateValueAndValidity(); + // fieldsFormArray.controls.forEach((section, index) => { + // section.get('ordinal').setValue(index + 1); + // }); + // } + + // // + // // + // // Autocomplete configuration + // // + // // + + // filterDescriptionTempaltes(value: string): Observable { + // const request = new DataTableRequest(null, null, { fields: ['+label'] }); + // const criteria = new DatasetProfileCriteria(); + // criteria.like = value; + // request.criteria = criteria; + // return this.dmpService.searchDescriptions(request); + // } + + // onRemoveDescritionTemplate(event, sectionIndex: number) { + // const descriptionTemplateFormArray = (this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray; + // const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id); + // if (foundIndex !== -1) { + // descriptionTemplateFormArray.removeAt(foundIndex); + // } + // } + + // onSelectDescritionTemplate(item, sectionIndex) { + // const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel(); + // descriptionTemplate.id = Guid.create(); + // descriptionTemplate.descriptionTemplateId = item.id; + // descriptionTemplate.label = item.label; + // ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).push(descriptionTemplate.buildForm()); //TODO: dtziotzios validation path + // } + + + public cancel(): void { + this.router.navigate(['/descriptions']); + } + + finalize() { + // if (this.checkValidity()) { + // this.formGroup.get('status').setValue(DescriptionStatus.Finalized); + // this.formSubmit(); + // } + } +} + +// export class DescriptionEditorComponent extends CheckDeactivateBaseComponent implements OnInit {//IBreadCrumbComponent +// canDeactivate(): boolean { +// return !this.isDirty(); +// } + +// // breadCrumbs: Observable; +// viewOnly = false; +// editMode = false; +// publicMode = false; +// hasChanges = false; +// isDiscarded = false; +// formGroupRawValue: any; +// saving = false; + +// DescriptionStatus = DescriptionStatus; +// dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + +// descriptionModel: DescriptionEditorModel; +// isNew = true; +// isCopy = false; +// formGroup: UntypedFormGroup = null; +// descriptionProfileDefinitionModel: DescriptionDescriptionFormEditorModel; + +// availableProfiles: DescriptionProfileModel[] = []; +// finalize: boolean = false; +// itemId: string; +// dmpId: string; +// dmpSectionIndex: number; +// availableDescriptionTemplates: DescriptionProfileModel[] = []; +// newDmpId: string; +// publicId: string; +// profileUpdateId: string; +// downloadDocumentId: string; +// isLinear = false; +// lock: LockModel; +// lockStatus: Boolean; + +// step: number = 0; +// stepOffset: number = 1; + +// saveAnd = SaveType; +// descriptionSavedLinks: any = null; + +// scrollTop: number; +// tocScrollTop: number; +// links: Link[] = []; +// //the table seraches for elements to scroll on page with id (TOCENTRY_ID_PREFIX+fieldsetId) +// TOCENTRY_ID_PREFIX = "TocEntRy"; +// showtocentriesErrors = false; +// @ViewChild('table0fContents') table0fContents: TableOfContents; +// hintErrors: boolean = false; +// descriptionIsOnceSaved = false; + +// fieldsetIdWithFocus: string; +// visRulesService: VisibilityRulesService; + +// constructor( +// private descriptionService: DescriptionService, +// private route: ActivatedRoute, +// public snackBar: MatSnackBar, +// public router: Router, +// public language: TranslateService, +// public externalSourcesService: ExternalSourcesService, +// public dmpService: DmpService, +// public dialog: MatDialog, +// public externalSourcesConfigurationService: ExternalSourcesConfigurationService, +// private uiNotificationService: UiNotificationService, +// private formService: FormService, +// private lockService: LockService, +// private location: Location, +// private authService: AuthService, +// private configurationService: ConfigurationService, +// private httpClient: HttpClient, +// private matomoService: MatomoService, +// private fileUtils: FileUtils +// ) { +// super(); +// } + +// ngOnInit() { +// this.matomoService.trackPageView('Description Editor'); +// this.route +// .data +// .pipe(takeUntil(this._destroyed)) +// .subscribe(v => { +// this.viewOnly = v['public']; +// }); + +// const dmpRequestItem: RequestItem = new RequestItem(); +// dmpRequestItem.criteria = new DmpCriteria(); + +// this.dmpAutoCompleteConfiguration = { +// filterFn: this.searchDmp.bind(this), +// initialItems: (extraData) => this.searchDmp(''), +// displayFn: (item) => this.getDescriptionDisplay(item), +// titleFn: (item) => item['label'], +// subtitleFn: (item) => this.language.instant('DATASET-WIZARD.FIRST-STEP.SUB-TITLE') + new Date(item['creationTime']).toISOString() +// // iconFn: (item) => this.publicMode ? '' : (item['status'] ? 'lock' : 'lock_open'), +// // linkFn: (item) => this.publicMode ? '/explore-plans/overview/' + item['id'] : '/plans/overview/' + item['id'] +// }; + +// const params = this.route.snapshot.params; +// const queryParams = this.route.snapshot.queryParams; +// const data: any = this.route.snapshot.data; +// this.itemId = params['id']; +// this.dmpId = params['dmpId']; +// this.dmpSectionIndex = parseInt(params['dmpSectionIndex']); +// this.newDmpId = queryParams['newDmpId']; +// this.publicId = params['publicId']; +// this.profileUpdateId = params['updateId']; +// this.finalize = data.finalize; +// this.itemId ? this.downloadDocumentId = this.itemId : this.downloadDocumentId = this.publicId + +// this.init(); +// // this.route.params +// // .pipe(takeUntil(this._destroyed)) +// // .subscribe((params: Params) => { +// // const itemId = params['id']; +// // if (itemId != null) { setTimeout(() => this.stepper.selectedIndex = 2); } +// // }); +// } + +// init() { +// if (this.itemId != null && this.newDmpId == null) { +// this.isNew = false; +// this.descriptionService.getSingle(this.itemId) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(data => { +// this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { +// this.lockStatus = lockStatus; +// this.descriptionModel = new DescriptionEditorModel().fromModel(data); +// this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex; +// this.needsUpdate(); +// // this.breadCrumbs = observableOf([ +// // { +// // parentComponentName: null, +// // label: this.descriptionModel.label, +// // url: '/descriptions/edit/' + this.descriptionModel.id, +// // notFoundResolver: [ +// // { +// // parentComponentName: null, +// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(), +// // url: '/descriptions' +// // }, +// // ] +// // }]); +// this.formGroup = this.descriptionModel.buildForm(); +// let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.descriptionModel.dmpSectionIndex)); +// for (var profile of profiles) { +// this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) +// } +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) { +// this.formGroup.disable(); +// this.viewOnly = true; +// } +// if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { +// const lockedBy: UserInfoListingModel = { +// email: this.authService.getUserProfileEmail(), +// id: this.authService.userId()?.toString(), +// name: this.authService.getPrincipalName(), +// role: 0 //TODO +// //role: this.authService.getRoles()?.at(0) +// } +// this.lock = new LockModel(data.id, lockedBy); + +// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { +// this.lock.id = Guid.parse(result); +// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); +// }); +// } +// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. +// this.loadDescriptionProfiles(); +// this.registerFormListeners(); + +// if (lockStatus) { +// this.dialog.open(PopupNotificationDialogComponent, { +// data: { +// title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'), +// message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE') +// }, maxWidth: '30em' +// }); +// } +// if (this.finalize && !this.lockStatus && !this.viewOnly) { +// setTimeout(() => { +// this.saveFinalize(); +// }, 0); +// } +// // this.availableProfiles = this.descriptionModel.dmp.profiles; +// }); +// }, +// error => { +// switch (error.status) { +// case 403: +// this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-ALLOWED'), SnackBarNotificationLevel.Error); +// break; +// case 404: +// this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error); +// break; +// default: +// this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.ERRORS.HTTP-REQUEST-ERROR'), SnackBarNotificationLevel.Error); +// } +// this.router.navigate(['/descriptions/']); +// return observableOf(null); +// }); +// } else if (this.dmpId != null) { +// this.isNew = true; +// this.dmpService.getSingle(this.dmpId).pipe(map(data => data as DmpModel)) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(data => { +// this.descriptionModel = new DescriptionEditorModel(); +// setTimeout(() => { +// this.descriptionModel.dmp = data; +// this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex; +// this.formGroup = this.descriptionModel.buildForm(); +// let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.dmpSectionIndex)); +// for (var profile of profiles) { +// this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) +// } +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// this.formGroup.get('dmp').disable(); +// const dialogRef = this.dialog.open(PrefillDescriptionComponent, { +// width: '590px', +// minHeight: '200px', +// restoreFocus: false, +// data: { +// availableProfiles: this.availableDescriptionTemplates, +// descriptionFormGroup: this.formGroup +// }, +// panelClass: 'custom-modalbox' +// }); +// dialogRef.afterClosed().subscribe(result => { +// if (result) { +// this.descriptionModel = this.descriptionModel.fromModel(result); +// this.descriptionModel.dmp = data; +// this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex; +// this.formGroup = this.descriptionModel.buildForm(); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); +// this.formGroup.get('dmp').disable(); +// this.loadDescriptionProfiles(); +// this.registerFormListeners(); +// } +// }) +// this.loadDescriptionProfiles(); +// this.registerFormListeners(); +// // this.availableProfiles = data.profiles; + +// // this.breadCrumbs = observableOf([ +// // { +// // parentComponentName: null, +// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), +// // url: '/descriptions', +// // notFoundResolver: [ +// // // { +// // // parentComponentName: null, +// // // label: this.descriptionModel.dmp.grant.label, +// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id +// // // }, +// // { +// // parentComponentName: null, +// // label: this.descriptionModel.dmp.label, +// // url: '/plans/edit/' + this.descriptionModel.dmp.id, +// // }] +// // }]); +// }); +// }); +// } else if (this.newDmpId != null) { +// this.isNew = false; +// this.isCopy = true; +// this.descriptionService.getSingle(this.itemId) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(data => { +// this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { +// this.lockStatus = lockStatus; +// this.descriptionModel = new DescriptionEditorModel().fromModel(data); +// this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex; +// this.descriptionModel.status = 0; +// this.formGroup = this.descriptionModel.buildForm(); +// this.formGroup.get('id').setValue(null); +// this.dmpService.getSingleNoDescriptions(this.newDmpId).pipe(map(data => data as DmpModel)) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(data => { +// setTimeout(() => { +// this.descriptionModel.dmp = data; +// this.formGroup.get('dmp').setValue(this.descriptionModel.dmp); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + +// this.loadDescriptionProfiles(); +// // this.breadCrumbs = observableOf([ +// // { +// // parentComponentName: null, +// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), +// // url: '/descriptions', +// // notFoundResolver: [ +// // // { +// // // parentComponentName: null, +// // // label: this.descriptionModel.dmp.grant.label, +// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id +// // // }, +// // { +// // parentComponentName: null, +// // label: this.descriptionModel.dmp.label, +// // url: '/plans/edit/' + this.descriptionModel.dmp.id, +// // } +// // ] +// // }]); +// }); +// }); +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) { +// this.formGroup.disable(); +// this.viewOnly = true; +// } +// if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { +// const lockedBy: UserInfoListingModel = { +// email: this.authService.getUserProfileEmail(), +// id: this.authService.userId()?.toString(), +// name: this.authService.getPrincipalName(), +// role: 0 //TODO +// //role: this.authService.getRoles()?.at(0) +// } +// this.lock = new LockModel(data.id, lockedBy); + +// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { +// this.lock.id = Guid.parse(result); +// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); +// }); +// } +// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. +// this.loadDescriptionProfiles(); +// // this.availableProfiles = data.dmp.profiles; +// }) +// }); +// } else if (this.publicId != null) { // For Finalized -> Public Descriptions +// this.isNew = false; +// this.descriptionService.getSinglePublic(this.publicId) +// .pipe(takeUntil(this._destroyed)).pipe( +// catchError((error: any) => { +// this.uiNotificationService.snackBarNotification(error.error.message, SnackBarNotificationLevel.Error); +// this.router.navigate(['/descriptions/publicEdit/' + this.publicId]); +// return observableOf(null); +// })) +// .subscribe(data => { +// if (data) { +// this.descriptionModel = new DescriptionEditorModel().fromModel(data); +// this.formGroup = this.descriptionModel.buildForm(); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); +// this.formGroup.disable(); +// this.viewOnly = true; +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// this.formGroup.get('dmp').setValue(this.descriptionModel.dmp); +// const breadcrumbs = []; +// breadcrumbs.push({ +// parentComponentName: null, +// label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), +// url: '/explore-descriptions' +// }); +// breadcrumbs.push({ +// parentComponentName: null, +// label: this.descriptionModel.label, +// url: '/descriptions/publicEdit/' + this.descriptionModel.id +// }); +// // this.breadCrumbs = observableOf(breadcrumbs); +// } +// }); +// this.publicMode = true; +// } else if (this.profileUpdateId != null) { +// this.descriptionService.updateDescriptionProfile(this.profileUpdateId) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(data => { +// this.descriptionModel = new DescriptionEditorModel().fromModel(data); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + +// this.needsUpdate(); +// // this.breadCrumbs = observableOf([ +// // { +// // parentComponentName: null, +// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), +// // url: '/descriptions', +// // notFoundResolver: [ +// // // { +// // // parentComponentName: null, +// // // label: this.descriptionModel.dmp.grant.label, +// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id +// // // }, +// // { +// // parentComponentName: null, +// // label: this.descriptionModel.dmp.label, +// // url: '/plans/edit/' + this.descriptionModel.dmp.id, +// // }, +// // ] +// // }]); +// this.formGroup = this.descriptionModel.buildForm(); +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// if (this.descriptionModel.status === DescriptionStatus.Finalized) { +// this.formGroup.disable(); +// this.viewOnly = true; +// } +// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. +// this.loadDescriptionProfiles(); +// }); + +// } else { +// this.descriptionModel = new DescriptionEditorModel(); +// this.formGroup = this.descriptionModel.buildForm(); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// if (this.descriptionModel.status === DescriptionStatus.Finalized) { +// this.formGroup.disable(); +// this.viewOnly = true; +// } +// //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. +// this.registerFormListeners(); +// this.dmpValueChanged(null); +// // this.breadCrumbs = observableOf([ +// // { +// // parentComponentName: null, +// // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), +// // url: '/descriptions/new/' +// // }]); +// } +// } + +// // private _listenersSubscription:Subscription = new Subscription(); +// registerFormListeners() { +// // const dmpSubscription = +// this.formGroup.get('dmp').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.dmpValueChanged(x); +// }); +// // const profileSubscription = +// this.formGroup.get('profile').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// if (x) { +// this.showtocentriesErrors = false; +// this.descriptionProfileValueChanged(x.id); +// this.formChanged(); +// } +// }); +// // const labelSubscription = +// this.formGroup.get('label').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// // const descriptionSubscription = +// this.formGroup.get('description').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// // const uriSubscription = +// this.formGroup.get('uri').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// // const tagsSubscription = +// this.formGroup.get('tags').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// if (this.formGroup.get('descriptionProfileDefinition')) { +// // const descriptionProfileDefinitionSubscription = +// this.formGroup.get('descriptionProfileDefinition').valueChanges +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// // this._listenersSubscription.add(descriptionProfileDefinitionSubscription); +// } + +// // this._listenersSubscription.add(dmpSubscription); +// // this._listenersSubscription.add(profileSubscription); +// // this._listenersSubscription.add(labelSubscription); +// // this._listenersSubscription.add(descriptionSubscription); +// // this._listenersSubscription.add(uriSubscription); +// // this._listenersSubscription.add(tagsSubscription); +// } + +// // private _unregisterFormListeners(){ +// // this._listenersSubscription.unsubscribe(); +// // this._listenersSubscription = new Subscription(); +// // } + +// dmpValueChanged(dmp: DmpListingModel) { +// if (dmp) { +// this.formGroup.get('profile').enable(); +// this.loadDescriptionProfiles(); +// } else { +// this.availableProfiles = []; +// this.formGroup.get('profile').reset(); +// this.formGroup.get('profile').disable(); +// this.formGroup.removeControl('descriptionProfileDefinition'); +// } +// } + +// descriptionProfileValueChanged(profiledId: string) { +// if (profiledId && profiledId.length > 0) { +// this.formGroup.removeControl('descriptionProfileDefinition'); +// this.getDefinition(profiledId); +// } +// } + +// searchDmp(query: string): Observable { +// const fields: Array = new Array(); +// fields.push('-created'); +// const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); +// dmpDataTableRequest.criteria = new DmpCriteria(); +// dmpDataTableRequest.criteria.like = query; +// dmpDataTableRequest.criteria.status = DmpStatus.Draft; +// return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(map(x => x.data)); +// } + +// loadDescriptionProfiles() { +// const descriptionProfileRequestItem: RequestItem = new RequestItem(); +// descriptionProfileRequestItem.criteria = new DescriptionProfileCriteria(); +// descriptionProfileRequestItem.criteria.id = this.formGroup.get('dmp').value.id; +// if (descriptionProfileRequestItem.criteria.id) { +// this.descriptionService.getAvailableProfiles(descriptionProfileRequestItem) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(items => { +// this.availableProfiles = items; +// }); +// } +// } + +// public formChanged() { +// if (!this.isDiscarded) { +// this.hasChanges = true; +// } +// } + +// public cancel(): void { +// if (!isNullOrUndefined(this.lock)) { +// this.lockService.unlockTarget(this.descriptionModel.id).pipe(takeUntil(this._destroyed)).subscribe( +// complete => { +// this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/descriptions']); +// }, +// error => { +// this.formGroup.get('status').setValue(DmpStatus.Draft); +// this.onCallbackError(error); +// } +// ) +// } else { +// this.publicMode ? this.router.navigate(['/explore']) : this.router.navigate(['/descriptions']); +// } + +// } + +// getDescriptionDisplay(item: any): string { +// if (!this.publicMode) { +// return (item['status'] ? this.language.instant('TYPES.DATASET-STATUS.FINALISED').toUpperCase() : this.language.instant('TYPES.DATASET-STATUS.DRAFT').toUpperCase()) + ': ' + item['label']; +// } else { +// return item['label']; +// } +// } + +// getDefinition(profileId: string) { +// // if (this.formGroup.invalid) { setTimeout(() => this.stepper.selectedIndex = 0); return; } +// this.descriptionService.getDefinition(profileId) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(item => { +// this.descriptionModel.descriptionProfileDefinition = new DescriptionDescriptionFormEditorModel().fromModel(item); +// this.descriptionProfileDefinitionModel = this.descriptionModel.descriptionProfileDefinition; +// this.formGroup.addControl('descriptionProfileDefinition', this.descriptionProfileDefinitionModel.buildForm()); + +// // const descriptionProfileDefinitionForm = this.descriptionProfileDefinitionModel.buildForm(); + +// // let profId = null; +// // try{ +// // profId = this.formGroup.get('profile').value.id; +// // }catch{ + +// // } +// // if(this.formGroupRawValue && this.formGroupRawValue.descriptionProfileDefinition && (this.formGroupRawValue.profile.id === profId)){ +// // // this.formGroup.get('descriptionProfileDefinition').patchValue( this.formGroupRawValue.descriptionProfileDefinition); +// // descriptionProfileDefinitionForm.patchValue(this.formGroupRawValue.descriptionProfileDefinition); +// // } + +// // this.formGroup.addControl('descriptionProfileDefinition', descriptionProfileDefinitionForm); +// this.formGroup.get('descriptionProfileDefinition').valueChanges +// .pipe(debounceTime(600)) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.formChanged(); +// }); +// }); +// } + +// // formSubmit(): void { +// // if (!this.isFormValid()) { return; } +// // this.onSubmit(); +// // } + +// public isFormValid() { +// return this.formGroup.valid; +// } + +// public isSemiFormValid(formGroup: UntypedFormGroup): boolean { +// var isValid: boolean = true; +// Object.keys(formGroup.controls).forEach(controlName => { +// if (controlName != 'descriptionProfileDefinition' && !formGroup.get(controlName).disabled && !(formGroup.get(controlName).valid)) { +// isValid = false; +// } +// }); +// return isValid; +// } + +// // onSubmit(): void { +// // this.descriptionService.createDescription(this.formGroup.value) +// // .pipe(takeUntil(this._destroyed)) +// // .subscribe( +// // complete => { +// // this.descriptionService.getSingle(complete.id) +// // .pipe(takeUntil(this._destroyed)) +// // .subscribe( +// // result => { +// // this.descriptionModel = new DescriptionEditorModel().fromModel(result); +// // } +// // ); +// // this.onCallbackSuccess(); +// // }, +// // error => this.onCallbackError(error) +// // ); +// // } + + +// submit(saveType?: SaveType, onSuccess: Function = null, onError: Function = null) { +// this.scrollTop = document.getElementById('description-editor-form').scrollTop; +// this.tocScrollTop = document.getElementById('stepper-options').scrollTop; +// this.descriptionService.createDescription(this.formGroup.getRawValue()) +// .pipe(takeUntil(this._destroyed)) +// .subscribe( +// data => { +// this.hasChanges = false; +// this.descriptionIsOnceSaved = true; +// this.onCallbackSuccess(data, saveType); +// if (onSuccess) { +// onSuccess(); +// } +// }, +// error => { +// if (onError) { +// onError(); +// } +// this.onCallbackError(error) +// }); +// } + + +// private _getErrorMessage(formControl: AbstractControl, name: string): string[] { +// const errors: string[] = []; +// Object.keys(formControl.errors).forEach(key => { +// if (key === 'required') { +// errors.push(this.language.instant(name + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED'))); +// } +// // if (key === 'required') { errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + this.getPlaceHolder(formControl) + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')); } +// else if (key === 'email') { +// errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.EMAIL')); +// } else if (key === 'min') { +// errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MIN-VALUE', { 'min': formControl.getError('min').min })); +// } else if (key === 'max') { +// errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.MAX-VALUE', { 'max': formControl.getError('max').max })); +// } else { +// errors.push(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.THIS-FIELD') + ' "' + name + '" ' + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR') + ', ' + formControl.errors[key].message); +// } +// }); +// return errors; +// } + +// private _getPlaceHolder(formControl: any): string { +// if (formControl.nativeElement.localName === 'input' || formControl.nativeElement.localName === 'textarea' +// || formControl.nativeElement.localName === 'richTextarea') { +// return formControl.nativeElement.getAttribute('placeholder'); +// } else if (formControl.nativeElement.localName === 'mat-select') { +// return formControl.nativeElement.getAttribute('placeholder'); +// } else if (formControl.nativeElement.localName === 'app-single-auto-complete') { +// return (Array.from(formControl.nativeElement.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); +// } else if (formControl.nativeElement.localName === 'app-multiple-auto-complete') { +// return (Array.from(formControl.nativeElement.firstChild.firstChild.firstChild.children).filter((x: any) => x.localName === 'input')[0] as any).getAttribute('placeholder'); +// } +// } + + +// private _buildSemiFormErrorMessages(): string[] {//not including descriptionProfileDefinition +// const errmess: string[] = []; +// Object.keys(this.formGroup.controls).forEach(controlName => { +// if (controlName != 'descriptionProfileDefinition' && this.formGroup.get(controlName).invalid) { +// errmess.push(...this._buildErrorMessagesForAbstractControl(this.formGroup.get(controlName), controlName)); +// } +// }) + +// return errmess; +// } + +// // takes as an input an abstract control and gets its error messages[] +// private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string): string[] { +// const errmess: string[] = []; + +// if (aControl.invalid) { + +// if (aControl.errors) { +// //check if has placeholder +// if ((aControl).nativeElement !== undefined && (aControl).nativeElement !== null) { +// const placeholder = this._getPlaceHolder(aControl); +// if (placeholder) { +// controlName = placeholder; +// } +// } +// const errorMessage = this._getErrorMessage(aControl, controlName); + +// errmess.push(...errorMessage); +// } + +// /*in case the aControl is FormControl then the it should have provided its error messages above. +// No need to check case of FormControl below*/ + +// if (aControl instanceof UntypedFormGroup) { + +// const fg = aControl as UntypedFormGroup; +// //check children +// Object.keys(fg.controls).forEach(controlName => { +// errmess.push(...this._buildErrorMessagesForAbstractControl(fg.get(controlName), controlName)); +// }); +// } else if (aControl instanceof UntypedFormArray) { + +// const fa = aControl as UntypedFormArray; + +// fa.controls.forEach((control, index) => { +// errmess.push(...this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index + 1}`)); +// }); + +// } +// } + +// return errmess; +// } + +// save(saveType?: SaveType) { +// this.saving = true; +// Object.keys(this.formGroup.controls).forEach(controlName => { +// if (controlName == 'descriptionProfileDefinition') { +// return; +// } +// this.formService.touchAllFormFields(this.formGroup.get(controlName)); +// }) + + +// // this.formService.touchAllFormFields(this.formGroup); +// if (!this.isSemiFormValid(this.formGroup)) { +// //build messages +// const errorMessages = this._buildSemiFormErrorMessages(); +// this.showValidationErrorsDialog(undefined, errorMessages); +// this.hintErrors = true; +// this.saving = false; +// return; +// } +// this.submit(saveType); +// } + +// private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) { +// if (errmess) { +// const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { +// disableClose: true, +// autoFocus: false, +// restoreFocus: false, +// data: { +// errorMessages: errmess, +// projectOnly: projectOnly +// }, +// }); +// } else { + +// const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { +// disableClose: true, +// autoFocus: false, +// restoreFocus: false, +// data: { +// formGroup: this.formGroup, +// projectOnly: projectOnly +// }, +// }); +// } + +// } + +// hasReversableStatus(): boolean { +// if (this.formGroup.get('dmp').value) { +// return (this.formGroup.get('dmp').value.status == DmpStatus.Draft && this.formGroup.get('status').value == DescriptionStatus.Finalized); +// } else { +// return false; +// } +// } + +// hasNotReversableStatus(): boolean { +// if (this.formGroup.get('dmp').value && !this.publicMode) { +// return (this.formGroup.get('dmp').value.status == DmpStatus.Finalized && this.formGroup.get('status').value == DescriptionStatus.Finalized); +// } else { +// return false; +// } +// } + +// reverse() { + +// this.dialog.open(ConfirmationDialogComponent, { +// data: { +// message: this.language.instant('DATASET-WIZARD.ACTIONS.UNDO-FINALIZATION-QUESTION'), +// confirmButton: this.language.instant('DATASET-WIZARD.ACTIONS.CONFIRM'), +// cancelButton: this.language.instant('DATASET-WIZARD.ACTIONS.REJECT'), +// }, +// maxWidth: '30em' +// }) +// .afterClosed() +// .pipe( +// filter(x => x), +// takeUntil(this._destroyed) +// ).subscribe(result => { +// if (result) { +// // if (!this.isFormValid()) { return; } +// this.formGroup.get('status').setValue(DescriptionStatus.Draft); +// this.submit(SaveType.finalize, () => { +// this.viewOnly = false; +// this.descriptionModel.status = DescriptionStatus.Draft; +// setTimeout(x => { +// this.formGroup = null; +// }); +// setTimeout(x => { +// this.formGroup = this.descriptionModel.buildForm(); +// this.registerFormListeners(); +// }); +// }, () => { +// this.formGroup.get('status').setValue(DescriptionStatus.Finalized); +// this.viewOnly = true; +// }); +// } else { +// this.saving = false; +// } +// }); + + +// } + +// saveFinalize() { +// // this.formService.touchAllFormFields(this.formGroup); +// this.saving = true; +// if (!this.isSemiFormValid(this.formGroup) || (this.table0fContents && this.table0fContents.hasVisibleInvalidFields())) { +// // this.showValidationErrorsDialog(); +// this.dialog.open(FormValidationErrorsDialogComponent, { +// data: { +// errorMessages: [this.language.instant('DATASET-WIZARD.MESSAGES.MISSING-FIELDS')] +// } +// }) + + +// this.touchForm(); +// this.hintErrors = true; +// this.saving = false; +// return; +// } +// const dialogRef = this.dialog.open(ConfirmationDialogComponent, { +// restoreFocus: false, +// data: { +// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'), +// confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'), +// cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'), +// isDeleteConfirmation: false +// } +// }); +// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { +// if (result) { +// // if (!this.isFormValid()) { return; } +// this.formGroup.get('status').setValue(DescriptionStatus.Finalized); +// this.submit(SaveType.finalize, null, () => { +// this.formGroup.get('status').setValue(DescriptionStatus.Draft); +// }); +// } else { +// this.saving = false; +// } +// }); +// } + +// onCallbackSuccess(data?: DescriptionModel, saveType?: SaveType): void { +// this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); +// if (data) { +// if (saveType === this.saveAnd.addNew) { +// this.router.navigate(['/reload']).then(() => { +// this.router.navigate(['/descriptions', 'new', this.formGroup.get('dmp').value.id, this.dmpSectionIndex]); +// }) +// } else if (saveType === this.saveAnd.close) { +// this.router.navigate(['/reload']).then(() => { +// this.router.navigate(['/plans', 'edit', this.formGroup.get('dmp').value.id]); +// }); +// } else if (saveType === SaveType.finalize) { +// this.router.navigate(['/reload']).then(() => { +// this.router.navigate(['/descriptions', 'edit', data.id]); +// }); +// } else { +// this.descriptionModel = new DescriptionEditorModel().fromModel(data); +// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; +// // setTimeout(() => { this.formGroup = null; }); +// setTimeout(() => { +// this.formGroup.get('id').patchValue(data.id); +// this.formGroup.get('modified').patchValue(data.modified); +// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); +// this.hasChanges = false; + +// // this.formGroup = this.descriptionModel.buildForm(); +// // if (this.formGroup.get('descriptionProfileDefinition')) { +// // this.formGroup.removeControl('descriptionProfileDefinition'); +// // this.getDefinition(data.profile.id); +// // this.maxStep = 1; +// // } else { +// // this.getDefinition(data.profile.id); +// // this.maxStep = 1; +// // } +// }); + +// setTimeout(() => { +// document.getElementById('description-editor-form').scrollTop = this.scrollTop; +// document.getElementById('stepper-options').scrollTop = this.tocScrollTop; +// }, 500); +// this.saving = false; +// if (this.isNew) { +// this.reloadDateset(this.descriptionModel.id); +// } +// // this.router.navigate(['/reload']).then(() => { this.router.navigate(['/descriptions', 'edit', data.id]); }); +// } +// } else { +// this.router.navigate(['/descriptions']); +// } +// } + +// onCallbackError(error: any) { +// const errmes = error && error.message ? error.message as string : null; +// let feedbackMessage = this.language.instant('DATASET-EDITOR.ERRORS.ERROR-OCCURED'); +// if (errmes) { +// feedbackMessage += errmes; +// } +// this.uiNotificationService.snackBarNotification(feedbackMessage, SnackBarNotificationLevel.Warning); +// this.setErrorModel(error.error); +// this.saving = false; +// } + +// public setErrorModel(validationErrorModel: ValidationErrorModel) { +// Object.keys(validationErrorModel).forEach(item => { +// (this.descriptionModel.validationErrorModel)[item] = (validationErrorModel)[item]; +// }); +// } + +// downloadPDF(id: string): void { +// this.descriptionService.downloadPDF(id) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(response => { +// const blob = new Blob([response.body], { type: 'application/pdf' }); +// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + +// FileSaver.saveAs(blob, filename); +// this.matomoService.trackDownload('descriptions', "pdf", id); +// }); +// } + +// downloadDOCX(id: string): void { +// this.descriptionService.downloadDOCX(id) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(response => { +// const blob = new Blob([response.body], { type: 'application/msword' }); +// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + +// FileSaver.saveAs(blob, filename); +// this.matomoService.trackDownload('descriptions', "docx", id); +// }); + +// } + +// downloadXML(id: string): void { +// this.descriptionService.downloadXML(id) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(response => { +// const blob = new Blob([response.body], { type: 'application/xml' }); +// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + +// FileSaver.saveAs(blob, filename); +// this.matomoService.trackDownload('descriptions', "xml", id); +// }); +// } + +// // advancedClicked() { +// // const dialogRef = this.dialog.open(ExportMethodDialogComponent, { +// // maxWidth: '500px', +// // data: { +// // message: "Download as:", +// // XMLButton: "XML", +// // documentButton: "Document", +// // pdfButton: "PDF" +// // } +// // }); +// // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { +// // if (result == "pdf") { +// // this.downloadPDF(); +// // } else if (result == "xml") { +// // this.downloadXML(); +// // } else if (result == "doc") { +// // this.downloadDOCX(); +// // } +// // }); +// // } + +// public redirectToGrant() { +// this.router.navigate(['grants/edit/' + this.descriptionModel.dmp.grant.id]); +// } + +// public redirectToDmp() { +// this.router.navigate(['plans/edit/' + this.descriptionModel.dmp.id]); +// } + +// public enableForm() { +// if (this.formGroup.get('status').value !== DescriptionStatus.Finalized) { +// this.editMode = true; +// this.viewOnly = false; +// this.formGroup.enable(); +// } else { +// this.descriptionService.unlock(this.formGroup.get('id').value) +// .pipe(takeUntil(this._destroyed)) +// .subscribe(x => { +// this.editMode = true; +// this.viewOnly = false; +// this.descriptionModel.status = DescriptionStatus.Draft; +// this.formGroup.get('status').patchValue(DescriptionStatus.Draft); +// this.formGroup.enable(); +// }); +// } +// } + +// public disableForm() { +// this.editMode = false; +// //this.viewOnly = true; +// this.formGroup.disable(); +// } + +// openConfirm(dmpLabel, id): void { +// const dialogRef = this.dialog.open(ConfirmationDialogComponent, { +// maxWidth: '300px', +// restoreFocus: false, +// data: { +// message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), +// confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), +// cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), +// isDeleteConfirmation: true +// } +// }); +// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { +// if (result) { +// this.descriptionService.delete(id) +// .pipe(takeUntil(this._destroyed)) +// .subscribe( +// complete => this.onCallbackSuccess(), +// error => this.onCallbackError(error) +// ); +// } +// }); +// } + +// openDmpSearchDialogue() { +// const formControl = new UntypedFormControl(); +// const dialogRef = this.dialog.open(DescriptionCopyDialogueComponent, { +// width: '500px', +// restoreFocus: false, +// data: { +// formControl: formControl, +// descriptionId: this.formGroup.value.id, +// descriptionProfileId: this.formGroup.value.profile, +// descriptionProfileExist: false, +// confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'), +// cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL') +// } +// }); + +// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)) +// .subscribe(result => { +// if (result && result.descriptionProfileExist) { +// const newDmpId = result.formControl.value.id +// this.router.navigate(['/descriptions/copy/' + result.descriptionId], { queryParams: { newDmpId: newDmpId } }); +// } +// }); +// } + +// needsUpdate() { +// if (this.descriptionModel.isProfileLatestVersion || (this.descriptionModel.status === DescriptionStatus.Finalized) +// || (this.descriptionModel.isProfileLatestVersion == undefined && this.descriptionModel.status == undefined)) { +// return false; +// } else { +// return true; +// } +// } + +// linkToScroll: LinkToScroll; + +// onStepFound(linkToScroll: LinkToScroll) { +// this.linkToScroll = linkToScroll; +// } + +// private pumpLock() { +// this.lock.touchedAt = new Date(); +// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { +// if (!isNullOrUndefined(result)) { +// this.lock.id = Guid.parse(result); +// } else { +// this.location.back(); +// } +// }); +// } + +// getEntryVisibleFieldSets(entry: ToCEntry): ToCEntry[] { +// let fieldSets = []; +// if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)) { +// fieldSets.push(entry); +// } else if (entry.type !== ToCEntryType.FieldSet) { +// entry.subEntries.forEach(subEntry => { +// fieldSets = fieldSets.concat(this.getEntryVisibleFieldSets(subEntry)); +// }); +// } +// return fieldSets; +// } + +// get visibleFieldSets(): ToCEntry[] { +// let fieldSets = []; +// let arrays = this.table0fContents ? this.table0fContents.tocentries. +// filter(entry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)).map(entry => { +// return this.getEntryVisibleFieldSets(entry); +// }) +// : []; +// arrays.forEach(array => { +// fieldSets = fieldSets.concat(array); +// }); +// return fieldSets; +// } + +// getFirstFieldSet(entry: ToCEntry): ToCEntry { +// if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id)) { +// return entry; +// } else { +// let subEntries = entry.subEntries.filter(subEntry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === subEntry.id)); +// if (subEntries.length > 0) { +// return this.getFirstFieldSet(subEntries[0]); +// } else { +// return null; +// } +// } +// } + +// public changeStep(selected: ToCEntry = null, execute: boolean = true) { +// if (execute) { +// if (selected) { +// let fieldSet = this.getFirstFieldSet(selected); +// let index = this.visibleFieldSets.findIndex(entry => entry.id === fieldSet.id); +// this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5); +// } else { +// this.step = 0; +// this.resetScroll(); +// } +// } +// } + +// get maxStep() { +// return this.visibleFieldSets.length; +// } + +// public nextStep() { +// if (this.step < this.maxStep) {//view is changing +// this.step = Math.floor(this.step + 1); +// let entry = this.visibleFieldSets[this.step - 1]; +// this.table0fContents.onToCentrySelected(entry, false); +// this.scroll(entry); +// } +// } + +// public previousStep() { +// if (this.step > 0) { +// this.step = Math.ceil(this.step - 1); +// if (this.step >= 1) { +// let entry = this.visibleFieldSets[this.step - 1]; +// this.table0fContents.onToCentrySelected(entry, false); +// this.scroll(entry); +// } else { +// this.table0fContents.onToCentrySelected(null, false); +// this.resetScroll(); +// } +// } +// } + +// private resetScroll() { +// document.getElementById('description-editor-form').scrollTop = 0; +// } + +// private scroll(entry: ToCEntry) { +// document.getElementById(entry.id).scrollIntoView(); +// } + +// isDirty() { +// return this.formGroup.dirty && this.hasChanges; // do we need this.formGroup.dirty +// } + +// discardChanges() { +// // this.isDiscarded = true; +// // this.hasChanges = false; +// // this.hintErrors = false; +// let messageText = ""; +// let confirmButtonText = ""; +// let cancelButtonText = ""; +// let isDeleteConfirmation = false; + +// if (this.isNew && !this.descriptionIsOnceSaved) { + +// messageText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-MESSAGE'); +// confirmButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-CONFIRM'); +// cancelButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-NEW-DENY'); +// isDeleteConfirmation = true; + +// // Object.keys(this.formGroup['controls']).forEach((key: string) => { +// // if (key !== 'dmp' && (key!== 'profile')) { +// // if(key === 'descriptionProfileDefinition'){ +// // this.formGroup.get(key).patchValue(this.descriptionProfileDefinitionModel.buildForm().getRawValue); +// // }else{ +// // this.formGroup.get(key).reset(); +// // } + +// // } +// // }); +// } else { + +// messageText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-MESSAGE'); +// confirmButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-CONFIRM'); +// cancelButtonText = this.language.instant('DATASET-EDITOR.ACTIONS.DISCARD.DISCARD-EDITED-DENY'); +// isDeleteConfirmation = false; + +// // this.isDiscarded = true; +// // this.hasChanges = false; +// // this.hintErrors = false; +// // // this._unregisterFormListeners(); +// // this.formGroup.patchValue(JSON.parse(JSON.stringify(this.formGroupRawValue))); +// // // this.registerFormListeners(); +// // this.isDiscarded = false; + + +// } + + +// const dialogRef = this.dialog.open(ConfirmationDialogComponent, { +// restoreFocus: false, +// data: { +// message: messageText, +// confirmButton: confirmButtonText, +// cancelButton: cancelButtonText, +// isDeleteConfirmation: true +// }, +// maxWidth: '40em' +// }); +// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { +// if (result) { +// // this.backToDmp(this.formGroup.get('dmp').value.id) +// setTimeout(x => { +// this.init(); +// }); +// } +// }); + + +// // this.isDiscarded = false; +// } + +// addDescription(dmpId: string) { +// this.router.navigate(['/descriptions', 'new', dmpId]); +// } + +// reloadDateset(descriptionId: string) { +// let url = this.router.createUrlTree(['/descriptions', 'edit', descriptionId]).toString(); +// this.location.go(url); +// } + +// backToDmp(id: string) { +// this.router.navigate(['/plans', 'edit', id]); +// } + +// descriptionInfoValid(): boolean { +// return this.formGroup.get('label') && this.formGroup.get('label').valid && this.formGroup.get('profile') && this.formGroup.get('profile').valid; +// } + +// getLinks(currentLinks: Link[]) { +// this.links = currentLinks; +// } + +// printForm() { +// console.log(this.formGroup); +// } + +// printFormValue() { +// console.log(this.formGroup.value); +// } + +// touchForm() { +// this.formGroup.markAllAsTouched(); +// this.showtocentriesErrors = true; +// } +// } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.model.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.model.ts new file mode 100644 index 000000000..0f3c31457 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.model.ts @@ -0,0 +1,613 @@ +import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; +import { DescriptionStatus } from "@app/core/common/enum/description-status"; +import { Description, DescriptionField, DescriptionFieldPersist, DescriptionPersist, DescriptionReference, DescriptionReferencePersist, PropertyDefinition, PropertyDefinitionPersist } from "@app/core/model/description/description"; +import { 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'; +import { Guid } from "@common/types/guid"; + +export class DescriptionEditorModel extends BaseEditorModel implements DescriptionPersist { + label: string; + dmpId: Guid; + dmpDescriptionTemplateId: Guid; + descriptionTemplateId: Guid; + status: DescriptionStatus; + description: string; + properties: DescriptionPropertyDefinitionEditorModel; + tags: string[]; + references: DescriptionReferenceEditorModel[]; + permissions: string[]; + + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor() { super(); } + + public fromModel(item: Description): DescriptionEditorModel { + if (item) { + super.fromModel(item); + this.label = item.label; + this.dmpId = item.dmp?.id; + this.dmpDescriptionTemplateId = item.dmpDescriptionTemplate?.id; + this.descriptionTemplateId = item.descriptionTemplate?.id; + this.status = item.status; + this.description = item.description; + this.tags = item.descriptionTags?.map(x => x.tag?.label); + this.properties = new DescriptionPropertyDefinitionEditorModel().fromModel(item.properties); + //if (item.references) { item.references.map(x => this.references.push(new DescriptionReferenceEditorModel().fromModel(x))); } + } + 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], + dmpId: [{ value: this.dmpId, disabled: disabled }, context.getValidation('dmpId').validators], + dmpDescriptionTemplateId: [{ value: this.dmpDescriptionTemplateId, disabled: disabled }, context.getValidation('dmpDescriptionTemplateId').validators], + descriptionTemplateId: [{ value: this.descriptionTemplateId, disabled: disabled }, context.getValidation('descriptionTemplateId').validators], + status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], + description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], + tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators], + properties: this.properties.buildForm({ + rootPath: `properties.` + }), + 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: 'dmpId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'dmpId')] }); + baseValidationArray.push({ key: 'dmpDescriptionTemplateId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'dmpDescriptionTemplateId')] }); + baseValidationArray.push({ key: 'descriptionTemplateId', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'descriptionTemplateId')] }); + baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); + baseValidationArray.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] }); + baseValidationArray.push({ key: 'tags', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'tags')] }); + baseValidationArray.push({ key: 'hash', validators: [] }); + + baseContext.validation = baseValidationArray; + return baseContext; + } +} + +export class DescriptionPropertyDefinitionEditorModel implements PropertyDefinitionPersist { + fields: DescriptionFieldEditorModel[] = []; + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor( + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel() + ) { } + + public fromModel(item: PropertyDefinition): DescriptionPropertyDefinitionEditorModel { + if (item) { + if (item.fields) { item.fields.map(x => this.fields.push(new DescriptionFieldEditorModel().fromModel(x))); } + } + return this; + } + + buildForm(params?: { + context?: ValidationContext, + disabled?: boolean, + rootPath?: string + }): UntypedFormGroup { + let { context = null, disabled = false, rootPath } = params ?? {} + if (context == null) { + context = DescriptionPropertyDefinitionEditorModel.createValidationContext({ + validationErrorModel: this.validationErrorModel, + rootPath + }); + } + + return this.formBuilder.group({ + fields: this.formBuilder.array( + (this.fields ?? []).map( + (item, index) => new DescriptionFieldEditorModel( + this.validationErrorModel + ).fromModel(item).buildForm({ + rootPath: `${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: [BackendErrorValidator(validationErrorModel, `${rootPath}fields`)] }); + + baseContext.validation = baseValidationArray; + return baseContext; + } + +} + +export class DescriptionFieldEditorModel implements DescriptionFieldPersist { + key?: string; + value: string; + + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor( + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel() + ) { } + + public fromModel(item: DescriptionField): DescriptionFieldEditorModel { + if (item) { + this.key = item.key; + 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 = DescriptionFieldEditorModel.createValidationContext({ + validationErrorModel: this.validationErrorModel, + rootPath + }); + } + + return this.formBuilder.group({ + key: [{ value: this.key, disabled: disabled }, context.getValidation('key').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: 'key', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}key`)] }); + baseValidationArray.push({ key: 'value', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}value`)] }); + baseContext.validation = baseValidationArray; + return baseContext; + } + +} + +export class DescriptionReferenceEditorModel implements DescriptionReferencePersist { + id: Guid; + reference?: ReferencePersist; + hash: string; + + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor( + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel() + ) { } + + fromModel(item: DescriptionReference): DescriptionReferenceEditorModel { + this.id = item.id; + this.reference = item.reference; + this.hash = item.hash; + + return this; + } + + buildForm(params?: { + context?: ValidationContext, + disabled?: boolean, + rootPath?: string + }): UntypedFormGroup { + let { context = null, disabled = false, rootPath } = params ?? {} + if (context == null) { + context = DescriptionReferenceEditorModel.createValidationContext({ + validationErrorModel: this.validationErrorModel, + rootPath + }); + } + + return this.formBuilder.group({ + id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], + reference: [{ value: this.reference, disabled: disabled }, context.getValidation('reference').validators], + hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').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: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] }); + baseValidationArray.push({ key: 'reference', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}reference`)] }); + baseValidationArray.push({ key: 'hash', validators: [] }); + + baseContext.validation = baseValidationArray; + return baseContext; + } +} + +// export class DescriptionEditorModel { +// public id: string; +// public label: string; +// public profile: DescriptionProfileModel; +// public uri: String; +// public status: number; +// public description: String; +// public services: ExternalServiceEditorModel[] = []; +// public registries: ExternalRegistryEditorModel[] = []; +// public dataRepositories: ExternalDataRepositoryEditorModel[] = []; +// public tags: ExternalTagEditorModel[] = []; +// public externalDescriptions: ExternalDescriptionEditorModel[] = []; +// public dmp: DmpModel; +// public dmpSectionIndex: number; +// public descriptionProfileDefinition: DescriptionDescriptionFormEditorModel; +// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); +// public isProfileLatestVersion: Boolean; +// public modified: Date; + +// fromModel(item: DescriptionModel): DescriptionEditorModel { +// this.id = item.id; +// this.label = item.label; +// this.profile = item.profile; +// this.uri = item.uri; +// this.status = item.status; +// this.description = item.description; +// if (item.services) { this.services = item.services.map(x => new ExternalServiceEditorModel().fromModel(x)); } +// if (item.registries) { this.registries = item.registries.map(x => new ExternalRegistryEditorModel().fromModel(x)); } +// if (item.dataRepositories) { this.dataRepositories = item.dataRepositories.map(x => new ExternalDataRepositoryEditorModel().fromModel(x)); } +// if (item.externalDescriptions) { this.externalDescriptions = item.externalDescriptions.map(x => new ExternalDescriptionEditorModel().fromModel(x)); } +// this.dmp = item.dmp; +// this.dmpSectionIndex = item.dmpSectionIndex; +// if (item.descriptionProfileDefinition) { this.descriptionProfileDefinition = new DescriptionDescriptionFormEditorModel().fromModel(item.descriptionProfileDefinition); } +// if (item.tags) { this.tags = item.tags.map(x => new ExternalTagEditorModel().fromModel(x)); } +// this.isProfileLatestVersion = item.isProfileLatestVersion; +// this.modified = new Date(item.modified); +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// if (context == null) { context = this.createValidationContext(); } +// const formBuilder = new UntypedFormBuilder(); +// const formGroup = formBuilder.group({ +// id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], +// label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], +// uri: [{ value: this.uri, disabled: disabled }, context.getValidation('uri').validators], +// status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], +// description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], +// dmp: [{ value: this.dmp, disabled: disabled }, context.getValidation('dmp').validators], +// dmpSectionIndex: [{ value: this.dmpSectionIndex, disabled: disabled }, context.getValidation('dmpSectionIndex').validators], +// //externalDescriptions: [{ value: this.externalDescriptions, disabled: disabled }, context.getValidation('externalDescriptions').validators], +// tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators], +// //registries: [{ value: this.registries, disabled: disabled }, context.getValidation('registries').validators], +// //dataRepositories: [{ value: this.dataRepositories, disabled: disabled }, context.getValidation('dataRepositories').validators], +// //services: [{ value: this.services, disabled: disabled }, context.getValidation('services').validators], +// profile: [{ value: this.profile, disabled: disabled }, context.getValidation('profile').validators], +// modified: [{value: this.modified, disabled: disabled}, context.getValidation('modified').validators] +// }); + +// const externalDescriptionsFormArray = new Array(); +// //if (this.externalDescriptions && this.externalDescriptions.length > 0) { +// this.externalDescriptions.forEach(item => { +// externalDescriptionsFormArray.push(item.buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// }); +// // } else { +// // //externalDescriptionsFormArray.push(new ExternalDescriptionModel().buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// // } +// formGroup.addControl('externalDescriptions', formBuilder.array(externalDescriptionsFormArray)); + +// // const tagsFormArray = new Array(); +// // if (this.tags && this.tags.length > 0) { +// // this.tags.forEach(item => { +// // tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled)); +// // }); +// // } else { +// // //externalDescriptionsFormArray.push(new ExternalDescriptionModel().buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// // } +// // formGroup.addControl('tags', formBuilder.array(tagsFormArray)); + +// const registriesFormArray = new Array(); +// //if (this.registries && this.registries.length > 0) { +// this.registries.forEach(item => { +// registriesFormArray.push(item.buildForm(context.getValidation('registries').descendantValidations, disabled)); +// }); +// // } else { +// // //externalDescriptionsFormArray.push(new ExternalDescriptionModel().buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// // } +// formGroup.addControl('registries', formBuilder.array(registriesFormArray)); + +// const dataRepositoriesFormArray = new Array(); +// //if (this.dataRepositories && this.dataRepositories.length > 0) { +// this.dataRepositories.forEach(item => { +// dataRepositoriesFormArray.push(item.buildForm(context.getValidation('dataRepositories').descendantValidations, disabled)); +// }); +// // } else { +// // //externalDescriptionsFormArray.push(new ExternalDescriptionModel().buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// // } +// formGroup.addControl('dataRepositories', formBuilder.array(dataRepositoriesFormArray)); + +// const servicesFormArray = new Array(); +// // if (this.services && this.services.length > 0) { +// this.services.forEach(item => { +// servicesFormArray.push(item.buildForm(context.getValidation('services').descendantValidations, disabled)); +// }); +// // } else { +// // //externalDescriptionsFormArray.push(new ExternalDescriptionModel().buildForm(context.getValidation('externalDescriptions').descendantValidations, disabled)); +// // } +// formGroup.addControl('services', formBuilder.array(servicesFormArray)); + +// // const tagsFormArray = new Array(); +// // this.tags.forEach(item => { +// // tagsFormArray.push(item.buildForm(context.getValidation('tags').descendantValidations, disabled)); +// // }); +// // formGroup.addControl('tags', formBuilder.array(tagsFormArray)); + +// if (this.descriptionProfileDefinition) { formGroup.addControl('descriptionProfileDefinition', this.descriptionProfileDefinition.buildForm()); } +// // formGroup.addControl('profile', this.profile.buildForm()); +// return formGroup; +// } + +// createValidationContext(): ValidationContext { +// const baseContext: ValidationContext = new ValidationContext(); +// 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: 'externalDescriptions', validators: [BackendErrorValidator(this.validationErrorModel, 'externalDescriptions')] }); +// baseContext.validation.push({ key: 'dmp', validators: [BackendErrorValidator(this.validationErrorModel, 'dmp')] }); +// baseContext.validation.push({ key: 'dmpSectionIndex', validators: [BackendErrorValidator(this.validationErrorModel, 'dmpSectionIndex')] }); +// baseContext.validation.push({ key: 'descriptionProfileDefinition', validators: [BackendErrorValidator(this.validationErrorModel, 'descriptionProfileDefinition')] }); +// baseContext.validation.push({ key: 'tags', validators: [BackendErrorValidator(this.validationErrorModel, 'descriptionProfileDefinition')] }); +// baseContext.validation.push({ key: 'modified', validators: []}); +// return baseContext; +// } +// } + +// export class ExternalTagEditorModel { +// public abbreviation: String; +// public definition: String; +// public id: String; +// public name: String; +// public reference: String; +// public uri: String; + +// constructor(id?: String, name?: String) { +// this.id = id; +// this.name = name; +// } + +// fromModel(item: TagModel): ExternalTagEditorModel { +// this.id = item.id; +// this.name = item.name; +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// return new UntypedFormBuilder().group({ +// id: [this.id], +// name: [this.name] +// }); +// } +// } + +// export class ExternalServiceEditorModel { +// public id: String; +// public abbreviation: String; +// public definition: String; +// public uri: String; +// public label: String; +// public reference: String; +// public source: String; + +// constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) { +// this.id = id; +// this.abbreviation = abbreviation; +// this.definition = definition; +// this.uri = uri; +// this.label = label; +// this.reference = reference; +// this.source = source; +// } + +// fromModel(item: ServiceModel): ExternalServiceEditorModel { +// this.id = item.id; +// this.abbreviation = item.abbreviation; +// this.definition = item.definition; +// this.uri = item.uri; +// this.label = item.label; +// this.reference = item.reference; +// this.source = item.source; +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// return new UntypedFormBuilder().group({ +// id: [this.id], +// abbreviation: [this.abbreviation], +// label: [this.label, Validators.required], +// reference: [this.reference], +// uri: [this.uri, Validators.required], +// definition: [this.definition], +// source: [this.source] +// }); +// } +// } + +// export class ExternalRegistryEditorModel { +// public abbreviation: String; +// public definition: String; +// public id: String; +// public label: String; +// public reference: String; +// public uri: String; +// public source: String + +// constructor(abbreviation?: String, definition?: String, id?: String, label?: String, reference?: String, uri?: String, source?: String) { +// this.abbreviation = abbreviation; +// this.definition = definition; +// this.id = id; +// this.label = label; +// this.reference = reference; +// this.uri = uri; +// this.source = source; +// } + +// fromModel(item: RegistryModel): ExternalRegistryEditorModel { +// this.abbreviation = item.abbreviation; +// this.definition = item.definition; +// this.id = item.id; +// this.label = item.label; +// this.reference = item.pid ? item.pid : item.reference; +// this.uri = item.uri; +// this.source = item.source + +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// return new UntypedFormBuilder().group({ +// id: [this.id], +// abbreviation: [this.abbreviation], +// label: [this.label, Validators.required], +// reference: [this.reference], +// uri: [this.uri, Validators.required], +// definition: [this.definition], +// source: [this.source] +// }); +// } +// } + +// export class ExternalDescriptionEditorModel { + +// public abbreviation: String; +// public id: String; +// public name: String; +// public reference: String; +// public type: ExternalDescriptionType; +// public info: String; +// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); +// public source: String; + +// constructor(id?: string, abbreviation?: string, name?: string, reference?: string, source?: String, info?: string, type?: ExternalDescriptionType) { +// this.id = id; +// this.name = name; +// this.abbreviation = abbreviation; +// this.reference = reference; +// this.info = info; +// this.type = type; +// this.source = source; +// } + +// fromModel(item: ExternalDescriptionModel): ExternalDescriptionEditorModel { +// this.abbreviation = item.abbreviation; +// this.id = item.id; +// this.name = item.name; +// this.reference = item.reference; +// this.type = item.type; +// this.info = item.info; +// this.source = item.source; +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// return new UntypedFormBuilder().group({ +// id: [this.id], +// abbreviation: [this.abbreviation], +// name: [this.name, Validators.required], +// reference: [this.reference], +// type: [this.type], +// info: [this.info], +// source: [this.source] +// }); +// } +// } + +// export class ExternalDataRepositoryEditorModel { +// public id: string; +// public name: string; +// public abbreviation: string; +// public uri: string; +// public reference: string; +// public info: string; +// public created: Date; +// public modified: Date; +// public source: string; + +// constructor(id?: string, name?: string, abbreviation?: string, uri?: string, reference?: string, source?: string) { +// this.id = id; +// this.name = name; +// this.abbreviation = abbreviation; +// this.uri = uri; +// this.reference = reference; +// this.source = source; +// } + +// fromModel(item: DataRepositoryModel): ExternalDataRepositoryEditorModel { +// this.id = item.id; +// this.name = item.name; +// this.abbreviation = item.abbreviation; +// this.uri = item.uri; +// this.info = item.info; +// this.reference = item.pid; +// this.source = item.source; +// return this; +// } + +// buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { +// return new UntypedFormBuilder().group({ +// id: [this.id], +// name: [this.name, [Validators.required]], +// abbreviation: [this.abbreviation], +// uri: [this.uri, [Validators.required]], +// info: [this.info], +// reference: [this.reference], +// source: [this.source] +// }); +// } +// } + +// // export class TagModel implements Serializable { + +// // public id: string; +// // public name: string; + +// // constructor(id?: string, name?: string) { +// // this.id = id; +// // this.name = name; +// // } + +// // fromJSONObject(item: any): TagModel { +// // this.id = item.id; +// // this.name = item.name; +// // return this; +// // } + +// // buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { +// // return new FormBuilder().group({ +// // id: [this.id], +// // name: [this.name] +// // }); +// // } +// // } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts new file mode 100644 index 000000000..633ed936d --- /dev/null +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; +import { Description, DescriptionField, DescriptionReference, DescriptionTag, PropertyDefinition } from '@app/core/model/description/description'; +import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp'; +import { Reference } from '@app/core/model/reference/reference'; +import { Tag } from '@app/core/model/tag/tag'; +import { DescriptionService } from '@app/core/services/description/description.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 DescriptionEditorResolver extends BaseEditorResolver { + + constructor(private descriptionService: DescriptionService, private breadcrumbService: BreadcrumbService) { + super(); + } + + public static lookupFields(): string[] { + return [ + ...BaseEditorResolver.lookupFields(), + nameof(x => x.id), + nameof(x => x.label), + nameof(x => x.status), + nameof(x => x.description), + nameof(x => x.status), + [nameof(x => x.dmp), nameof(x => x.id)].join('.'), + + [nameof(x => x.dmpDescriptionTemplate), nameof(x => x.id)].join('.'), + + [nameof(x => x.descriptionTemplate), nameof(x => x.id)].join('.'), + + [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.key)].join('.'), + [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.value)].join('.'), + + [nameof(x => x.descriptionTags), nameof(x => x.id),].join('.'), + [nameof(x => x.descriptionTags), nameof(x => x.tag), nameof(x => x.label)].join('.'), + + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.label)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.type)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.reference)].join('.'), + nameof(x => x.createdAt), + nameof(x => x.hash), + nameof(x => x.isActive) + ] + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + + const fields = [ + ...DescriptionEditorResolver.lookupFields() + ]; + const id = route.paramMap.get('id'); + // const cloneid = route.paramMap.get('cloneid'); + if (id != null) { + return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); + } + //TODO: check this + // else if (cloneid != null) { + // return this.descriptionService.clone(Guid.parse(cloneid), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); + // } + } +} diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.service.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.service.ts new file mode 100644 index 000000000..6dbad1783 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/dataset-wizard/description-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 DescriptionEditorService { + 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/description/description.module.ts b/dmp-frontend/src/app/ui/description/description.module.ts index de71c24eb..6d15033b4 100644 --- a/dmp-frontend/src/app/ui/description/description.module.ts +++ b/dmp-frontend/src/app/ui/description/description.module.ts @@ -27,6 +27,7 @@ import { CommonUiModule } from '@common/ui/common-ui.module'; import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; import { DescriptionCopyDialogModule } from './description-copy-dialog/description-copy-dialog.module'; import { DescriptionOverviewModule } from './overview/description-overview.module'; +import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component'; // import { FormProgressIndicationModule } from '../misc/description-description-form/components/form-progress-indication/form-progress-indication.module'; // import { DescriptionCopyDialogModule } from './description-wizard/description-copy-dialogue/description-copy-dialogue.module'; // import { DescriptionCriteriaDialogComponent } from './listing/criteria/description-criteria-dialogue/description-criteria-dialog.component'; @@ -53,13 +54,13 @@ import { DescriptionOverviewModule } from './overview/description-overview.modul RichTextEditorModule, DescriptionCopyDialogModule, - DescriptionOverviewModule + DescriptionOverviewModule, ], declarations: [ DescriptionListingComponent, // DescriptionCriteriaComponent, // DescriptionWizardComponent, - // DescriptionEditorComponent, + DescriptionEditorComponent, // DescriptionExternalReferencesEditorComponent, // DescriptionExternalDataRepositoryDialogEditorComponent, // DescriptionExternalDescriptionDialogEditorComponent, diff --git a/dmp-frontend/src/app/ui/description/description.routing.ts b/dmp-frontend/src/app/ui/description/description.routing.ts index 11f55612f..08f511956 100644 --- a/dmp-frontend/src/app/ui/description/description.routing.ts +++ b/dmp-frontend/src/app/ui/description/description.routing.ts @@ -4,7 +4,13 @@ import { AuthGuard } from '../../core/auth-guard.service'; // import { DescriptionWizardComponent } from './description-wizard/description-wizard.component'; import { DescriptionListingComponent } from './listing/description-listing.component'; import { DescriptionOverviewComponent } from './overview/description-overview.component'; +import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; +import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { DescriptionEditorResolver } from './dataset-wizard/description-editor.resolver'; +import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service'; // import { DescriptionOverviewComponent } from './overview/description-overview.component'; +import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service'; const routes: Routes = [ { @@ -38,7 +44,24 @@ const routes: Routes = [ breadcrumb: true, title: 'GENERAL.TITLES.DATASET-OVERVIEW' }, - } + }, + { + path: 'edit/:id', + canActivate: [AuthGuard], + component: DescriptionEditorComponent, + canDeactivate: [PendingChangesGuard], + resolve: { + 'entity': DescriptionEditorResolver + }, + data: { + ...BreadcrumbService.generateRouteDataConfiguration({ + title: 'BREADCRUMBS.EDIT-DESCRIPTION' + }), + authContext: { + permissions: [AppPermission.EditDescription] + } + } + }, // { // path: 'new/:dmpId/:dmpSectionIndex', // component: DescriptionWizardComponent, @@ -49,17 +72,7 @@ const routes: Routes = [ // }, // canDeactivate:[CanDeactivateGuard] // }, - // { - // path: 'edit/:id', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // public: false, - // title: 'GENERAL.TITLES.DATASET-EDIT' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, + // { // path: 'edit/:id/finalize', // component: DescriptionWizardComponent, @@ -117,6 +130,7 @@ const routes: Routes = [ @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], + providers: [DescriptionEditorResolver] }) export class DescriptionRoutingModule { } diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.component.html b/dmp-frontend/src/app/ui/description/overview/description-overview.component.html index 9a7bb3f19..fafc186de 100644 --- a/dmp-frontend/src/app/ui/description/overview/description-overview.component.html +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.component.html @@ -103,7 +103,7 @@
-
+
diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts index 11b101b49..10fb19d5a 100644 --- a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts @@ -12,8 +12,8 @@ import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; import { ReferenceType } from '@app/core/common/enum/reference-type'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; -import { Description } from '@app/core/model/description/description'; -import { Dmp, DmpUser } from '@app/core/model/dmp/dmp'; +import { Description, DescriptionStatusPersist } from '@app/core/model/description/description'; +import { Dmp, DmpUser, DmpUserRemovePersist } from '@app/core/model/dmp/dmp'; import { DmpReference, Reference } from '@app/core/model/reference/reference'; import { AuthService } from '@app/core/services/auth/auth.service'; import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; @@ -365,18 +365,18 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni }); dialogRef.afterClosed().subscribe(result => { if (result) { - //TODO: implement remove user from backend - // const index = this.users.findIndex(x => x.id === user.id); - // if (index > -1) { - // this.users.splice(index, 1); - // } - // this.dmpService.updateUsers(this.description.dmp.id, this.users).pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => { - // this.onUpdateCallbackSuccess(); - // }, - // error => this.onUpdateCallbackError(error) - // ); + const dmpUserRemovePersist: DmpUserRemovePersist = { + id: dmpUser.id, + dmpId: this.description.dmp.id, + role: dmpUser.role + }; + this.dmpService.removeUser(dmpUserRemovePersist).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.reloadPage(); + }, (error: any) => { + //TODO: Error handling + }); + } }); } @@ -405,7 +405,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni return description.dmp.status == DmpStatus.Draft && description.status == DescriptionStatus.Finalized } - reverse(description: Description) { + reverseFinalization(description: Description) { const dialogRef = this.dialog.open(ConfirmationDialogComponent, { restoreFocus: false, data: { @@ -417,19 +417,18 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result) { - // TODO: implement endpoint to undo finalization to a Description and set it to Draft again - // this.descriptionWizardService.getSingle(description.id) - // .pipe(takeUntil(this._destroyed)) - // .subscribe(data => { - // this.description = data; - // this.description.status = DescriptionStatus.Draft; - // this.descriptionWizardService.createDescription(this.description) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // data => this.onUpdateCallbackSuccess(), - // error => this.onUpdateCallbackError(error) - // ); - // }); + const dmpUserRemovePersist: DescriptionStatusPersist = { + id: description.id, + status: DescriptionStatus.Draft, + hash: description.hash + }; + this.descriptionService.persistStatus(dmpUserRemovePersist).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.reloadPage(); + this.onUpdateCallbackSuccess() + }, (error: any) => { + this.onUpdateCallbackError(error) + }); } }); } diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 16606b9dc..a79cbc0c8 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -94,7 +94,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr this.lookup.isActive = [IsActive.Active]; if (this.groupId != null && Guid.isGuid(this.groupId)) { - // this.lookup.groupIds = [this.groupId]; //TODO: add filter in backend + this.lookup.groupIds = [Guid.parse(this.groupId)]; } this.refresh(this.lookup); diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html index afb2be780..3d8a5bd20 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html @@ -32,7 +32,7 @@ add{{'DMP-LISTING.ACTIONS.ADD-DESCRIPTION-SHORT' | translate}} group_add{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}} filter_none{{'DMP-LISTING.ACTIONS.CLONE' | translate}} - library_books{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}} + library_books{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}} delete{{ 'DMP-LISTING.ACTIONS.DELETE' | translate }} more_horiz @@ -60,7 +60,7 @@ -