diff --git a/dmp-frontend/src/annotation-service/services/core-service.module.ts b/dmp-frontend/src/annotation-service/services/core-service.module.ts index 4e967df1c..58e1e9189 100644 --- a/dmp-frontend/src/annotation-service/services/core-service.module.ts +++ b/dmp-frontend/src/annotation-service/services/core-service.module.ts @@ -24,13 +24,13 @@ export class CoreAnnotationServiceModule { return { ngModule: CoreAnnotationServiceModule, providers: [ - BaseHttpV2Service, + BaseHttpV2Service, HttpErrorHandlingService, FilterService, FormService, LoggingService, PrincipalService, - AnnotationService + AnnotationService ], }; } diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index b2c06f73f..d10e6ad88 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -80,16 +80,6 @@ const appRoutes: Routes = [ title: 'GENERAL.TITLES.ABOUT' } }, - // ----------- UNCOMMENT TO ADD AGAIN GRANTS -------- - // { - // path: 'grants', - // loadChildren: () => import('./ui/grant/grant.module').then(m => m.GrantModule), - // data: { - // breadcrumb: true, - // title: 'GENERAL.TITLES.GRANTS' - // } - // }, - { path: 'description-templates', diff --git a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts index ee9220d69..2a7bfd10f 100644 --- a/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts +++ b/dmp-frontend/src/app/ui/annotations/annotation-dialog-component/annotation-dialog.component.ts @@ -1,4 +1,3 @@ -import { HttpClient } from '@angular/common/http'; import { Component, Inject } from '@angular/core'; import { FormBuilder, FormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; @@ -31,6 +30,8 @@ export class AnnotationDialogComponent extends BaseComponent { private anchor: string; private entityType: string; + private changesMade: boolean = false; + public comments = new Array(); public threads = new Set(); public annotationsPerThread = {}; @@ -49,12 +50,13 @@ export class AnnotationDialogComponent extends BaseComponent { private language: TranslateService, private annotationService: AnnotationService, private formService: FormService, - private enumUtils: EnumUtils + private enumUtils: EnumUtils, ) { super(); this.entityId = data.entityId; this.anchor = data.anchor; this.entityType = data.entityType; + dialogRef.beforeClosed().pipe(takeUntil(this._destroyed)).subscribe(() => dialogRef.close(this.changesMade)); } ngOnInit(): void { @@ -199,8 +201,7 @@ export class AnnotationDialogComponent extends BaseComponent { private onCallbackSuccess() { this.uiNotificationService.snackBarNotification(this.language.instant('ANNOTATION-DIALOG.SUCCESS'), SnackBarNotificationLevel.Success); this.refreshAnnotations(); - // this.router.navigate(['/reload']).then(() => this.router.navigate(['/plans'])); - // this.router.navigate(['/reload']).then(() => this.isPublic ? this.router.navigate(['/explore-plans']) : this.router.navigate(['/plans'])); + this.changesMade = true; } private onCallbackError(error: any) { @@ -214,15 +215,11 @@ export class AnnotationDialogComponent extends BaseComponent { cancel() { - this.dialogRef.close(); - } - - send() { - this.dialogRef.close(this.data); + this.dialogRef.close(this.changesMade); } close() { - this.dialogRef.close(false); + this.dialogRef.close(this.changesMade); } startWizard() { diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html index e652970a0..a6d8faf1a 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html @@ -6,7 +6,7 @@
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts index 983ff0b8f..452315966 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts @@ -13,6 +13,7 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid import { Guid } from '@common/types/guid'; import { AnnotationDialogComponent } from '@app/ui/annotations/annotation-dialog-component/annotation-dialog.component'; import { AnnotationEntityType } from '@app/core/common/enum/annotation-entity-type'; +import { DescriptionFormAnnotationService } from '../../description-form-annotation.service'; @Component({ selector: 'app-description-form-field-set', @@ -52,7 +53,8 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { constructor( private dialog: MatDialog, - private changeDetector: ChangeDetectorRef + private changeDetector: ChangeDetectorRef, + private descriptionFormAnnotationService: DescriptionFormAnnotationService ) { super(); } @@ -79,7 +81,7 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { } const item: DescriptionPropertyDefinitionFieldSetEditorModel = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel).calculateFieldSetProperties(this.fieldSet, null, null); - formArray.push((item.buildForm({rootPath: `properties.fieldSets[${this.fieldSet.id}].`}).get('items') as UntypedFormArray).at(0)); + formArray.push((item.buildForm({ rootPath: `properties.fieldSets[${this.fieldSet.id}].` }).get('items') as UntypedFormArray).at(0)); } @@ -134,50 +136,12 @@ export class DescriptionFormFieldSetComponent extends BaseComponent { entityType: AnnotationEntityType.Description } }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result && result.success) { - //TODO refactor + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(changesMade => { + if (changesMade) { + this.descriptionFormAnnotationService.refreshAnnotations(() => { + this.changeDetector.markForCheck(); + }); } }); } - - - - // deleteCompositeFieldFormGroup() { - - // const compositeFieldId = ((this.form.get('multiplicityItems') as UntypedFormArray).get('' + 0) as UntypedFormGroup).getRawValue().id; - // const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[]; - - // const numberOfItems = this.form.get('multiplicityItems').get('' + 0).get('fields').value.length; - // for (let i = 0; i < numberOfItems; i++) { - // const multiplicityItem = this.form.get('multiplicityItems').get('' + 0).get('fields').get('' + i).value; - // this.form.get('fields').get('' + i).patchValue(multiplicityItem); - // } - // ((this.form.get('multiplicityItems'))).removeAt(0); - - - // this.visibilityRulesService.removeAllIdReferences(compositeFieldId); - // fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x)); - // } - - // deleteMultipeFieldFromCompositeFormGroup() { - // const parent = this.form.parent; - // const index = (parent as UntypedFormArray).controls.indexOf(this.form); - - // const currentId = this.form.get('id').value; - // const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[]; - - - // this.visibilityRulesService.removeAllIdReferences(currentId); - // fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x)); - - // (parent as UntypedFormArray).removeAt(index); - // (parent as UntypedFormArray).controls.forEach((control, i) => { - // try { - // control.get('ordinal').setValue(i); - // } catch { - // throw 'Could not find ordinal'; - // } - // }); - // } } diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts index 54aa1c6e8..fe9765583 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts @@ -34,6 +34,7 @@ export class DescriptionFormSectionComponent extends BaseComponent implements On @Input() path: string; @Input() descriptionId: Guid; + // @Input() datasetProfileId: String; // @Input() form: UntypedFormGroup; @Input() tocentry: ToCEntry; diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts new file mode 100644 index 000000000..3662abe15 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form-annotation.service.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@angular/core'; +import { Annotation } from '@annotation-service/core/model/annotation.model'; +import { AnnotationLookup } from '@annotation-service/core/query/annotation.lookup'; +import { AnnotationService } from '@annotation-service/services/http/annotation.service'; +import { AnnotationEntityType } from '@app/core/common/enum/annotation-entity-type'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { BaseService } from '@common/base/base.service'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; + + +@Injectable({ + providedIn: 'any', +}) +export class DescriptionFormAnnotationService extends BaseService { + + private entityId: Guid; + private annotationsPerAnchor: Map; + + constructor( + private annotationService: AnnotationService, + private uiNotificationService: UiNotificationService, + private language: TranslateService + ) { + super(); + } + + init(entityId: Guid) { + this.entityId = entityId; + this.refreshAnnotations(); + } + + public getCount(anchor: string) { + if (this.annotationsPerAnchor.has(anchor)) { + return this.annotationsPerAnchor.get(anchor); + } else { + return 0; + } + } + + public refreshAnnotations(onSuccess?: () => void) { + const lookup: AnnotationLookup = new AnnotationLookup(); + lookup.entityIds = [this.entityId]; + lookup.entityTypes = [AnnotationEntityType.Description]; + lookup.project = { + fields: [ + nameof(x => x.id), + nameof(x => x.anchor), + ] + }; + + this.annotationService.query(lookup) + .pipe(takeUntil(this._destroyed)) + .subscribe( + data => { + this.annotationsPerAnchor = new Map(); + for (const item of data.items) { + if (!this.annotationsPerAnchor.has(item.anchor)) { + this.annotationsPerAnchor.set(item.anchor, 0); + } + this.annotationsPerAnchor.set(item.anchor, this.annotationsPerAnchor.get(item.anchor) + 1); + } + onSuccess ? onSuccess() : null; + }, + error => this.onCallbackError(error), + ); + } + + private onCallbackError(error: any) { + this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); + } +} + diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts index 31828a4d8..8befbf6d0 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts @@ -1,13 +1,13 @@ import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; import { MatExpansionPanel } from '@angular/material/expansion'; -import { DescriptionTemplate, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; +import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { BaseComponent } from '@common/base/base.component'; -import { LinkToScroll } from '../table-of-contents/table-of-contents.component'; -import { VisibilityRulesService } from './visibility-rules/visibility-rules.service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { Guid } from '@common/types/guid'; -import { RuleWithTarget } from './visibility-rules/models/rule'; +import { LinkToScroll } from '../table-of-contents/table-of-contents.component'; +import { DescriptionFormAnnotationService } from './description-form-annotation.service'; +import { VisibilityRulesService } from './visibility-rules/visibility-rules.service'; @Component({ selector: 'app-description-form', @@ -22,6 +22,7 @@ export class DescriptionFormComponent extends BaseComponent implements OnInit, A @Input() descriptionId: Guid; + // @ViewChild('stepper', { static: false }) stepper: MatStepper; @Input() path: string; @Input() datasetDescription: String; @@ -38,6 +39,7 @@ export class DescriptionFormComponent extends BaseComponent implements OnInit, A // public hiddenEntriesIds: string[] = []; constructor( + public descriptionFormAnnotationService: DescriptionFormAnnotationService, ) { super(); @@ -57,6 +59,11 @@ export class DescriptionFormComponent extends BaseComponent implements OnInit, A // this.stepper.selectedIndex = changes['linkToScroll'].currentValue.page; // } // } + + + if (this.descriptionId != null) { + this.descriptionFormAnnotationService.init(this.descriptionId); + } } ngAfterViewInit() { @@ -99,273 +106,4 @@ export class DescriptionFormComponent extends BaseComponent implements OnInit, A // this.fieldsetFocusChange.emit(id); } - - - // private _enrichWithMultiplicityRules(tocentries: ToCEntry[]): Rule[] { - // if (tocentries) { - // return tocentries.map(entry => { - // if (entry.type === ToCEntryType.Field) return []; // * TODO Me to tora implementation den tha ftasei pote edo - - - // if (entry.type === ToCEntryType.FieldSet) { - // // if(multiplicity: ) - // try { - // // TODO OTAN KANW HIDE MULTIPLE PEDIO TOTE STO ON SHOW HANO TA VALUES (AUTO MPOREI NA EINAI KAI LEGIT) ('NA DOUME AN ONTOS DIAGRAFONTAI I APLA DEN TA DEIXNOUME') - // // * UPDATE KANEI DESTROY TO COMPONENT H NGIF . PITHANOTATA NA XREIASTEI NA TO KANOUME HIDDEN AN THELOUME KATI ALLO - // const multiplicity = entry.form.get('multiplicity').value; - // if ((multiplicity.max > 1) && (multiplicity.min > 0) && (multiplicity.max >= multiplicity.min)) { // has valid multiplicity - // return this._createAndAppendVisibilityRule(entry); - // } - // } catch { - - // } - // return []; - // } - - // if (entry.subEntries) { - // return this._enrichWithMultiplicityRules(entry.subEntries); - // } - // }) - // .reduce((r, c) => { return [...c, ...r] }, []); - // } - // return []; - // } - - // private _createAndAppendVisibilityRule(entry: ToCEntry): Rule[] { - - - // const rules_to_append = []; - - // if (entry && (entry.type === ToCEntryType.FieldSet)) { - - // //childs that are either target or source - // const childIdsWithVisRules = (entry.form.get('fields') as UntypedFormArray).controls.reduce((all, s) => { - // const sval = s.value as Field; - // return this.visibilityRules.find(x => (x.targetField === sval.id) || (x.sourceField === sval.id)) ? [...all, sval] : all; - // }, []) as Field[]; - - - // const innerCompositeFieldOriginalIds = (entry.form.get('fields') as UntypedFormArray).controls.map(x => x.get('id').value) as string[]; - - // //multiplicity items - // const multiplicityItemsValue = entry.form.get('multiplicityItems').value as CompositeField[]; - - - // // ********* FIELDS OF FIELDSET ARE EITHER TARGETS OR SOURCES ***** - - - // if (childIdsWithVisRules.length && multiplicityItemsValue && multiplicityItemsValue.length) { - // //check each multiplicity item composite field - // multiplicityItemsValue.forEach(mi => { - - // const multiplicityCompositeFieldIds = mi.fields.map(x => x.id); - // const idMappings = multiplicityCompositeFieldIds.map(x => { - // return { - // original: innerCompositeFieldOriginalIds.find(l => x.includes(l)), - // multiplicityIdValue: x - // } - // }) as { original: string, multiplicityIdValue: string }[]; - - // //each field of mutliplicity item - // mi.fields.forEach(field => { - - - // //get original visibility rules (original field) - - // //original id - // const original_id = childIdsWithVisRules.find(x => field.id.includes(x.id)).id; - - - // //get vis rules - - // //as source - // const original_as_source = this.visibilityRules.filter(x => x.sourceField === original_id); - // const original_as_target = this.visibilityRules.filter(x => x.targetField === original_id); - - - - // if (original_as_source.length) { - - // //inner dependencies - // const innerDep = original_as_source.filter(x => innerCompositeFieldOriginalIds.includes(x.targetField)); - // innerDep.forEach(x => { - // const newRule = { ...x, sourceField: field.id, targetField: idMappings.find(l => l.original === x.targetField).multiplicityIdValue } as Rule; - // rules_to_append.push(newRule); - // }) - - - // //outer dependencies - // const outerDep = original_as_source.filter(x => !innerCompositeFieldOriginalIds.includes(x.targetField)); - // outerDep.forEach(x => { - // const newRule = { ...x, sourceField: field.id }; - // rules_to_append.push(newRule); - // }) - // } - - - - // if (original_as_target.length) { - - // //inner dependencies - // const innerDep = original_as_target.filter(x => innerCompositeFieldOriginalIds.includes(x.sourceField)); - // innerDep.forEach(x => { - // const newRule = { ...x, targetField: field.id, sourceField: idMappings.find(l => l.original === x.sourceField).multiplicityIdValue } as Rule; - // rules_to_append.push(newRule); - // }) - - // //outer dependencies - // const outerDep = original_as_target.filter(x => !innerCompositeFieldOriginalIds.includes(x.sourceField)); - // outerDep.forEach(x => { - // const newRule = { ...x, targetField: field.id } as Rule; - // rules_to_append.push(newRule); - // }) - // } - - // }) - // }); - // } - - - - - // // ** FIELDSET ITSELF IS TARGET - // // ** source it can never be - - // const compositeFieldAsTargetRules = this.visibilityRules.filter(x => x.targetField === entry.id); - // const idCompositeFieldMappings = multiplicityItemsValue.map(x => { - // return { - // originalValue: entry.id, - // newValue: x.id - // } - // }) as { originalValue: string, newValue: string }[]; - - - // if (compositeFieldAsTargetRules.length) { - - // compositeFieldAsTargetRules.forEach(x => { - // idCompositeFieldMappings.forEach(l => { - // const newRule = { ...x, targetField: l.newValue }; - // rules_to_append.push(newRule); - // }); - // }); - // } - - - // } - - // return rules_to_append; - // } - - // private _buildRecursively(form: UntypedFormGroup, whatAmI: ToCEntryType): ToCEntry { - // if (!form) return null; - - // switch (whatAmI) { - // case ToCEntryType.Section: - // const sections = form.get('sections') as UntypedFormArray; - // const fieldsets = form.get('compositeFields') as UntypedFormArray; - - - // const tempResult: ToCEntry[] = []; - - // if (sections && sections.length) { - // sections.controls.forEach(section => { - // tempResult.push(this._buildRecursively(section as UntypedFormGroup, ToCEntryType.Section)); - // }); - - // } else if (fieldsets && fieldsets.length) { - // fieldsets.controls.forEach(fieldset => { - // tempResult.push(this._buildRecursively(fieldset as UntypedFormGroup, ToCEntryType.FieldSet)); - // }); - // } - // return { - // // form: form, - // id: form.get('id').value, - // label: form.get('title').value, - // numbering: '', - // subEntries: tempResult, - // subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet, - // type: ToCEntryType.Section, - // ordinal: form.get('ordinal').value - // } - // case ToCEntryType.FieldSet: - // return { - // // form: form, - // label: form.get('title').value, - // id: form.get('id').value, - // numbering: 's', - // subEntries: [], - // subEntriesType: ToCEntryType.Field, - // type: ToCEntryType.FieldSet, - // ordinal: form.get('ordinal').value - // } - // } - // } - - // private _sortByOrdinal(tocentries: ToCEntry[]) { - - // if (!tocentries || !tocentries.length) return; - - // tocentries.sort(this._customCompare); - // tocentries.forEach(entry => { - // this._sortByOrdinal(entry.subEntries); - // }); - // } - - // private _customCompare(a, b) { - // return a.ordinal - b.ordinal; - // } - - // private _calculateNumbering(tocentries: ToCEntry[], depth: number[] = []) { - // if (!tocentries || !tocentries.length) { - // return; - // } - - // let prefixNumbering = depth.length ? depth.join('.') : ''; - - // if (depth.length) prefixNumbering = prefixNumbering + "."; - // tocentries.forEach((entry, i) => { - // entry.numbering = prefixNumbering + (i + 1); - // this._calculateNumbering(entry.subEntries, [...depth, i + 1]) - // }); - // } - - // getTocEntries(): ToCEntry[] { - // if (!this.form) { return []; } - // const result: ToCEntry[] = []; - - // //build parent pages - // (this.form.get('pages') as UntypedFormArray).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 UntypedFormArray; - - // sections.controls.forEach(section => { - // const tempResults = this._buildRecursively(section as UntypedFormGroup, 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/editor/description-form/description-form.module.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts index d816a63ce..c553a3f13 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts @@ -13,6 +13,7 @@ import { DescriptionFormFieldSetComponent } from './components/form-field-set/fo import { DescriptionFormFieldComponent } from './components/form-field/form-field.component'; import { DescriptionFormSectionComponent } from './components/form-section/form-section.component'; import { DescriptionFormComponent } from './description-form.component'; +import { DescriptionFormAnnotationService } from './description-form-annotation.service'; @NgModule({ @@ -39,6 +40,7 @@ import { DescriptionFormComponent } from './description-form.component'; DescriptionFormFieldSetComponent ], providers: [ + DescriptionFormAnnotationService ] }) export class DescriptionFormModule { } diff --git a/dmp-frontend/src/common/model/query-result.ts b/dmp-frontend/src/common/model/query-result.ts index a845cfbfb..aa547d8bb 100644 --- a/dmp-frontend/src/common/model/query-result.ts +++ b/dmp-frontend/src/common/model/query-result.ts @@ -1,5 +1,4 @@ export interface QueryResult { count: number; - countOverride?: number; items: T[]; } \ No newline at end of file