From a2695edbac5ea198146c50c082584d1e1cd82122 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 1 Oct 2019 14:42:25 +0200 Subject: [PATCH 01/22] 65240: Add community/collection logo on create/edit pages --- resources/i18n/en.json5 | 8 ++ .../collection-form.component.ts | 36 ++++- .../create-collection-page.component.html | 2 +- .../edit-collection-page.component.html | 4 +- .../community-form.component.ts | 36 ++++- .../create-community-page.component.html | 2 +- .../edit-community-page.component.html | 3 +- .../my-dspace-new-submission.component.ts | 3 +- src/app/core/data/comcol-data.service.ts | 12 +- src/app/core/shared/hal-endpoint.service.ts | 4 +- .../comcol-form/comcol-form.component.html | 11 ++ .../comcol-form/comcol-form.component.ts | 127 ++++++++++++++++-- .../create-comcol-page.component.ts | 37 ++++- .../edit-comcol-page.component.ts | 33 ++++- .../shared/uploader/uploader-options.model.ts | 2 + .../shared/uploader/uploader.component.html | 6 +- src/app/shared/uploader/uploader.component.ts | 7 +- .../form/submission-form.component.ts | 3 +- 18 files changed, 300 insertions(+), 36 deletions(-) diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index 6570d5bf3a..cc6d49814b 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -130,6 +130,10 @@ "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", "collection.edit.delete": "Delete this collection", "collection.edit.head": "Edit Collection", + "collection.edit.logo.label": "Collection logo", + "collection.edit.logo.notifications.error": "Uploading Collection logo failed. Please verify the content before retrying.", + "collection.edit.logo.notifications.success": "Upload Collection logo successful.", + "collection.edit.logo.upload": "Drop a Collection Logo to upload", "collection.form.abstract": "Short Description", "collection.form.description": "Introductory text (HTML)", "collection.form.errors.title.required": "Please enter a collection name", @@ -153,6 +157,10 @@ "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", "community.edit.delete": "Delete this community", "community.edit.head": "Edit Community", + "community.edit.logo.label": "Community logo", + "community.edit.logo.notifications.error": "Uploading Community logo failed. Please verify the content before retrying.", + "community.edit.logo.notifications.success": "Upload Community logo successful.", + "community.edit.logo.upload": "Drop a Community Logo to upload", "community.form.abstract": "Short Description", "community.form.description": "Introductory text (HTML)", "community.form.errors.title.required": "Please enter a community name", diff --git a/src/app/+collection-page/collection-form/collection-form.component.ts b/src/app/+collection-page/collection-form/collection-form.component.ts index 21b494f41f..e3ca07a2ad 100644 --- a/src/app/+collection-page/collection-form/collection-form.component.ts +++ b/src/app/+collection-page/collection-form/collection-form.component.ts @@ -1,9 +1,14 @@ import { Component, Input } from '@angular/core'; -import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; +import { DynamicFormService, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { Collection } from '../../core/shared/collection.model'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model'; +import { Location } from '@angular/common'; +import { TranslateService } from '@ngx-translate/core'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { CommunityDataService } from '../../core/data/community-data.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Form used for creating and editing collections @@ -19,6 +24,26 @@ export class CollectionFormComponent extends ComColFormComponent { */ @Input() dso: Collection = new Collection(); + /** + * i18n key for the logo's label + */ + protected logoLabelMsg = 'collection.edit.logo.label'; + + /** + * i18n key for the logo's drop message + */ + protected logoDropMsg = 'collection.edit.logo.upload'; + + /** + * i18n key for the logo's upload success message + */ + protected logoSuccessMsg = 'collection.edit.logo.notifications.success'; + + /** + * i18n key for the logo's upload error message + */ + protected logoErrorMsg = 'collection.edit.logo.notifications.error'; + /** * @type {Collection.type} This is a collection-type form */ @@ -65,4 +90,13 @@ export class CollectionFormComponent extends ComColFormComponent { name: 'dc.description.provenance', }), ]; + + public constructor(protected location: Location, + protected formService: DynamicFormService, + protected translate: TranslateService, + protected notificationsService: NotificationsService, + protected authService: AuthService, + protected dsoService: CommunityDataService) { + super(location, formService, translate, notificationsService, authService); + } } diff --git a/src/app/+collection-page/create-collection-page/create-collection-page.component.html b/src/app/+collection-page/create-collection-page/create-collection-page.component.html index b3f4361bc6..dc5c5b186a 100644 --- a/src/app/+collection-page/create-collection-page/create-collection-page.component.html +++ b/src/app/+collection-page/create-collection-page/create-collection-page.component.html @@ -4,5 +4,5 @@

{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}

- + diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html index c389c681ce..b4429d0f7c 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.html @@ -2,7 +2,9 @@
- + {{'collection.edit.delete' | translate}} diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts index 17d601e251..29149f4d01 100644 --- a/src/app/+community-page/community-form/community-form.component.ts +++ b/src/app/+community-page/community-form/community-form.component.ts @@ -1,9 +1,14 @@ import { Component, Input } from '@angular/core'; -import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; +import { DynamicFormService, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { Community } from '../../core/shared/community.model'; import { ResourceType } from '../../core/shared/resource-type'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; +import { Location } from '@angular/common'; +import { TranslateService } from '@ngx-translate/core'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { CommunityDataService } from '../../core/data/community-data.service'; +import { AuthService } from '../../core/auth/auth.service'; /** * Form used for creating and editing communities @@ -19,6 +24,26 @@ export class CommunityFormComponent extends ComColFormComponent { */ @Input() dso: Community = new Community(); + /** + * i18n key for the logo's label + */ + protected logoLabelMsg = 'community.edit.logo.label'; + + /** + * i18n key for the logo's drop message + */ + protected logoDropMsg = 'community.edit.logo.upload'; + + /** + * i18n key for the logo's upload success message + */ + protected logoSuccessMsg = 'community.edit.logo.notifications.success'; + + /** + * i18n key for the logo's upload error message + */ + protected logoErrorMsg = 'community.edit.logo.notifications.error'; + /** * @type {Community.type} This is a community-type form */ @@ -57,4 +82,13 @@ export class CommunityFormComponent extends ComColFormComponent { name: 'dc.description.tableofcontents', }), ]; + + public constructor(protected location: Location, + protected formService: DynamicFormService, + protected translate: TranslateService, + protected notificationsService: NotificationsService, + protected authService: AuthService, + protected dsoService: CommunityDataService) { + super(location, formService, translate, notificationsService, authService); + } } diff --git a/src/app/+community-page/create-community-page/create-community-page.component.html b/src/app/+community-page/create-community-page/create-community-page.component.html index 55a080d2a1..c1b0cf5971 100644 --- a/src/app/+community-page/create-community-page/create-community-page.component.html +++ b/src/app/+community-page/create-community-page/create-community-page.component.html @@ -7,5 +7,5 @@
- + diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.html b/src/app/+community-page/edit-community-page/edit-community-page.component.html index cedb771c14..ba3a3ce32b 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.component.html +++ b/src/app/+community-page/edit-community-page/edit-community-page.component.html @@ -3,7 +3,8 @@
+ [dso]="(dsoRD$ | async)?.payload" + (finishUpload)="navigateToHomePage()"> {{'community.edit.delete' | translate}} diff --git a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts index 938a1ec899..26ed4110b3 100644 --- a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts +++ b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts @@ -34,7 +34,8 @@ export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit { url: '', authToken: null, disableMultipart: false, - itemAlias: null + itemAlias: null, + autoUpload: true }; /** diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index 68eb3e4880..42c414a8a7 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -1,4 +1,4 @@ -import { distinctUntilChanged, filter, map, mergeMap, share, take, tap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, mergeMap, share, switchMap, take, tap } from 'rxjs/operators'; import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs'; import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { NormalizedCommunity } from '../cache/models/normalized-community.model'; @@ -57,4 +57,14 @@ export abstract class ComColDataService extends DataS return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged(), share()); } } + + /** + * Get the endpoint for the community or collection's logo + * @param id The community or collection's ID + */ + public getLogoEndpoint(id: string): Observable { + return this.halService.getEndpoint(this.linkPath).pipe( + switchMap((href: string) => this.halService.getEndpoint('logo', `${href}/${id}`)) + ) + } } diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts index a93d54db64..117cc074ca 100644 --- a/src/app/core/shared/hal-endpoint.service.ts +++ b/src/app/core/shared/hal-endpoint.service.ts @@ -43,8 +43,8 @@ export class HALEndpointService { ); } - public getEndpoint(linkPath: string): Observable { - return this.getEndpointAt(this.getRootHref(), ...linkPath.split('/')); + public getEndpoint(linkPath: string, startHref?: string): Observable { + return this.getEndpointAt(startHref || this.getRootHref(), ...linkPath.split('/')); } /** diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html index 6c67937063..8e1e280b22 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html @@ -1,3 +1,14 @@ +
+ + + +
diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index 8d1d5c1dca..7f59b73c6a 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { Location } from '@angular/common'; import { DynamicFormService, @@ -10,8 +10,16 @@ import { TranslateService } from '@ngx-translate/core'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models'; import { ResourceType } from '../../../core/shared/resource-type'; -import { isNotEmpty } from '../../empty.util'; +import { hasValue, isNotEmpty, isUndefined } from '../../empty.util'; +import { UploaderOptions } from '../../uploader/uploader-options.model'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { Subscription } from 'rxjs/internal/Subscription'; +import { AuthService } from '../../../core/auth/auth.service'; import { Community } from '../../../core/shared/community.model'; +import { Collection } from '../../../core/shared/collection.model'; +import { UploaderComponent } from '../../uploader/uploader.component'; +import { FileUploader } from 'ng2-file-upload'; /** * A form for creating and editing Communities or Collections @@ -21,12 +29,38 @@ import { Community } from '../../../core/shared/community.model'; styleUrls: ['./comcol-form.component.scss'], templateUrl: './comcol-form.component.html' }) -export class ComColFormComponent implements OnInit { +export class ComColFormComponent implements OnInit, OnDestroy { + + /** + * The logo uploader component + */ + @ViewChild(UploaderComponent) uploaderComponent: UploaderComponent; + /** * DSpaceObject that the form represents */ @Input() dso: T; + /** + * i18n key for the logo's label + */ + protected logoLabelMsg: string; + + /** + * i18n key for the logo's drop message + */ + protected logoDropMsg: string; + + /** + * i18n key for the logo's upload success message + */ + protected logoSuccessMsg: string; + + /** + * i18n key for the logo's upload error message + */ + protected logoErrorMsg: string; + /** * Type of DSpaceObject that the form represents */ @@ -53,14 +87,46 @@ export class ComColFormComponent implements OnInit { formGroup: FormGroup; /** - * Emits DSO when the form is submitted - * @type {EventEmitter} + * The uploader configuration options + * @type {UploaderOptions} */ - @Output() submitForm: EventEmitter = new EventEmitter(); + uploadFilesOptions: UploaderOptions = { + url: '', + authToken: null, + disableMultipart: true, + itemAlias: null, + autoUpload: false + }; - public constructor(private location: Location, - private formService: DynamicFormService, - private translate: TranslateService) { + /** + * Emits DSO and Uploader when the form is submitted + */ + @Output() submitForm: EventEmitter<{ + dso: T, + uploader: FileUploader + }> = new EventEmitter(); + + /** + * Fires an event when the logo has finished uploading (with or without errors) + */ + @Output() finishUpload: EventEmitter = new EventEmitter(); + + /** + * Array to track all subscriptions and unsubscribe them onDestroy + * @type {Array} + */ + protected subs: Subscription[] = []; + + /** + * The service used to fetch from or send data to + */ + protected dsoService: ComColDataService; + + public constructor(protected location: Location, + protected formService: DynamicFormService, + protected translate: TranslateService, + protected notificationsService: NotificationsService, + protected authService: AuthService) { } ngOnInit(): void { @@ -76,6 +142,19 @@ export class ComColFormComponent implements OnInit { .subscribe(() => { this.updateFieldTranslations(); }); + + if (hasValue(this.dso.id)) { + this.subs.push( + this.dsoService.getLogoEndpoint(this.dso.id).subscribe((href: string) => { + this.uploadFilesOptions.url = href; + this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + }) + ); + } else { + // Set a placeholder URL to not break the uploader component. This will be replaced once the object is created. + this.uploadFilesOptions.url = 'placeholder'; + this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + } } /** @@ -102,7 +181,10 @@ export class ComColFormComponent implements OnInit { }, type: Community.type }); - this.submitForm.emit(updatedDSO); + this.submitForm.emit({ + dso: updatedDSO, + uploader: this.uploaderComponent.uploader + }); } /** @@ -122,7 +204,32 @@ export class ComColFormComponent implements OnInit { ); } + /** + * The request was successful, display a success notification + */ + public onCompleteItem() { + this.notificationsService.success(null, this.translate.get(this.logoSuccessMsg)); + this.finishUpload.emit(); + } + + /** + * The request was unsuccessful, display an error notification + */ + public onUploadError() { + this.notificationsService.error(null, this.translate.get(this.logoErrorMsg)); + this.finishUpload.emit(); + } + onCancel() { this.location.back(); } + + /** + * Unsubscribe from open subscriptions + */ + ngOnDestroy(): void { + this.subs + .filter((subscription) => hasValue(subscription)) + .forEach((subscription) => subscription.unsubscribe()); + } } diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts index e07f2a5a0a..baa05ac5e7 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -5,11 +5,12 @@ import { Observable } from 'rxjs'; import { RouteService } from '../../../core/services/route.service'; import { Router } from '@angular/router'; import { RemoteData } from '../../../core/data/remote-data'; -import { isNotEmpty, isNotUndefined } from '../../empty.util'; +import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util'; import { take } from 'rxjs/operators'; import { getSucceededRemoteData } from '../../../core/shared/operators'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { DataService } from '../../../core/data/data.service'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; /** * Component representing the create page for communities and collections @@ -34,8 +35,13 @@ export class CreateComColPageComponent implements */ public parentRD$: Observable>; + /** + * The UUID of the newly created object + */ + private newUUID: string; + public constructor( - protected dsoDataService: DataService, + protected dsoDataService: ComColDataService, protected parentDataService: CommunityDataService, protected routeService: RouteService, protected router: Router @@ -53,20 +59,39 @@ export class CreateComColPageComponent implements } /** - * @param {TDomain} dso The updated version of the DSO * Creates a new DSO based on the submitted user data and navigates to the new object's home page + * @param event The event returned by the community/collection form. Contains the new dso and logo uploader */ - onSubmit(dso: TDomain) { + onSubmit(event) { + const dso = event.dso; + const uploader = event.uploader; + this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => { this.dsoDataService.create(dso, uuid) .pipe(getSucceededRemoteData()) .subscribe((dsoRD: RemoteData) => { if (isNotUndefined(dsoRD)) { - const newUUID = dsoRD.payload.uuid; - this.router.navigate([this.frontendURL + newUUID]); + this.newUUID = dsoRD.payload.uuid; + if (uploader.queue.length > 0) { + this.dsoDataService.getLogoEndpoint(this.newUUID).pipe(take(1)).subscribe((href: string) => { + uploader.options.url = href; + uploader.uploadAll(); + }); + } else { + this.navigateToNewPage(); + } } }); }); } + /** + * Navigate to the page of the newly created object + */ + navigateToNewPage() { + if (hasValue(this.newUUID)) { + this.router.navigate([this.frontendURL + this.newUUID]); + } + } + } diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts index 24181b5e61..ec4a7fd745 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts @@ -3,10 +3,11 @@ import { Observable } from 'rxjs'; import { ActivatedRoute, Router } from '@angular/router'; import { RemoteData } from '../../../core/data/remote-data'; import { isNotUndefined } from '../../empty.util'; -import { first, map } from 'rxjs/operators'; +import { first, map, take } from 'rxjs/operators'; import { getSucceededRemoteData } from '../../../core/shared/operators'; import { DataService } from '../../../core/data/data.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; /** * Component representing the edit page for communities and collections @@ -26,7 +27,7 @@ export class EditComColPageComponent implements On public dsoRD$: Observable>; public constructor( - protected dsoDataService: DataService, + protected dsoDataService: ComColDataService, protected router: Router, protected route: ActivatedRoute ) { @@ -37,17 +38,39 @@ export class EditComColPageComponent implements On } /** - * @param {TDomain} dso The updated version of the DSO * Updates an existing DSO based on the submitted user data and navigates to the edited object's home page + * @param event The event returned by the community/collection form. Contains the new dso and logo uploader */ - onSubmit(dso: TDomain) { + onSubmit(event) { + const dso = event.dso; + const uploader = event.uploader; + this.dsoDataService.update(dso) .pipe(getSucceededRemoteData()) .subscribe((dsoRD: RemoteData) => { if (isNotUndefined(dsoRD)) { const newUUID = dsoRD.payload.uuid; - this.router.navigate([this.frontendURL + newUUID]); + if (uploader.queue.length > 0) { + this.dsoDataService.getLogoEndpoint(newUUID).pipe(take(1)).subscribe((href: string) => { + uploader.options.url = href; + uploader.uploadAll(); + }); + } else { + this.router.navigate([this.frontendURL + newUUID]); + } } }); } + + /** + * Navigate to the home page of the object + */ + navigateToHomePage() { + this.dsoRD$.pipe( + getSucceededRemoteData(), + take(1) + ).subscribe((dsoRD: RemoteData) => { + this.router.navigate([this.frontendURL + dsoRD.payload.id]); + }); + } } diff --git a/src/app/shared/uploader/uploader-options.model.ts b/src/app/shared/uploader/uploader-options.model.ts index 0bd6412b17..fa77a36d11 100644 --- a/src/app/shared/uploader/uploader-options.model.ts +++ b/src/app/shared/uploader/uploader-options.model.ts @@ -10,4 +10,6 @@ export class UploaderOptions { disableMultipart = false; itemAlias: string; + + autoUpload = true; } diff --git a/src/app/shared/uploader/uploader.component.html b/src/app/shared/uploader/uploader.component.html index 9d994313c6..a3181be21c 100644 --- a/src/app/shared/uploader/uploader.component.html +++ b/src/app/shared/uploader/uploader.component.html @@ -29,13 +29,15 @@
- {{'uploader.queue-length' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }} + + {{'uploader.queue-length' | translate}}: {{ uploader?.queue?.length }} | {{ uploader?.queue[0]?.file.name }} +
- {{ uploader.progress }}% + {{ uploader.progress }}% {{'uploader.processing' | translate}}...
diff --git a/src/app/shared/uploader/uploader.component.ts b/src/app/shared/uploader/uploader.component.ts index ad52f4a93f..794b5cb4b3 100644 --- a/src/app/shared/uploader/uploader.component.ts +++ b/src/app/shared/uploader/uploader.component.ts @@ -95,7 +95,7 @@ export class UploaderComponent { disableMultipart: this.uploadFilesOptions.disableMultipart, itemAlias: this.uploadFilesOptions.itemAlias, removeAfterUpload: true, - autoUpload: true + autoUpload: this.uploadFilesOptions.autoUpload }); if (isUndefined(this.enableDragOverDocument)) { @@ -117,7 +117,10 @@ export class UploaderComponent { if (isUndefined(this.onBeforeUpload)) { this.onBeforeUpload = () => {return}; } - this.uploader.onBeforeUploadItem = () => { + this.uploader.onBeforeUploadItem = (item) => { + if (item.url !== this.uploader.options.url) { + item.url = this.uploader.options.url; + } this.onBeforeUpload(); this.isOverDocumentDropZone = observableOf(false); diff --git a/src/app/submission/form/submission-form.component.ts b/src/app/submission/form/submission-form.component.ts index b592972839..7ed7bec04b 100644 --- a/src/app/submission/form/submission-form.component.ts +++ b/src/app/submission/form/submission-form.component.ts @@ -81,7 +81,8 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy { url: '', authToken: null, disableMultipart: false, - itemAlias: null + itemAlias: null, + autoUpload: true }; /** From ed91e96d4282163a373d336572af3c52a1475b04 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 1 Oct 2019 15:26:09 +0200 Subject: [PATCH 02/22] 65240: Message cleanup --- .../collection-form.component.ts | 20 ---------------- .../community-form.component.ts | 20 ---------------- .../comcol-form/comcol-form.component.html | 6 ++--- .../comcol-form/comcol-form.component.ts | 24 ++----------------- 4 files changed, 5 insertions(+), 65 deletions(-) diff --git a/src/app/+collection-page/collection-form/collection-form.component.ts b/src/app/+collection-page/collection-form/collection-form.component.ts index e3ca07a2ad..d91d9fc1fb 100644 --- a/src/app/+collection-page/collection-form/collection-form.component.ts +++ b/src/app/+collection-page/collection-form/collection-form.component.ts @@ -24,26 +24,6 @@ export class CollectionFormComponent extends ComColFormComponent { */ @Input() dso: Collection = new Collection(); - /** - * i18n key for the logo's label - */ - protected logoLabelMsg = 'collection.edit.logo.label'; - - /** - * i18n key for the logo's drop message - */ - protected logoDropMsg = 'collection.edit.logo.upload'; - - /** - * i18n key for the logo's upload success message - */ - protected logoSuccessMsg = 'collection.edit.logo.notifications.success'; - - /** - * i18n key for the logo's upload error message - */ - protected logoErrorMsg = 'collection.edit.logo.notifications.error'; - /** * @type {Collection.type} This is a collection-type form */ diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts index 29149f4d01..fc1e77c445 100644 --- a/src/app/+community-page/community-form/community-form.component.ts +++ b/src/app/+community-page/community-form/community-form.component.ts @@ -24,26 +24,6 @@ export class CommunityFormComponent extends ComColFormComponent { */ @Input() dso: Community = new Community(); - /** - * i18n key for the logo's label - */ - protected logoLabelMsg = 'community.edit.logo.label'; - - /** - * i18n key for the logo's drop message - */ - protected logoDropMsg = 'community.edit.logo.upload'; - - /** - * i18n key for the logo's upload success message - */ - protected logoSuccessMsg = 'community.edit.logo.notifications.success'; - - /** - * i18n key for the logo's upload error message - */ - protected logoErrorMsg = 'community.edit.logo.notifications.error'; - /** * @type {Community.type} This is a community-type form */ diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html index 8e1e280b22..fff1908823 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html @@ -1,9 +1,9 @@
- + implements OnInit, OnDe */ @Input() dso: T; - /** - * i18n key for the logo's label - */ - protected logoLabelMsg: string; - - /** - * i18n key for the logo's drop message - */ - protected logoDropMsg: string; - - /** - * i18n key for the logo's upload success message - */ - protected logoSuccessMsg: string; - - /** - * i18n key for the logo's upload error message - */ - protected logoErrorMsg: string; - /** * Type of DSpaceObject that the form represents */ @@ -208,7 +188,7 @@ export class ComColFormComponent implements OnInit, OnDe * The request was successful, display a success notification */ public onCompleteItem() { - this.notificationsService.success(null, this.translate.get(this.logoSuccessMsg)); + this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.success')); this.finishUpload.emit(); } @@ -216,7 +196,7 @@ export class ComColFormComponent implements OnInit, OnDe * The request was unsuccessful, display an error notification */ public onUploadError() { - this.notificationsService.error(null, this.translate.get(this.logoErrorMsg)); + this.notificationsService.error(null, this.translate.get(this.type.value + '.edit.logo.notifications.error')); this.finishUpload.emit(); } From ecef1b35d15c2734e8e8521005d75714490b4477 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 1 Oct 2019 16:12:08 +0200 Subject: [PATCH 03/22] 65240: Delete logo button and service method --- resources/i18n/en.json5 | 14 +++++--- src/app/core/data/comcol-data.service.ts | 18 ++++++++-- .../comcol-form/comcol-form.component.html | 11 ++++-- .../comcol-form/comcol-form.component.ts | 36 +++++++++++++++++-- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index cc6d49814b..cf155c0841 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -131,8 +131,11 @@ "collection.edit.delete": "Delete this collection", "collection.edit.head": "Edit Collection", "collection.edit.logo.label": "Collection logo", - "collection.edit.logo.notifications.error": "Uploading Collection logo failed. Please verify the content before retrying.", - "collection.edit.logo.notifications.success": "Upload Collection logo successful.", + "collection.edit.logo.notifications.add.error": "Uploading Collection logo failed. Please verify the content before retrying.", + "collection.edit.logo.notifications.add.success": "Upload Collection logo successful.", + "collection.edit.logo.notifications.delete.success.title": "Logo deleted", + "collection.edit.logo.notifications.delete.success.content": "Successfully deleted the collection's logo", + "collection.edit.logo.notifications.delete.error.title": "Error deleting logo", "collection.edit.logo.upload": "Drop a Collection Logo to upload", "collection.form.abstract": "Short Description", "collection.form.description": "Introductory text (HTML)", @@ -158,8 +161,11 @@ "community.edit.delete": "Delete this community", "community.edit.head": "Edit Community", "community.edit.logo.label": "Community logo", - "community.edit.logo.notifications.error": "Uploading Community logo failed. Please verify the content before retrying.", - "community.edit.logo.notifications.success": "Upload Community logo successful.", + "community.edit.logo.notifications.add.error": "Uploading Community logo failed. Please verify the content before retrying.", + "community.edit.logo.notifications.add.success": "Upload Community logo successful.", + "community.edit.logo.notifications.delete.success.title": "Logo deleted", + "community.edit.logo.notifications.delete.success.content": "Successfully deleted the community's logo", + "community.edit.logo.notifications.delete.error.title": "Error deleting logo", "community.edit.logo.upload": "Drop a Community Logo to upload", "community.form.abstract": "Short Description", "community.form.description": "Introductory text (HTML)", diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index 42c414a8a7..ba17d04d76 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -6,10 +6,11 @@ import { ObjectCacheService } from '../cache/object-cache.service'; import { CommunityDataService } from './community-data.service'; import { DataService } from './data.service'; -import { FindAllOptions, FindByIDRequest } from './request.models'; +import { DeleteRequest, FindAllOptions, FindByIDRequest, RestRequest } from './request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { getResponseFromEntry } from '../shared/operators'; +import { configureRequest, getResponseFromEntry } from '../shared/operators'; import { CacheableObject } from '../cache/object-cache.reducer'; +import { RestResponse } from '../cache/response.models'; export abstract class ComColDataService extends DataService { protected abstract cds: CommunityDataService; @@ -67,4 +68,17 @@ export abstract class ComColDataService extends DataS switchMap((href: string) => this.halService.getEndpoint('logo', `${href}/${id}`)) ) } + + /** + * Delete the logo from the community or collection + * @param id The community or collection's ID + */ + public deleteLogo(id: string): Observable { + return this.getLogoEndpoint(id).pipe( + map((href: string) => new DeleteRequest(this.requestService.generateRequestId(), href)), + configureRequest(this.requestService), + switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)), + getResponseFromEntry() + ); + } } diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html index fff1908823..b65e6e8f80 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html @@ -1,7 +1,14 @@
- - + +
+ +
+ + implements OnInit, OnDe */ @Output() finishUpload: EventEmitter = new EventEmitter(); + /** + * Observable keeping track whether or not the uploader has finished initializing + * Used to start rendering the uploader component + */ + private initializedUploaderOptions = new BehaviorSubject(false); + /** * Array to track all subscriptions and unsubscribe them onDestroy * @type {Array} @@ -128,12 +136,14 @@ export class ComColFormComponent implements OnInit, OnDe this.dsoService.getLogoEndpoint(this.dso.id).subscribe((href: string) => { this.uploadFilesOptions.url = href; this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + this.initializedUploaderOptions.next(true); }) ); } else { // Set a placeholder URL to not break the uploader component. This will be replaced once the object is created. this.uploadFilesOptions.url = 'placeholder'; this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + this.initializedUploaderOptions.next(true); } } @@ -184,11 +194,33 @@ export class ComColFormComponent implements OnInit, OnDe ); } + /** + * Send out a delete request to remove the logo from the community/collection and display notifications + */ + deleteLogo() { + if (hasValue(this.dso.id)) { + this.dsoService.deleteLogo(this.dso.id).subscribe((response: RestResponse) => { + if (response.isSuccessful) { + this.notificationsService.success( + this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.title'), + this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.content') + ); + } else { + const errorResponse = response as ErrorResponse; + this.notificationsService.error( + this.translate.get(this.type.value + '.edit.logo.notifications.delete.error.title'), + errorResponse.errorMessage + ); + } + }); + } + } + /** * The request was successful, display a success notification */ public onCompleteItem() { - this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.success')); + this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.success')); this.finishUpload.emit(); } @@ -196,7 +228,7 @@ export class ComColFormComponent implements OnInit, OnDe * The request was unsuccessful, display an error notification */ public onUploadError() { - this.notificationsService.error(null, this.translate.get(this.type.value + '.edit.logo.notifications.error')); + this.notificationsService.error(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.error')); this.finishUpload.emit(); } From eade3e7d375fa826569b4e4cd344870b2213fd0a Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 1 Oct 2019 16:53:21 +0200 Subject: [PATCH 04/22] 65240: Set uploader method to PUT if object already contains a logo --- .../my-dspace-new-submission.component.ts | 8 +---- .../comcol-form/comcol-form.component.ts | 30 ++++++++++++------- .../shared/uploader/uploader-options.model.ts | 11 ++++++- src/app/shared/uploader/uploader.component.ts | 3 +- .../form/submission-form.component.ts | 8 +---- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts index 26ed4110b3..342e3f44e3 100644 --- a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts +++ b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts @@ -30,13 +30,7 @@ export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit { /** * The UploaderOptions object */ - public uploadFilesOptions: UploaderOptions = { - url: '', - authToken: null, - disableMultipart: false, - itemAlias: null, - autoUpload: true - }; + public uploadFilesOptions: UploaderOptions = new UploaderOptions(); /** * Subscription to unsubscribe from diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index 06c507b3ea..6e8b04e589 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -1,16 +1,13 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { Location } from '@angular/common'; -import { - DynamicFormService, - DynamicInputModel -} from '@ng-dynamic-forms/core'; +import { DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { FormGroup } from '@angular/forms'; import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { TranslateService } from '@ngx-translate/core'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models'; import { ResourceType } from '../../../core/shared/resource-type'; -import { hasValue, isNotEmpty, isUndefined } from '../../empty.util'; +import { hasValue, isNotEmpty } from '../../empty.util'; import { UploaderOptions } from '../../uploader/uploader-options.model'; import { NotificationsService } from '../../notifications/notifications.service'; import { ComColDataService } from '../../../core/data/comcol-data.service'; @@ -22,6 +19,10 @@ import { UploaderComponent } from '../../uploader/uploader.component'; import { FileUploader } from 'ng2-file-upload'; import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Bitstream } from '../../../core/shared/bitstream.model'; +import { combineLatest as observableCombineLatest } from 'rxjs'; +import { RestRequestMethod } from '../../../core/data/rest-request-method'; /** * A form for creating and editing Communities or Collections @@ -72,13 +73,10 @@ export class ComColFormComponent implements OnInit, OnDe * The uploader configuration options * @type {UploaderOptions} */ - uploadFilesOptions: UploaderOptions = { - url: '', - authToken: null, + uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), { disableMultipart: true, - itemAlias: null, autoUpload: false - }; + }); /** * Emits DSO and Uploader when the form is submitted @@ -133,9 +131,16 @@ export class ComColFormComponent implements OnInit, OnDe if (hasValue(this.dso.id)) { this.subs.push( - this.dsoService.getLogoEndpoint(this.dso.id).subscribe((href: string) => { + observableCombineLatest( + this.dsoService.getLogoEndpoint(this.dso.id), + (this.dso as any).logo + ).subscribe(([href, logoRD]: [string, RemoteData]) => { this.uploadFilesOptions.url = href; this.uploadFilesOptions.authToken = this.authService.buildAuthHeader(); + // If the object already contains a logo, send out a PUT request instead of POST for setting a new logo + if (hasValue(logoRD.payload)) { + this.uploadFilesOptions.method = RestRequestMethod.PUT; + } this.initializedUploaderOptions.next(true); }) ); @@ -232,6 +237,9 @@ export class ComColFormComponent implements OnInit, OnDe this.finishUpload.emit(); } + /** + * Cancel the form and return to the previous page + */ onCancel() { this.location.back(); } diff --git a/src/app/shared/uploader/uploader-options.model.ts b/src/app/shared/uploader/uploader-options.model.ts index fa77a36d11..f195b0930e 100644 --- a/src/app/shared/uploader/uploader-options.model.ts +++ b/src/app/shared/uploader/uploader-options.model.ts @@ -1,3 +1,4 @@ +import { RestRequestMethod } from '../../core/data/rest-request-method'; export class UploaderOptions { /** @@ -9,7 +10,15 @@ export class UploaderOptions { disableMultipart = false; - itemAlias: string; + itemAlias: string = null; + /** + * Automatically send out an upload request when adding files + */ autoUpload = true; + + /** + * The request method to use for the file upload request + */ + method: RestRequestMethod = RestRequestMethod.POST; } diff --git a/src/app/shared/uploader/uploader.component.ts b/src/app/shared/uploader/uploader.component.ts index 794b5cb4b3..935d196d08 100644 --- a/src/app/shared/uploader/uploader.component.ts +++ b/src/app/shared/uploader/uploader.component.ts @@ -95,7 +95,8 @@ export class UploaderComponent { disableMultipart: this.uploadFilesOptions.disableMultipart, itemAlias: this.uploadFilesOptions.itemAlias, removeAfterUpload: true, - autoUpload: this.uploadFilesOptions.autoUpload + autoUpload: this.uploadFilesOptions.autoUpload, + method: this.uploadFilesOptions.method }); if (isUndefined(this.enableDragOverDocument)) { diff --git a/src/app/submission/form/submission-form.component.ts b/src/app/submission/form/submission-form.component.ts index 7ed7bec04b..a11ad43db3 100644 --- a/src/app/submission/form/submission-form.component.ts +++ b/src/app/submission/form/submission-form.component.ts @@ -77,13 +77,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy { * The uploader configuration options * @type {UploaderOptions} */ - public uploadFilesOptions: UploaderOptions = { - url: '', - authToken: null, - disableMultipart: false, - itemAlias: null, - autoUpload: true - }; + public uploadFilesOptions: UploaderOptions = new UploaderOptions(); /** * A boolean representing if component is active From f3a032470dac20e1ca8f9f9eefb5541247877e27 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 2 Oct 2019 10:19:21 +0200 Subject: [PATCH 05/22] 65240: Fixed current tests --- .../comcol-form/comcol-form.component.spec.ts | 41 ++++++++++++------- .../create-comcol-page.component.spec.ts | 24 +++++++---- .../edit-comcol-page.component.spec.ts | 24 +++++++---- src/app/shared/mocks/mock-auth.service.ts | 3 ++ 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 1b44970402..c896614ca9 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -7,10 +7,14 @@ import { DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { FormControl, FormGroup } from '@angular/forms'; import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { Community } from '../../../core/shared/community.model'; -import { ResourceType } from '../../../core/shared/resource-type'; import { ComColFormComponent } from './comcol-form.component'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { hasValue } from '../../empty.util'; +import { VarDirective } from '../../utils/var.directive'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; +import { AuthService } from '../../../core/auth/auth.service'; +import { AuthServiceMock } from '../../mocks/mock-auth.service'; describe('ComColFormComponent', () => { let comp: ComColFormComponent; @@ -56,10 +60,12 @@ describe('ComColFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule], - declarations: [ComColFormComponent], + declarations: [ComColFormComponent, VarDirective], providers: [ { provide: Location, useValue: locationStub }, - { provide: DynamicFormService, useValue: formServiceStub } + { provide: DynamicFormService, useValue: formServiceStub }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: AuthService, useValue: new AuthServiceMock() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -70,6 +76,10 @@ describe('ComColFormComponent', () => { comp = fixture.componentInstance; comp.formModel = []; comp.dso = new Community(); + (comp as any).type = Community.type; + comp.uploaderComponent = Object.assign({ + uploader: {} + }); fixture.detectChanges(); location = (comp as any).location; }); @@ -94,18 +104,21 @@ describe('ComColFormComponent', () => { comp.onSubmit(); expect(comp.submitForm.emit).toHaveBeenCalledWith( - Object.assign( - {}, - new Community(), - { - metadata: { - ...newTitleMD, - ...randomMD, - ...abstractMD + { + dso: Object.assign( + {}, + new Community(), + { + metadata: { + ...newTitleMD, + ...randomMD, + ...abstractMD + }, + type: Community.type }, - type: Community.type - }, - ) + ), + uploader: {} + } ); }) }); diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts index 6ad2e5b5e1..bc468fada1 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts @@ -16,6 +16,7 @@ import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../testing/utils'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; describe('CreateComColPageComponent', () => { let comp: CreateComColPageComponent; @@ -74,7 +75,7 @@ describe('CreateComColPageComponent', () => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule], providers: [ - { provide: DataService, useValue: communityDataServiceStub }, + { provide: ComColDataService, useValue: communityDataServiceStub }, { provide: CommunityDataService, useValue: communityDataServiceStub }, { provide: RouteService, useValue: routeServiceStub }, { provide: Router, useValue: routerStub }, @@ -96,12 +97,21 @@ describe('CreateComColPageComponent', () => { describe('onSubmit', () => { let data; beforeEach(() => { - data = Object.assign(new Community(), { - metadata: [{ - key: 'dc.title', - value: 'test' - }] - }); + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [], + uploadAll: {} + } + }; }); it('should navigate when successful', () => { spyOn(router, 'navigate'); diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts index 03f751599f..d9fb59fe9e 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts @@ -15,6 +15,7 @@ import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../testing/utils'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; describe('EditComColPageComponent', () => { let comp: EditComColPageComponent; @@ -65,7 +66,7 @@ describe('EditComColPageComponent', () => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule], providers: [ - { provide: DataService, useValue: communityDataServiceStub }, + { provide: ComColDataService, useValue: communityDataServiceStub }, { provide: Router, useValue: routerStub }, { provide: ActivatedRoute, useValue: routeStub }, ], @@ -84,12 +85,21 @@ describe('EditComColPageComponent', () => { describe('onSubmit', () => { let data; beforeEach(() => { - data = Object.assign(new Community(), { - metadata: [{ - key: 'dc.title', - value: 'test' - }] - }); + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [], + uploadAll: {} + } + } }); it('should navigate when successful', () => { spyOn(router, 'navigate'); diff --git a/src/app/shared/mocks/mock-auth.service.ts b/src/app/shared/mocks/mock-auth.service.ts index 6258e4aa21..a168ffd8e5 100644 --- a/src/app/shared/mocks/mock-auth.service.ts +++ b/src/app/shared/mocks/mock-auth.service.ts @@ -3,4 +3,7 @@ export class AuthServiceMock { public checksAuthenticationToken() { return } + public buildAuthHeader() { + return 'auth-header'; + } } From 8a475f2523e482dc80c9a96ec11c3d5d3c5c73fa Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 2 Oct 2019 13:04:15 +0200 Subject: [PATCH 06/22] 65240: comcol form logo tests --- .../comcol-form/comcol-form.component.spec.ts | 217 ++++++++++++++---- .../create-comcol-page.component.spec.ts | 113 ++++++--- .../edit-comcol-page.component.spec.ts | 125 +++++++--- 3 files changed, 344 insertions(+), 111 deletions(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index c896614ca9..455e2ef4e0 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -15,6 +15,11 @@ import { NotificationsService } from '../../notifications/notifications.service' import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; import { AuthService } from '../../../core/auth/auth.service'; import { AuthServiceMock } from '../../mocks/mock-auth.service'; +import { of as observableOf } from 'rxjs'; +import { RemoteData } from '../../../core/data/remote-data'; +import { RestRequestMethod } from '../../../core/data/rest-request-method'; +import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; +import { RequestError } from '../../../core/data/request.models'; describe('ComColFormComponent', () => { let comp: ComColFormComponent; @@ -53,6 +58,13 @@ describe('ComColFormComponent', () => { }) ]; + const logoEndpoint = 'rest/api/logo/endpoint'; + const dsoService = Object.assign({ + getLogoEndpoint: () => observableOf(logoEndpoint), + deleteLogo: () => observableOf({}) + }); + const notificationsService = new NotificationsServiceStub(); + /* tslint:disable:no-empty */ const locationStub = jasmine.createSpyObj('location', ['back']); /* tslint:enable:no-empty */ @@ -64,69 +76,174 @@ describe('ComColFormComponent', () => { providers: [ { provide: Location, useValue: locationStub }, { provide: DynamicFormService, useValue: formServiceStub }, - { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: NotificationsService, useValue: notificationsService }, { provide: AuthService, useValue: new AuthServiceMock() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); })); - beforeEach(() => { + describe('when the dso doesn\'t contain an ID (newly created)', () => { + beforeEach(() => { + initComponent(new Community()); + }); + + it('should initialize the uploadFilesOptions with a placeholder url', () => { + expect(comp.uploadFilesOptions.url.length).toBeGreaterThan(0); + }); + + describe('onSubmit', () => { + beforeEach(() => { + spyOn(comp.submitForm, 'emit'); + comp.formModel = formModel; + }); + + it('should emit the new version of the community', () => { + comp.dso = Object.assign( + new Community(), + { + metadata: { + ...titleMD, + ...randomMD + } + } + ); + + comp.onSubmit(); + + expect(comp.submitForm.emit).toHaveBeenCalledWith( + { + dso: Object.assign( + {}, + new Community(), + { + metadata: { + ...newTitleMD, + ...randomMD, + ...abstractMD + }, + type: Community.type + }, + ), + uploader: {} + } + ); + }) + }); + + describe('onCancel', () => { + it('should call the back method on the Location service', () => { + comp.onCancel(); + expect(locationStub.back).toHaveBeenCalled(); + }); + }); + + describe('onCompleteItem', () => { + beforeEach(() => { + spyOn(comp.finishUpload, 'emit'); + comp.onCompleteItem(); + }); + + it('should show a success notification', () => { + expect(notificationsService.success).toHaveBeenCalled(); + }); + + it('should emit finishUpload', () => { + expect(comp.finishUpload.emit).toHaveBeenCalled(); + }); + }); + + describe('onUploadError', () => { + beforeEach(() => { + spyOn(comp.finishUpload, 'emit'); + comp.onUploadError(); + }); + + it('should show an error notification', () => { + expect(notificationsService.error).toHaveBeenCalled(); + }); + + it('should emit finishUpload', () => { + expect(comp.finishUpload.emit).toHaveBeenCalled(); + }); + }); + }); + + describe('when the dso contains an ID (being edited)', () => { + describe('and the dso doesn\'t contain a logo', () => { + beforeEach(() => { + initComponent(Object.assign(new Community(), { + id: 'community-id', + logo: observableOf(new RemoteData(false, false, true, null, undefined)) + })); + }); + + it('should initialize the uploadFilesOptions with the logo\'s endpoint url', () => { + expect(comp.uploadFilesOptions.url).toEqual(logoEndpoint); + }); + + it('should initialize the uploadFilesOptions with a POST method', () => { + expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.POST); + }); + }); + + describe('and the dso contains a logo', () => { + beforeEach(() => { + initComponent(Object.assign(new Community(), { + id: 'community-id', + logo: observableOf(new RemoteData(false, false, true, null, {})) + })); + }); + + it('should initialize the uploadFilesOptions with the logo\'s endpoint url', () => { + expect(comp.uploadFilesOptions.url).toEqual(logoEndpoint); + }); + + it('should initialize the uploadFilesOptions with a PUT method', () => { + expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.PUT); + }); + + describe('deleteLogo', () => { + describe('when dsoService.deleteLogo returns a successful response', () => { + const response = new RestResponse(true, 200, 'OK'); + + beforeEach(() => { + spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response)); + comp.deleteLogo(); + }); + + it('should display a success notification', () => { + expect(notificationsService.success).toHaveBeenCalled(); + }); + }); + + describe('when dsoService.deleteLogo returns an error response', () => { + const response = new ErrorResponse(new RequestError('errorMessage')); + + beforeEach(() => { + spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response)); + comp.deleteLogo(); + }); + + it('should display an error notification', () => { + expect(notificationsService.error).toHaveBeenCalled(); + }); + }); + }); + }); + }); + + function initComponent(dso: Community) { fixture = TestBed.createComponent(ComColFormComponent); comp = fixture.componentInstance; comp.formModel = []; - comp.dso = new Community(); + comp.dso = dso; (comp as any).type = Community.type; comp.uploaderComponent = Object.assign({ uploader: {} }); + (comp as any).dsoService = dsoService; fixture.detectChanges(); location = (comp as any).location; - }); - - describe('onSubmit', () => { - beforeEach(() => { - spyOn(comp.submitForm, 'emit'); - comp.formModel = formModel; - }); - - it('should emit the new version of the community', () => { - comp.dso = Object.assign( - new Community(), - { - metadata: { - ...titleMD, - ...randomMD - } - } - ); - - comp.onSubmit(); - - expect(comp.submitForm.emit).toHaveBeenCalledWith( - { - dso: Object.assign( - {}, - new Community(), - { - metadata: { - ...newTitleMD, - ...randomMD, - ...abstractMD - }, - type: Community.type - }, - ), - uploader: {} - } - ); - }) - }); - - describe('onCancel', () => { - it('should call the back method on the Location service', () => { - comp.onCancel(); - expect(locationStub.back).toHaveBeenCalled(); - }); - }); + } }); diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts index bc468fada1..99aac6757e 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts @@ -11,7 +11,6 @@ import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { CreateComColPageComponent } from './create-comcol-page.component'; -import { DataService } from '../../../core/data/data.service'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ @@ -32,6 +31,8 @@ describe('CreateComColPageComponent', () => { let routeServiceStub; let routerStub; + const logoEndpoint = 'rest/api/logo/endpoint'; + function initializeVars() { community = Object.assign(new Community(), { uuid: 'a20da287-e174-466a-9926-f66b9300d347', @@ -57,8 +58,8 @@ describe('CreateComColPageComponent', () => { value: community.name }] })), - create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity) - + create: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity), + getLogoEndpoint: () => observableOf(logoEndpoint) }; routeServiceStub = { @@ -96,36 +97,86 @@ describe('CreateComColPageComponent', () => { describe('onSubmit', () => { let data; - beforeEach(() => { - data = { - dso: Object.assign(new Community(), { - metadata: [{ - key: 'dc.title', - value: 'test' - }] - }), - uploader: { - options: { - url: '' - }, - queue: [], - uploadAll: {} - } - }; - }); - it('should navigate when successful', () => { - spyOn(router, 'navigate'); - comp.onSubmit(data); - fixture.detectChanges(); - expect(router.navigate).toHaveBeenCalled(); + + describe('with an empty queue in the uploader', () => { + beforeEach(() => { + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [], + /* tslint:disable:no-empty */ + uploadAll: () => {} + /* tslint:enable:no-empty */ + } + }; + }); + + it('should navigate when successful', () => { + spyOn(router, 'navigate'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).toHaveBeenCalled(); + }); + + it('should not navigate on failure', () => { + spyOn(router, 'navigate'); + spyOn(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity)); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).not.toHaveBeenCalled(); + }); }); - it('should not navigate on failure', () => { - spyOn(router, 'navigate'); - spyOn(dsoDataService, 'create').and.returnValue(createFailedRemoteDataObject$(newCommunity)); - comp.onSubmit(data); - fixture.detectChanges(); - expect(router.navigate).not.toHaveBeenCalled(); + describe('with at least one item in the uploader\'s queue', () => { + beforeEach(() => { + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [ + {} + ], + /* tslint:disable:no-empty */ + uploadAll: () => {} + /* tslint:enable:no-empty */ + } + }; + }); + + it('should not navigate', () => { + spyOn(router, 'navigate'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).not.toHaveBeenCalled(); + }); + + it('should set the uploader\'s url to the logo\'s endpoint', () => { + comp.onSubmit(data); + fixture.detectChanges(); + expect(data.uploader.options.url).toEqual(logoEndpoint); + }); + + it('should call the uploader\'s uploadAll', () => { + spyOn(data.uploader, 'uploadAll'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(data.uploader.uploadAll).toHaveBeenCalled(); + }); }); }); }); diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts index d9fb59fe9e..2a52049df5 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts @@ -10,12 +10,12 @@ import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { EditComColPageComponent } from './edit-comcol-page.component'; -import { DataService } from '../../../core/data/data.service'; import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../testing/utils'; import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { RemoteData } from '../../../core/data/remote-data'; describe('EditComColPageComponent', () => { let comp: EditComColPageComponent; @@ -29,6 +29,8 @@ describe('EditComColPageComponent', () => { let routerStub; let routeStub; + const logoEndpoint = 'rest/api/logo/endpoint'; + function initializeVars() { community = Object.assign(new Community(), { uuid: 'a20da287-e174-466a-9926-f66b9300d347', @@ -47,8 +49,8 @@ describe('EditComColPageComponent', () => { }); communityDataServiceStub = { - update: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity) - + update: (com, uuid?) => createSuccessfulRemoteDataObject$(newCommunity), + getLogoEndpoint: () => observableOf(logoEndpoint) }; routerStub = { @@ -56,7 +58,9 @@ describe('EditComColPageComponent', () => { }; routeStub = { - data: observableOf(community) + data: observableOf({ + dso: new RemoteData(false, false, true, null, community) + }) }; } @@ -84,36 +88,97 @@ describe('EditComColPageComponent', () => { describe('onSubmit', () => { let data; - beforeEach(() => { - data = { - dso: Object.assign(new Community(), { - metadata: [{ - key: 'dc.title', - value: 'test' - }] - }), - uploader: { - options: { - url: '' - }, - queue: [], - uploadAll: {} + + describe('with an empty queue in the uploader', () => { + beforeEach(() => { + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [], + /* tslint:disable:no-empty */ + uploadAll: () => {} + /* tslint:enable:no-empty */ + } } - } - }); - it('should navigate when successful', () => { - spyOn(router, 'navigate'); - comp.onSubmit(data); - fixture.detectChanges(); - expect(router.navigate).toHaveBeenCalled(); + }); + + it('should navigate when successful', () => { + spyOn(router, 'navigate'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).toHaveBeenCalled(); + }); + + it('should not navigate on failure', () => { + spyOn(router, 'navigate'); + spyOn(dsoDataService, 'update').and.returnValue(createFailedRemoteDataObject$(newCommunity)); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).not.toHaveBeenCalled(); + }); }); - it('should not navigate on failure', () => { + describe('with at least one item in the uploader\'s queue', () => { + beforeEach(() => { + data = { + dso: Object.assign(new Community(), { + metadata: [{ + key: 'dc.title', + value: 'test' + }] + }), + uploader: { + options: { + url: '' + }, + queue: [ + {} + ], + /* tslint:disable:no-empty */ + uploadAll: () => {} + /* tslint:enable:no-empty */ + } + } + }); + + it('should not navigate', () => { + spyOn(router, 'navigate'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(router.navigate).not.toHaveBeenCalled(); + }); + + it('should set the uploader\'s url to the logo\'s endpoint', () => { + comp.onSubmit(data); + fixture.detectChanges(); + expect(data.uploader.options.url).toEqual(logoEndpoint); + }); + + it('should call the uploader\'s uploadAll', () => { + spyOn(data.uploader, 'uploadAll'); + comp.onSubmit(data); + fixture.detectChanges(); + expect(data.uploader.uploadAll).toHaveBeenCalled(); + }); + }); + }); + + describe('navigateToHomePage', () => { + beforeEach(() => { spyOn(router, 'navigate'); - spyOn(dsoDataService, 'update').and.returnValue(createFailedRemoteDataObject$(newCommunity)); - comp.onSubmit(data); - fixture.detectChanges(); - expect(router.navigate).not.toHaveBeenCalled(); + comp.navigateToHomePage(); + }); + + it('should navigate', () => { + expect(router.navigate).toHaveBeenCalled(); }); }); }); From 37a18fdaa7d5230daa0e063e2f0b02a0d4a71066 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 2 Oct 2019 13:40:06 +0200 Subject: [PATCH 07/22] 65240: Success notification on submitting comcol form --- resources/i18n/en.json5 | 4 ++++ .../create-collection-page.component.spec.ts | 3 +++ .../create-collection-page.component.ts | 9 +++++++-- .../edit-collection-page.component.spec.ts | 3 +++ .../edit-collection-page.component.ts | 9 +++++++-- .../create-community-page.component.spec.ts | 3 +++ .../create-community-page.component.ts | 9 +++++++-- .../edit-community-page.component.spec.ts | 3 +++ .../edit-community-page.component.ts | 9 +++++++-- .../create-comcol-page.component.spec.ts | 4 ++++ .../create-comcol-page.component.ts | 15 +++++++++++++-- .../edit-comcol-page.component.spec.ts | 4 ++++ .../edit-comcol-page.component.ts | 13 ++++++++++++- 13 files changed, 77 insertions(+), 11 deletions(-) diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index cf155c0841..bf97bb4b07 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -121,6 +121,7 @@ "chips.remove": "Remove chip", "collection.create.head": "Create a Collection", + "collection.create.notifications.success": "Successfully created the Collection", "collection.create.sub-head": "Create a Collection for Community {{ parent }}", "collection.delete.cancel": "Cancel", "collection.delete.confirm": "Confirm", @@ -137,6 +138,7 @@ "collection.edit.logo.notifications.delete.success.content": "Successfully deleted the collection's logo", "collection.edit.logo.notifications.delete.error.title": "Error deleting logo", "collection.edit.logo.upload": "Drop a Collection Logo to upload", + "collection.edit.notifications.success": "Successfully edited the Collection", "collection.form.abstract": "Short Description", "collection.form.description": "Introductory text (HTML)", "collection.form.errors.title.required": "Please enter a collection name", @@ -151,6 +153,7 @@ "collection.page.news": "News", "community.create.head": "Create a Community", + "community.create.notifications.success": "Successfully created the Community", "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", "community.delete.cancel": "Cancel", "community.delete.confirm": "Confirm", @@ -167,6 +170,7 @@ "community.edit.logo.notifications.delete.success.content": "Successfully deleted the community's logo", "community.edit.logo.notifications.delete.error.title": "Error deleting logo", "community.edit.logo.upload": "Drop a Community Logo to upload", + "community.edit.notifications.success": "Successfully edited the Community", "community.form.abstract": "Short Description", "community.form.description": "Introductory text (HTML)", "community.form.errors.title.required": "Please enter a community name", diff --git a/src/app/+collection-page/create-collection-page/create-collection-page.component.spec.ts b/src/app/+collection-page/create-collection-page/create-collection-page.component.spec.ts index e223b11c65..869a89d5e0 100644 --- a/src/app/+collection-page/create-collection-page/create-collection-page.component.spec.ts +++ b/src/app/+collection-page/create-collection-page/create-collection-page.component.spec.ts @@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service'; import { of as observableOf } from 'rxjs'; import { CommunityDataService } from '../../core/data/community-data.service'; import { CreateCollectionPageComponent } from './create-collection-page.component'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; describe('CreateCollectionPageComponent', () => { let comp: CreateCollectionPageComponent; @@ -27,6 +29,7 @@ describe('CreateCollectionPageComponent', () => { }, { provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } }, { provide: Router, useValue: {} }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/app/+collection-page/create-collection-page/create-collection-page.component.ts b/src/app/+collection-page/create-collection-page/create-collection-page.component.ts index 2cab36d285..ae31b94c3d 100644 --- a/src/app/+collection-page/create-collection-page/create-collection-page.component.ts +++ b/src/app/+collection-page/create-collection-page/create-collection-page.component.ts @@ -5,6 +5,8 @@ import { Router } from '@angular/router'; import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component'; import { Collection } from '../../core/shared/collection.model'; import { CollectionDataService } from '../../core/data/collection-data.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; /** * Component that represents the page where a user can create a new Collection @@ -16,13 +18,16 @@ import { CollectionDataService } from '../../core/data/collection-data.service'; }) export class CreateCollectionPageComponent extends CreateComColPageComponent { protected frontendURL = '/collections/'; + protected type = Collection.type; public constructor( protected communityDataService: CommunityDataService, protected collectionDataService: CollectionDataService, protected routeService: RouteService, - protected router: Router + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { - super(collectionDataService, communityDataService, routeService, router); + super(collectionDataService, communityDataService, routeService, router, notificationsService, translate); } } diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts index 193cb293e4..8f82c30ff4 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.spec.ts @@ -8,6 +8,8 @@ import { EditCollectionPageComponent } from './edit-collection-page.component'; import { SharedModule } from '../../shared/shared.module'; import { CollectionDataService } from '../../core/data/collection-data.service'; import { of as observableOf } from 'rxjs'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; describe('EditCollectionPageComponent', () => { let comp: EditCollectionPageComponent; @@ -20,6 +22,7 @@ describe('EditCollectionPageComponent', () => { providers: [ { provide: CollectionDataService, useValue: {} }, { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts index ba70bd26c6..310fbb1427 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts @@ -3,6 +3,8 @@ import { ActivatedRoute, Router } from '@angular/router'; import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component'; import { Collection } from '../../core/shared/collection.model'; import { CollectionDataService } from '../../core/data/collection-data.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; /** * Component that represents the page where a user can edit an existing Collection @@ -14,12 +16,15 @@ import { CollectionDataService } from '../../core/data/collection-data.service'; }) export class EditCollectionPageComponent extends EditComColPageComponent { protected frontendURL = '/collections/'; + protected type = Collection.type; public constructor( protected collectionDataService: CollectionDataService, protected router: Router, - protected route: ActivatedRoute + protected route: ActivatedRoute, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { - super(collectionDataService, router, route); + super(collectionDataService, router, route, notificationsService, translate); } } diff --git a/src/app/+community-page/create-community-page/create-community-page.component.spec.ts b/src/app/+community-page/create-community-page/create-community-page.component.spec.ts index dead5a5c3b..d0de8ec71c 100644 --- a/src/app/+community-page/create-community-page/create-community-page.component.spec.ts +++ b/src/app/+community-page/create-community-page/create-community-page.component.spec.ts @@ -10,6 +10,8 @@ import { CollectionDataService } from '../../core/data/collection-data.service'; import { of as observableOf } from 'rxjs'; import { CommunityDataService } from '../../core/data/community-data.service'; import { CreateCommunityPageComponent } from './create-community-page.component'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; describe('CreateCommunityPageComponent', () => { let comp: CreateCommunityPageComponent; @@ -23,6 +25,7 @@ describe('CreateCommunityPageComponent', () => { { provide: CommunityDataService, useValue: { findById: () => observableOf({}) } }, { provide: RouteService, useValue: { getQueryParameterValue: () => observableOf('1234') } }, { provide: Router, useValue: {} }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/app/+community-page/create-community-page/create-community-page.component.ts b/src/app/+community-page/create-community-page/create-community-page.component.ts index fd5f18442a..30a2acbb0d 100644 --- a/src/app/+community-page/create-community-page/create-community-page.component.ts +++ b/src/app/+community-page/create-community-page/create-community-page.component.ts @@ -4,6 +4,8 @@ import { CommunityDataService } from '../../core/data/community-data.service'; import { RouteService } from '../../core/services/route.service'; import { Router } from '@angular/router'; import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; /** * Component that represents the page where a user can create a new Community @@ -15,12 +17,15 @@ import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comc }) export class CreateCommunityPageComponent extends CreateComColPageComponent { protected frontendURL = '/communities/'; + protected type = Community.type; public constructor( protected communityDataService: CommunityDataService, protected routeService: RouteService, - protected router: Router + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { - super(communityDataService, communityDataService, routeService, router); + super(communityDataService, communityDataService, routeService, router, notificationsService, translate); } } diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts index 54f2133ce7..86b1647c90 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.component.spec.ts @@ -8,6 +8,8 @@ import { SharedModule } from '../../shared/shared.module'; import { of as observableOf } from 'rxjs'; import { EditCommunityPageComponent } from './edit-community-page.component'; import { CommunityDataService } from '../../core/data/community-data.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; describe('EditCommunityPageComponent', () => { let comp: EditCommunityPageComponent; @@ -20,6 +22,7 @@ describe('EditCommunityPageComponent', () => { providers: [ { provide: CommunityDataService, useValue: {} }, { provide: ActivatedRoute, useValue: { data: observableOf({ dso: { payload: {} } }) } }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.ts index 9f49ac49dd..c9eea974f7 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.component.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.component.ts @@ -3,6 +3,8 @@ import { Community } from '../../core/shared/community.model'; import { CommunityDataService } from '../../core/data/community-data.service'; import { ActivatedRoute, Router } from '@angular/router'; import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; /** * Component that represents the page where a user can edit an existing Community @@ -14,12 +16,15 @@ import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-p }) export class EditCommunityPageComponent extends EditComColPageComponent { protected frontendURL = '/communities/'; + protected type = Community.type; public constructor( protected communityDataService: CommunityDataService, protected router: Router, - protected route: ActivatedRoute + protected route: ActivatedRoute, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { - super(communityDataService, router, route); + super(communityDataService, router, route, notificationsService, translate); } } diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts index 99aac6757e..717979891f 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.spec.ts @@ -16,6 +16,8 @@ import { createSuccessfulRemoteDataObject$ } from '../../testing/utils'; import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; describe('CreateComColPageComponent', () => { let comp: CreateComColPageComponent; @@ -80,6 +82,7 @@ describe('CreateComColPageComponent', () => { { provide: CommunityDataService, useValue: communityDataServiceStub }, { provide: RouteService, useValue: routeServiceStub }, { provide: Router, useValue: routerStub }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -88,6 +91,7 @@ describe('CreateComColPageComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(CreateComColPageComponent); comp = fixture.componentInstance; + (comp as any).type = Community.type; fixture.detectChanges(); dsoDataService = (comp as any).dsoDataService; communityDataService = (comp as any).communityDataService; diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts index baa05ac5e7..7b23c59498 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -3,7 +3,7 @@ import { Community } from '../../../core/shared/community.model'; import { CommunityDataService } from '../../../core/data/community-data.service'; import { Observable } from 'rxjs'; import { RouteService } from '../../../core/services/route.service'; -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { RemoteData } from '../../../core/data/remote-data'; import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util'; import { take } from 'rxjs/operators'; @@ -11,6 +11,9 @@ import { getSucceededRemoteData } from '../../../core/shared/operators'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { DataService } from '../../../core/data/data.service'; import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +import { ResourceType } from '../../../core/shared/resource-type'; /** * Component representing the create page for communities and collections @@ -40,11 +43,18 @@ export class CreateComColPageComponent implements */ private newUUID: string; + /** + * The type of the dso + */ + protected type: ResourceType; + public constructor( protected dsoDataService: ComColDataService, protected parentDataService: CommunityDataService, protected routeService: RouteService, - protected router: Router + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { } @@ -80,6 +90,7 @@ export class CreateComColPageComponent implements } else { this.navigateToNewPage(); } + this.notificationsService.success(null, this.translate.get(this.type.value + '.create.notifications.success')); } }); }); diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts index 2a52049df5..f2b45e8ed4 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts @@ -16,6 +16,8 @@ import { } from '../../testing/utils'; import { ComColDataService } from '../../../core/data/comcol-data.service'; import { RemoteData } from '../../../core/data/remote-data'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; describe('EditComColPageComponent', () => { let comp: EditComColPageComponent; @@ -73,6 +75,7 @@ describe('EditComColPageComponent', () => { { provide: ComColDataService, useValue: communityDataServiceStub }, { provide: Router, useValue: routerStub }, { provide: ActivatedRoute, useValue: routeStub }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -81,6 +84,7 @@ describe('EditComColPageComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(EditComColPageComponent); comp = fixture.componentInstance; + (comp as any).type = Community.type; fixture.detectChanges(); dsoDataService = (comp as any).dsoDataService; router = (comp as any).router; diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts index ec4a7fd745..19ba578cd6 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts @@ -8,6 +8,9 @@ import { getSucceededRemoteData } from '../../../core/shared/operators'; import { DataService } from '../../../core/data/data.service'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +import { ResourceType } from '../../../core/shared/resource-type'; /** * Component representing the edit page for communities and collections @@ -26,10 +29,17 @@ export class EditComColPageComponent implements On */ public dsoRD$: Observable>; + /** + * The type of the dso + */ + protected type: ResourceType; + public constructor( protected dsoDataService: ComColDataService, protected router: Router, - protected route: ActivatedRoute + protected route: ActivatedRoute, + protected notificationsService: NotificationsService, + protected translate: TranslateService ) { } @@ -58,6 +68,7 @@ export class EditComColPageComponent implements On } else { this.router.navigate([this.frontendURL + newUUID]); } + this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.notifications.success')); } }); } From e10a5bb8f81e5a780de51650d152dd8f8b8bae30 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 3 Oct 2019 14:39:46 +0200 Subject: [PATCH 08/22] 63669: Hide return button for metadata edit on com/col --- .../edit-collection-page.routing.module.ts | 5 ++++- .../edit-comcol-page/edit-comcol-page.component.html | 2 +- .../edit-comcol-page/edit-comcol-page.component.ts | 7 +++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts index a3eab30d73..fcfced9d81 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.routing.module.ts @@ -28,7 +28,10 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate { path: 'metadata', component: CollectionMetadataComponent, - data: { title: 'collection.edit.tabs.metadata.title' } + data: { + title: 'collection.edit.tabs.metadata.title', + hideReturnButton: true + } }, { path: 'roles', diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html index 964fea35e3..aa6290ea9f 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html @@ -16,7 +16,7 @@
- {{ type + '.edit.return' | translate }} + {{ type + '.edit.return' | translate }}
diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts index 9face94abd..b1b37f265e 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts @@ -36,12 +36,19 @@ export class EditComColPageComponent implements On */ public dsoRD$: Observable>; + /** + * Hide the default return button? + */ + public hideReturnButton: boolean; + public constructor( protected router: Router, protected route: ActivatedRoute ) { this.router.events.subscribe(() => { this.currentPage = this.route.snapshot.firstChild.routeConfig.path; + this.hideReturnButton = this.route.routeConfig.children + .find((child: any) => child.path === this.currentPage).data.hideReturnButton; }); } From ac68893f6e2c7c667b040ae56518734bcc10fe56 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 4 Oct 2019 15:47:52 +0200 Subject: [PATCH 09/22] 63669: Test fix --- .../edit-comcol-page/edit-comcol-page.component.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts index 8d1023e66d..d1b87db7ae 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.spec.ts @@ -39,7 +39,14 @@ describe('EditComColPageComponent', () => { dso: community }), routeConfig: { - children: [] + children: [ + { + path: 'mockUrl', + data: { + hideReturnButton: false + } + } + ] }, snapshot: { firstChild: { From c9ea9904839544c2bffc62b3964be92a6b6336e5 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 7 Oct 2019 13:43:26 +0200 Subject: [PATCH 10/22] 63669: Hide return button on community metadata edit --- .../edit-community-page.routing.module.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts index 527b3c018f..1182db2de1 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.routing.module.ts @@ -27,7 +27,10 @@ import { CommunityCurateComponent } from './community-curate/community-curate.co { path: 'metadata', component: CommunityMetadataComponent, - data: { title: 'community.edit.tabs.metadata.title' } + data: { + title: 'community.edit.tabs.metadata.title', + hideReturnButton: true + } }, { path: 'roles', From bfb2ef021a47c8c94ca2ddb8c75f9511ad96be14 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 7 Oct 2019 14:05:54 +0200 Subject: [PATCH 11/22] 65240: AoT build error fixes --- .../collection-form/collection-form.component.ts | 3 +-- .../edit-collection-page.component.ts | 2 +- .../community-form/community-form.component.ts | 2 +- .../edit-community-page/edit-community-page.component.ts | 2 +- .../comcol-forms/comcol-form/comcol-form.component.ts | 4 ++-- .../edit-comcol-page/edit-comcol-page.component.ts | 2 +- src/app/shared/uploader/uploader.component.spec.ts | 4 ++-- .../submission-upload-files.component.spec.ts | 9 +++++---- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/app/+collection-page/collection-form/collection-form.component.ts b/src/app/+collection-page/collection-form/collection-form.component.ts index d91d9fc1fb..a1d6a08290 100644 --- a/src/app/+collection-page/collection-form/collection-form.component.ts +++ b/src/app/+collection-page/collection-form/collection-form.component.ts @@ -3,7 +3,6 @@ import { DynamicFormService, DynamicInputModel, DynamicTextAreaModel } from '@ng import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { Collection } from '../../core/shared/collection.model'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; -import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model'; import { Location } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; import { NotificationsService } from '../../shared/notifications/notifications.service'; @@ -27,7 +26,7 @@ export class CollectionFormComponent extends ComColFormComponent { /** * @type {Collection.type} This is a collection-type form */ - protected type = Collection.type; + type = Collection.type; /** * The dynamic form fields used for creating/editing a collection diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts index 21671fe112..209ce5149a 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts @@ -12,7 +12,7 @@ import { getCollectionPageRoute } from '../collection-page-routing.module'; templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' }) export class EditCollectionPageComponent extends EditComColPageComponent { - protected type = 'collection'; + type = 'collection'; public constructor( protected router: Router, diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts index fc1e77c445..8e4f98c14e 100644 --- a/src/app/+community-page/community-form/community-form.component.ts +++ b/src/app/+community-page/community-form/community-form.component.ts @@ -27,7 +27,7 @@ export class CommunityFormComponent extends ComColFormComponent { /** * @type {Community.type} This is a community-type form */ - protected type = Community.type; + type = Community.type; /** * The dynamic form fields used for creating/editing a community diff --git a/src/app/+community-page/edit-community-page/edit-community-page.component.ts b/src/app/+community-page/edit-community-page/edit-community-page.component.ts index a8d4d32b7d..c0adfe0ff1 100644 --- a/src/app/+community-page/edit-community-page/edit-community-page.component.ts +++ b/src/app/+community-page/edit-community-page/edit-community-page.component.ts @@ -12,7 +12,7 @@ import { getCommunityPageRoute } from '../community-page-routing.module'; templateUrl: '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.html' }) export class EditCommunityPageComponent extends EditComColPageComponent { - protected type = 'community'; + type = 'community'; public constructor( protected router: Router, diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index 6e8b04e589..1fdaac33dd 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -47,7 +47,7 @@ export class ComColFormComponent implements OnInit, OnDe /** * Type of DSpaceObject that the form represents */ - protected type: ResourceType; + type: ResourceType; /** * @type {string} Key prefix used to generate form labels @@ -95,7 +95,7 @@ export class ComColFormComponent implements OnInit, OnDe * Observable keeping track whether or not the uploader has finished initializing * Used to start rendering the uploader component */ - private initializedUploaderOptions = new BehaviorSubject(false); + initializedUploaderOptions = new BehaviorSubject(false); /** * Array to track all subscriptions and unsubscribe them onDestroy diff --git a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts index b1b37f265e..0f9d4c55b4 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/edit-comcol-page.component.ts @@ -19,7 +19,7 @@ export class EditComColPageComponent implements On /** * The type of DSpaceObject (used to create i18n messages) */ - protected type: string; + public type: string; /** * The current page outlet string diff --git a/src/app/shared/uploader/uploader.component.spec.ts b/src/app/shared/uploader/uploader.component.spec.ts index a36bd7241b..dcdac911bf 100644 --- a/src/app/shared/uploader/uploader.component.spec.ts +++ b/src/app/shared/uploader/uploader.component.spec.ts @@ -64,12 +64,12 @@ describe('Chips component', () => { template: `` }) class TestComponent { - public uploadFilesOptions: UploaderOptions = { + public uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), { url: 'http://test', authToken: null, disableMultipart: false, itemAlias: null - }; + }); /* tslint:disable:no-empty */ public onBeforeUpload = () => { diff --git a/src/app/submission/form/submission-upload-files/submission-upload-files.component.spec.ts b/src/app/submission/form/submission-upload-files/submission-upload-files.component.spec.ts index 60a572df54..34d291f0e4 100644 --- a/src/app/submission/form/submission-upload-files/submission-upload-files.component.spec.ts +++ b/src/app/submission/form/submission-upload-files/submission-upload-files.component.spec.ts @@ -28,6 +28,7 @@ import { SubmissionJsonPatchOperationsServiceStub } from '../../../shared/testin import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service'; import { SharedModule } from '../../../shared/shared.module'; import { createTestComponent } from '../../../shared/testing/utils'; +import { UploaderOptions } from '../../../shared/uploader/uploader-options.model'; describe('SubmissionUploadFilesComponent Component', () => { @@ -112,12 +113,12 @@ describe('SubmissionUploadFilesComponent Component', () => { comp.submissionId = submissionId; comp.collectionId = collectionId; comp.sectionId = 'upload'; - comp.uploadFilesOptions = { + comp.uploadFilesOptions = Object.assign(new UploaderOptions(),{ url: '', authToken: null, disableMultipart: false, itemAlias: null - }; + }); }); @@ -208,11 +209,11 @@ class TestComponent { submissionId = mockSubmissionId; collectionId = mockSubmissionCollectionId; sectionId = 'upload'; - uploadFilesOptions = { + uploadFilesOptions = Object.assign(new UploaderOptions(), { url: '', authToken: null, disableMultipart: false, itemAlias: null - }; + }); } From c7bb6ab17c777a52a9d3614573fc878810bf33cf Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 17 Oct 2019 17:59:18 +0200 Subject: [PATCH 12/22] 65240: ComCol logo delete on bitstreams endpoint + caching issue fixes when editing logos --- .../collection-form.component.ts | 8 +++- .../community-form.component.ts | 8 +++- src/app/core/data/comcol-data.service.ts | 41 ++++++++++++++----- .../comcol-form/comcol-form.component.html | 40 +++++++++++------- .../comcol-form/comcol-form.component.ts | 21 ++++++++-- 5 files changed, 85 insertions(+), 33 deletions(-) diff --git a/src/app/+collection-page/collection-form/collection-form.component.ts b/src/app/+collection-page/collection-form/collection-form.component.ts index a1d6a08290..76ba549f14 100644 --- a/src/app/+collection-page/collection-form/collection-form.component.ts +++ b/src/app/+collection-page/collection-form/collection-form.component.ts @@ -8,6 +8,8 @@ import { TranslateService } from '@ngx-translate/core'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CommunityDataService } from '../../core/data/community-data.service'; import { AuthService } from '../../core/auth/auth.service'; +import { RequestService } from '../../core/data/request.service'; +import { ObjectCacheService } from '../../core/cache/object-cache.service'; /** * Form used for creating and editing collections @@ -75,7 +77,9 @@ export class CollectionFormComponent extends ComColFormComponent { protected translate: TranslateService, protected notificationsService: NotificationsService, protected authService: AuthService, - protected dsoService: CommunityDataService) { - super(location, formService, translate, notificationsService, authService); + protected dsoService: CommunityDataService, + protected requestService: RequestService, + protected objectCache: ObjectCacheService) { + super(location, formService, translate, notificationsService, authService, requestService, objectCache); } } diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts index 8e4f98c14e..1f081bd81b 100644 --- a/src/app/+community-page/community-form/community-form.component.ts +++ b/src/app/+community-page/community-form/community-form.component.ts @@ -9,6 +9,8 @@ import { TranslateService } from '@ngx-translate/core'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CommunityDataService } from '../../core/data/community-data.service'; import { AuthService } from '../../core/auth/auth.service'; +import { RequestService } from '../../core/data/request.service'; +import { ObjectCacheService } from '../../core/cache/object-cache.service'; /** * Form used for creating and editing communities @@ -68,7 +70,9 @@ export class CommunityFormComponent extends ComColFormComponent { protected translate: TranslateService, protected notificationsService: NotificationsService, protected authService: AuthService, - protected dsoService: CommunityDataService) { - super(location, formService, translate, notificationsService, authService); + protected dsoService: CommunityDataService, + protected requestService: RequestService, + protected objectCache: ObjectCacheService) { + super(location, formService, translate, notificationsService, authService, requestService, objectCache); } } diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index ba17d04d76..60bd837163 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -1,6 +1,6 @@ import { distinctUntilChanged, filter, map, mergeMap, share, switchMap, take, tap } from 'rxjs/operators'; -import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs'; -import { isEmpty, isNotEmpty } from '../../shared/empty.util'; +import { merge as observableMerge, Observable, throwError as observableThrowError, combineLatest as observableCombineLatest } from 'rxjs'; +import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { NormalizedCommunity } from '../cache/models/normalized-community.model'; import { ObjectCacheService } from '../cache/object-cache.service'; import { CommunityDataService } from './community-data.service'; @@ -8,15 +8,27 @@ import { CommunityDataService } from './community-data.service'; import { DataService } from './data.service'; import { DeleteRequest, FindAllOptions, FindByIDRequest, RestRequest } from './request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { configureRequest, getResponseFromEntry } from '../shared/operators'; +import { + configureRequest, + getRemoteDataPayload, + getResponseFromEntry, + getSucceededRemoteData +} from '../shared/operators'; import { CacheableObject } from '../cache/object-cache.reducer'; import { RestResponse } from '../cache/response.models'; +import { Bitstream } from '../shared/bitstream.model'; +import { DSpaceObject } from '../shared/dspace-object.model'; export abstract class ComColDataService extends DataService { protected abstract cds: CommunityDataService; protected abstract objectCache: ObjectCacheService; protected abstract halService: HALEndpointService; + /** + * Linkpath of endpoint to delete the logo + */ + protected logoDeleteLinkpath = 'bitstreams'; + /** * Get the scoped endpoint URL by fetching the object with * the given scopeID and returning its HAL link with this @@ -71,14 +83,21 @@ export abstract class ComColDataService extends DataS /** * Delete the logo from the community or collection - * @param id The community or collection's ID + * @param dso The object to delete the logo from */ - public deleteLogo(id: string): Observable { - return this.getLogoEndpoint(id).pipe( - map((href: string) => new DeleteRequest(this.requestService.generateRequestId(), href)), - configureRequest(this.requestService), - switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)), - getResponseFromEntry() - ); + public deleteLogo(dso: DSpaceObject): Observable { + const logo$ = (dso as any).logo; + if (hasValue(logo$)) { + return observableCombineLatest( + logo$.pipe(getSucceededRemoteData(), getRemoteDataPayload(), take(1)), + this.halService.getEndpoint(this.logoDeleteLinkpath) + ).pipe( + map(([logo, href]: [Bitstream, string]) => `${href}/${logo.id}`), + map((href: string) => new DeleteRequest(this.requestService.generateRequestId(), href)), + configureRequest(this.requestService), + switchMap((restRequest: RestRequest) => this.requestService.getByUUID(restRequest.uuid)), + getResponseFromEntry() + ); + } } } diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html index b65e6e8f80..fafe796107 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html @@ -1,20 +1,30 @@
- - - -
- +
+
+
- - + +
+ +
+
+
+ +
+
+
+ +
+
+
implements OnInit, OnDe * @type {UploaderOptions} */ uploadFilesOptions: UploaderOptions = Object.assign(new UploaderOptions(), { - disableMultipart: true, autoUpload: false }); @@ -112,7 +114,9 @@ export class ComColFormComponent implements OnInit, OnDe protected formService: DynamicFormService, protected translate: TranslateService, protected notificationsService: NotificationsService, - protected authService: AuthService) { + protected authService: AuthService, + protected requestService: RequestService, + protected objectCache: ObjectCacheService) { } ngOnInit(): void { @@ -204,7 +208,7 @@ export class ComColFormComponent implements OnInit, OnDe */ deleteLogo() { if (hasValue(this.dso.id)) { - this.dsoService.deleteLogo(this.dso.id).subscribe((response: RestResponse) => { + this.dsoService.deleteLogo(this.dso).subscribe((response: RestResponse) => { if (response.isSuccessful) { this.notificationsService.success( this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.title'), @@ -217,14 +221,25 @@ export class ComColFormComponent implements OnInit, OnDe errorResponse.errorMessage ); } + this.refreshCache(); }); } } + /** + * Refresh the object's cache to ensure the latest version + */ + private refreshCache() { + (this.dso as any).logo = undefined; + this.requestService.removeByHrefSubstring(this.dso.self); + this.objectCache.remove(this.dso.self); + } + /** * The request was successful, display a success notification */ public onCompleteItem() { + this.refreshCache(); this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.success')); this.finishUpload.emit(); } From 1fafc3a5d54bcfee13e831e48309f5d1a24fc359 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 18 Oct 2019 10:35:25 +0200 Subject: [PATCH 13/22] 65240: Additional tests --- .../comcol-form/comcol-form.component.spec.ts | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 455e2ef4e0..0a7c55a118 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -20,6 +20,8 @@ import { RemoteData } from '../../../core/data/remote-data'; import { RestRequestMethod } from '../../../core/data/rest-request-method'; import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; import { RequestError } from '../../../core/data/request.models'; +import { RequestService } from '../../../core/data/request.service'; +import { ObjectCacheService } from '../../../core/cache/object-cache.service'; describe('ComColFormComponent', () => { let comp: ComColFormComponent; @@ -69,6 +71,13 @@ describe('ComColFormComponent', () => { const locationStub = jasmine.createSpyObj('location', ['back']); /* tslint:enable:no-empty */ + const requestServiceStub = jasmine.createSpyObj({ + removeByHrefSubstring: {} + }); + const objectCacheStub = jasmine.createSpyObj({ + remove: {} + }); + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule], @@ -77,7 +86,9 @@ describe('ComColFormComponent', () => { { provide: Location, useValue: locationStub }, { provide: DynamicFormService, useValue: formServiceStub }, { provide: NotificationsService, useValue: notificationsService }, - { provide: AuthService, useValue: new AuthServiceMock() } + { provide: AuthService, useValue: new AuthServiceMock() }, + { provide: RequestService, useValue: requestServiceStub }, + { provide: ObjectCacheService, useValue: objectCacheStub } ], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -151,6 +162,11 @@ describe('ComColFormComponent', () => { it('should emit finishUpload', () => { expect(comp.finishUpload.emit).toHaveBeenCalled(); }); + + it('should remove the object\'s cache', () => { + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled(); + expect(objectCacheStub.remove).toHaveBeenCalled(); + }); }); describe('onUploadError', () => { @@ -215,6 +231,11 @@ describe('ComColFormComponent', () => { it('should display a success notification', () => { expect(notificationsService.success).toHaveBeenCalled(); }); + + it('should remove the object\'s cache', () => { + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled(); + expect(objectCacheStub.remove).toHaveBeenCalled(); + }); }); describe('when dsoService.deleteLogo returns an error response', () => { @@ -228,6 +249,11 @@ describe('ComColFormComponent', () => { it('should display an error notification', () => { expect(notificationsService.error).toHaveBeenCalled(); }); + + it('should remove the object\'s cache', () => { + expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled(); + expect(objectCacheStub.remove).toHaveBeenCalled(); + }); }); }); }); From 19a2ae6ecc25a6a8daa644c147c3a6c2a75fa56f Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 23 Oct 2019 10:59:14 +0200 Subject: [PATCH 14/22] 65240: ComCol logo caching issue fix --- .../comcol-forms/comcol-form/comcol-form.component.ts | 5 ++--- .../comcol-metadata/comcol-metadata.component.ts | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index eca3e16cc3..8a41efeef7 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -182,7 +182,7 @@ export class ComColFormComponent implements OnInit, OnDe }); this.submitForm.emit({ dso: updatedDSO, - uploader: this.uploaderComponent.uploader + uploader: hasValue(this.uploaderComponent) ? this.uploaderComponent.uploader : undefined }); } @@ -221,7 +221,7 @@ export class ComColFormComponent implements OnInit, OnDe errorResponse.errorMessage ); } - this.refreshCache(); + (this.dso as any).logo = undefined; }); } } @@ -230,7 +230,6 @@ export class ComColFormComponent implements OnInit, OnDe * Refresh the object's cache to ensure the latest version */ private refreshCache() { - (this.dso as any).logo = undefined; this.requestService.removeByHrefSubstring(this.dso.self); this.objectCache.remove(this.dso.self); } diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts index 2e4f4b745c..fbea6e03d1 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts @@ -5,7 +5,7 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { ActivatedRoute, Router } from '@angular/router'; import { first, map, take } from 'rxjs/operators'; import { getSucceededRemoteData } from '../../../../core/shared/operators'; -import { isNotUndefined } from '../../../empty.util'; +import { hasValue, isNotUndefined } from '../../../empty.util'; import { DataService } from '../../../../core/data/data.service'; import { ResourceType } from '../../../../core/shared/resource-type'; import { ComColDataService } from '../../../../core/data/comcol-data.service'; @@ -57,14 +57,14 @@ export class ComcolMetadataComponent implements On .subscribe((dsoRD: RemoteData) => { if (isNotUndefined(dsoRD)) { const newUUID = dsoRD.payload.uuid; - if (uploader.queue.length > 0) { + if (hasValue(uploader) && uploader.queue.length > 0) { this.dsoDataService.getLogoEndpoint(newUUID).pipe(take(1)).subscribe((href: string) => { uploader.options.url = href; uploader.uploadAll(); }); } else { - this.router.navigate([this.frontendURL + newUUID]); - } + this.router.navigate([this.frontendURL + newUUID]); + } this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.notifications.success')); } }); From 896e19990ba3344e2c2a3df3b294a765955c3acf Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Wed, 23 Oct 2019 13:37:13 +0200 Subject: [PATCH 15/22] 65240: Removed old test cases --- .../comcol-form/comcol-form.component.spec.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 0a7c55a118..51faa20280 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -231,11 +231,6 @@ describe('ComColFormComponent', () => { it('should display a success notification', () => { expect(notificationsService.success).toHaveBeenCalled(); }); - - it('should remove the object\'s cache', () => { - expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled(); - expect(objectCacheStub.remove).toHaveBeenCalled(); - }); }); describe('when dsoService.deleteLogo returns an error response', () => { @@ -249,11 +244,6 @@ describe('ComColFormComponent', () => { it('should display an error notification', () => { expect(notificationsService.error).toHaveBeenCalled(); }); - - it('should remove the object\'s cache', () => { - expect(requestServiceStub.removeByHrefSubstring).toHaveBeenCalled(); - expect(objectCacheStub.remove).toHaveBeenCalled(); - }); }); }); }); From 89f4d660126141bb17000e17a0ea0440b9ac00cf Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Fri, 25 Oct 2019 11:37:43 +0200 Subject: [PATCH 16/22] 65240: Switch to POST requests after logo has been deleted --- src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index 8a41efeef7..c80a2e4506 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -222,6 +222,7 @@ export class ComColFormComponent implements OnInit, OnDe ); } (this.dso as any).logo = undefined; + this.uploadFilesOptions.method = RestRequestMethod.POST; }); } } From 792455f00751d27721f89cd9b8690c804f8eebf4 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 12 Nov 2019 14:21:33 +0100 Subject: [PATCH 17/22] 65240: Uploader alignment fix --- resources/i18n/en.json5 | 2 +- src/app/shared/uploader/uploader.component.html | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index 9e31e31ddb..c4312c0d8f 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -819,7 +819,7 @@ "uploader.browse": "browse", "uploader.drag-message": "Drag & Drop your files here", - "uploader.or": ", or", + "uploader.or": ", or ", "uploader.processing": "Processing", "uploader.queue-length": "Queue length", } diff --git a/src/app/shared/uploader/uploader.component.html b/src/app/shared/uploader/uploader.component.html index a3181be21c..36078fbeb4 100644 --- a/src/app/shared/uploader/uploader.component.html +++ b/src/app/shared/uploader/uploader.component.html @@ -19,12 +19,11 @@ (fileOver)="fileOverBase($event)" class="well ds-base-drop-zone mt-1 mb-3 text-muted">

- {{dropMsg | translate}} {{'uploader.or' | translate}} - - + {{dropMsg | translate}} {{'uploader.or' | translate}} +

From 166aab606d412129a88476f86bd27bd6127e9a91 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Tue, 12 Nov 2019 14:54:16 +0100 Subject: [PATCH 18/22] 65240: logo under browse --- .../collection-page.component.html | 14 ++++++++------ .../+community-page/community-page.component.html | 7 ++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html index 436cd351a0..a8a9a9fdd5 100644 --- a/src/app/+collection-page/collection-page.component.html +++ b/src/app/+collection-page/collection-page.component.html @@ -3,12 +3,7 @@ *ngVar="(collectionRD$ | async) as collectionRD">
-
- - - [alternateText]="'Collection Logo'"> - +
@@ -38,6 +33,13 @@ [contentType]="collection.type"> + + + +

{{'collection.page.browse.recent.head' | translate}}

diff --git a/src/app/+community-page/community-page.component.html b/src/app/+community-page/community-page.component.html index 05d0bd1d0e..87c64b79b7 100644 --- a/src/app/+community-page/community-page.component.html +++ b/src/app/+community-page/community-page.component.html @@ -2,9 +2,6 @@
- - - @@ -25,6 +22,10 @@ + + + + From 64978f2cfee26e8b11d8e59fe4584c15b5714bb9 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 18 Nov 2019 16:28:51 +0100 Subject: [PATCH 19/22] 65240: Marking logo for deletion and request on form submit --- .../create-collection-page.component.html | 2 +- .../collection-metadata.component.html | 2 +- .../create-community-page.component.html | 2 +- .../community-metadata.component.html | 2 +- .../comcol-form/comcol-form.component.html | 23 ++++-- .../comcol-form/comcol-form.component.spec.ts | 81 ++++++++++++++++--- .../comcol-form/comcol-form.component.ts | 67 +++++++++------ .../comcol-metadata.component.ts | 3 +- 8 files changed, 133 insertions(+), 49 deletions(-) diff --git a/src/app/+collection-page/create-collection-page/create-collection-page.component.html b/src/app/+collection-page/create-collection-page/create-collection-page.component.html index dc5c5b186a..800d285846 100644 --- a/src/app/+collection-page/create-collection-page/create-collection-page.component.html +++ b/src/app/+collection-page/create-collection-page/create-collection-page.component.html @@ -4,5 +4,5 @@

{{'collection.create.sub-head' | translate:{ parent: (parentRD$| async)?.payload.name } }}

- +
diff --git a/src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.html b/src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.html index dbfeab98ad..6f3a63790d 100644 --- a/src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.html +++ b/src/app/+collection-page/edit-collection-page/collection-metadata/collection-metadata.component.html @@ -1,6 +1,6 @@ + (finish)="navigateToHomePage()"> {{'collection.edit.delete' | translate}} diff --git a/src/app/+community-page/create-community-page/create-community-page.component.html b/src/app/+community-page/create-community-page/create-community-page.component.html index c1b0cf5971..4f75771f6d 100644 --- a/src/app/+community-page/create-community-page/create-community-page.component.html +++ b/src/app/+community-page/create-community-page/create-community-page.component.html @@ -7,5 +7,5 @@
- +
diff --git a/src/app/+community-page/edit-community-page/community-metadata/community-metadata.component.html b/src/app/+community-page/edit-community-page/community-metadata/community-metadata.component.html index 71c37f5697..6b441dbabd 100644 --- a/src/app/+community-page/edit-community-page/community-metadata/community-metadata.component.html +++ b/src/app/+community-page/edit-community-page/community-metadata/community-metadata.component.html @@ -1,6 +1,6 @@ + (finish)="navigateToHomePage()"> {{'community.edit.delete' | translate}} diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html index fafe796107..09f7e459e4 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.html @@ -4,14 +4,21 @@
-
- -
-
-
- +
+
+
+ +
+
+
+ + +
+
diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 51faa20280..7beafa510b 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -22,8 +22,9 @@ import { ErrorResponse, RestResponse } from '../../../core/cache/response.models import { RequestError } from '../../../core/data/request.models'; import { RequestService } from '../../../core/data/request.service'; import { ObjectCacheService } from '../../../core/cache/object-cache.service'; +import { By } from '@angular/platform-browser'; -describe('ComColFormComponent', () => { +fdescribe('ComColFormComponent', () => { let comp: ComColFormComponent; let fixture: ComponentFixture>; let location: Location; @@ -136,7 +137,8 @@ describe('ComColFormComponent', () => { type: Community.type }, ), - uploader: {} + uploader: {}, + deleteLogo: false } ); }) @@ -151,7 +153,7 @@ describe('ComColFormComponent', () => { describe('onCompleteItem', () => { beforeEach(() => { - spyOn(comp.finishUpload, 'emit'); + spyOn(comp.finish, 'emit'); comp.onCompleteItem(); }); @@ -159,8 +161,8 @@ describe('ComColFormComponent', () => { expect(notificationsService.success).toHaveBeenCalled(); }); - it('should emit finishUpload', () => { - expect(comp.finishUpload.emit).toHaveBeenCalled(); + it('should emit finish', () => { + expect(comp.finish.emit).toHaveBeenCalled(); }); it('should remove the object\'s cache', () => { @@ -171,7 +173,7 @@ describe('ComColFormComponent', () => { describe('onUploadError', () => { beforeEach(() => { - spyOn(comp.finishUpload, 'emit'); + spyOn(comp.finish, 'emit'); comp.onUploadError(); }); @@ -179,8 +181,8 @@ describe('ComColFormComponent', () => { expect(notificationsService.error).toHaveBeenCalled(); }); - it('should emit finishUpload', () => { - expect(comp.finishUpload.emit).toHaveBeenCalled(); + it('should emit finish', () => { + expect(comp.finish.emit).toHaveBeenCalled(); }); }); }); @@ -219,13 +221,17 @@ describe('ComColFormComponent', () => { expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.PUT); }); - describe('deleteLogo', () => { + describe('submit with logo marked for deletion', () => { + beforeEach(() => { + comp.markLogoForDeletion = true; + }); + describe('when dsoService.deleteLogo returns a successful response', () => { const response = new RestResponse(true, 200, 'OK'); beforeEach(() => { spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response)); - comp.deleteLogo(); + comp.onSubmit(); }); it('should display a success notification', () => { @@ -238,7 +244,7 @@ describe('ComColFormComponent', () => { beforeEach(() => { spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response)); - comp.deleteLogo(); + comp.onSubmit(); }); it('should display an error notification', () => { @@ -246,6 +252,59 @@ describe('ComColFormComponent', () => { }); }); }); + + describe('deleteLogo', () => { + beforeEach(() => { + comp.deleteLogo(); + fixture.detectChanges(); + }); + + it('should set markLogoForDeletion to true', () => { + expect(comp.markLogoForDeletion).toEqual(true); + }); + + it('should mark the logo section with a danger alert', () => { + const logoSection = fixture.debugElement.query(By.css('#logo-section.alert-danger')); + expect(logoSection).toBeTruthy(); + }); + + it('should hide the delete button', () => { + const button = fixture.debugElement.query(By.css('#logo-section .btn-danger')); + expect(button).not.toBeTruthy(); + }); + + it('should show the undo button', () => { + const button = fixture.debugElement.query(By.css('#logo-section .btn-warning')); + expect(button).toBeTruthy(); + }); + }); + + describe('undoDeleteLogo', () => { + beforeEach(() => { + comp.markLogoForDeletion = true; + comp.undoDeleteLogo(); + fixture.detectChanges(); + }); + + it('should set markLogoForDeletion to false', () => { + expect(comp.markLogoForDeletion).toEqual(false); + }); + + it('should disable the danger alert on the logo section', () => { + const logoSection = fixture.debugElement.query(By.css('#logo-section.alert-danger')); + expect(logoSection).not.toBeTruthy(); + }); + + it('should show the delete button', () => { + const button = fixture.debugElement.query(By.css('#logo-section .btn-danger')); + expect(button).toBeTruthy(); + }); + + it('should hide the undo button', () => { + const button = fixture.debugElement.query(By.css('#logo-section .btn-warning')); + expect(button).not.toBeTruthy(); + }); + }); }); }); diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index c80a2e4506..d1ad0b8153 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -25,7 +25,6 @@ import { combineLatest as observableCombineLatest } from 'rxjs'; import { RestRequestMethod } from '../../../core/data/rest-request-method'; import { RequestService } from '../../../core/data/request.service'; import { ObjectCacheService } from '../../../core/cache/object-cache.service'; -import { take } from 'rxjs/operators'; /** * A form for creating and editing Communities or Collections @@ -85,13 +84,14 @@ export class ComColFormComponent implements OnInit, OnDe */ @Output() submitForm: EventEmitter<{ dso: T, - uploader: FileUploader + uploader: FileUploader, + deleteLogo: boolean }> = new EventEmitter(); /** - * Fires an event when the logo has finished uploading (with or without errors) + * Fires an event when the logo has finished uploading (with or without errors) or was removed */ - @Output() finishUpload: EventEmitter = new EventEmitter(); + @Output() finish: EventEmitter = new EventEmitter(); /** * Observable keeping track whether or not the uploader has finished initializing @@ -99,6 +99,11 @@ export class ComColFormComponent implements OnInit, OnDe */ initializedUploaderOptions = new BehaviorSubject(false); + /** + * Is the logo marked to be deleted? + */ + markLogoForDeletion = false; + /** * Array to track all subscriptions and unsubscribe them onDestroy * @type {Array} @@ -160,6 +165,26 @@ export class ComColFormComponent implements OnInit, OnDe * Checks which new fields were added and sends the updated version of the DSO to the parent component */ onSubmit() { + if (this.markLogoForDeletion && hasValue(this.dso.id)) { + this.dsoService.deleteLogo(this.dso).subscribe((response: RestResponse) => { + if (response.isSuccessful) { + this.notificationsService.success( + this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.title'), + this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.content') + ); + } else { + const errorResponse = response as ErrorResponse; + this.notificationsService.error( + this.translate.get(this.type.value + '.edit.logo.notifications.delete.error.title'), + errorResponse.errorMessage + ); + } + (this.dso as any).logo = undefined; + this.uploadFilesOptions.method = RestRequestMethod.POST; + this.finish.emit(); + }); + } + const formMetadata = new Object() as MetadataMap; this.formModel.forEach((fieldModel: DynamicInputModel) => { const value: MetadataValue = { @@ -182,7 +207,8 @@ export class ComColFormComponent implements OnInit, OnDe }); this.submitForm.emit({ dso: updatedDSO, - uploader: hasValue(this.uploaderComponent) ? this.uploaderComponent.uploader : undefined + uploader: hasValue(this.uploaderComponent) ? this.uploaderComponent.uploader : undefined, + deleteLogo: this.markLogoForDeletion }); } @@ -204,27 +230,18 @@ export class ComColFormComponent implements OnInit, OnDe } /** + * Mark the logo to be deleted * Send out a delete request to remove the logo from the community/collection and display notifications */ deleteLogo() { - if (hasValue(this.dso.id)) { - this.dsoService.deleteLogo(this.dso).subscribe((response: RestResponse) => { - if (response.isSuccessful) { - this.notificationsService.success( - this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.title'), - this.translate.get(this.type.value + '.edit.logo.notifications.delete.success.content') - ); - } else { - const errorResponse = response as ErrorResponse; - this.notificationsService.error( - this.translate.get(this.type.value + '.edit.logo.notifications.delete.error.title'), - errorResponse.errorMessage - ); - } - (this.dso as any).logo = undefined; - this.uploadFilesOptions.method = RestRequestMethod.POST; - }); - } + this.markLogoForDeletion = true; + } + + /** + * Undo marking the logo to be deleted + */ + undoDeleteLogo() { + this.markLogoForDeletion = false; } /** @@ -241,7 +258,7 @@ export class ComColFormComponent implements OnInit, OnDe public onCompleteItem() { this.refreshCache(); this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.success')); - this.finishUpload.emit(); + this.finish.emit(); } /** @@ -249,7 +266,7 @@ export class ComColFormComponent implements OnInit, OnDe */ public onUploadError() { this.notificationsService.error(null, this.translate.get(this.type.value + '.edit.logo.notifications.add.error')); - this.finishUpload.emit(); + this.finish.emit(); } /** diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts index fbea6e03d1..1031fead10 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.ts @@ -51,6 +51,7 @@ export class ComcolMetadataComponent implements On onSubmit(event) { const dso = event.dso; const uploader = event.uploader; + const deleteLogo = event.deleteLogo; this.dsoDataService.update(dso) .pipe(getSucceededRemoteData()) @@ -62,7 +63,7 @@ export class ComcolMetadataComponent implements On uploader.options.url = href; uploader.uploadAll(); }); - } else { + } else if (!deleteLogo) { this.router.navigate([this.frontendURL + newUUID]); } this.notificationsService.success(null, this.translate.get(this.type.value + '.edit.notifications.success')); From c7b37663997f5f04c47d658c8c81767d8201c091 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Mon, 18 Nov 2019 17:36:56 +0100 Subject: [PATCH 20/22] 65240: fdescribe to describe --- .../comcol-forms/comcol-form/comcol-form.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 7beafa510b..42e2c4ccb5 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -24,7 +24,7 @@ import { RequestService } from '../../../core/data/request.service'; import { ObjectCacheService } from '../../../core/cache/object-cache.service'; import { By } from '@angular/platform-browser'; -fdescribe('ComColFormComponent', () => { +describe('ComColFormComponent', () => { let comp: ComColFormComponent; let fixture: ComponentFixture>; let location: Location; From 7755228b59e279ed52e942ccfadf0a06f1f7e2d0 Mon Sep 17 00:00:00 2001 From: Kristof De Langhe Date: Thu, 28 Nov 2019 11:51:07 +0100 Subject: [PATCH 21/22] 65240: Refresh object cache after removing com/col logo --- src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index d1ad0b8153..4db744e7d5 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -181,6 +181,7 @@ export class ComColFormComponent implements OnInit, OnDe } (this.dso as any).logo = undefined; this.uploadFilesOptions.method = RestRequestMethod.POST; + this.refreshCache(); this.finish.emit(); }); } From 9df5a508f1511b683ff675a53fbf6549eb98a4d1 Mon Sep 17 00:00:00 2001 From: Philip Vissenaekens Date: Thu, 12 Dec 2019 13:11:54 +0100 Subject: [PATCH 22/22] 65240: Community and Collection logo layout --- .../collection-page.component.html | 21 +++++++------------ .../community-page.component.html | 8 +++---- src/app/core/data/comcol-data.service.ts | 11 +++------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html index 1cd0318bd5..98552ed40b 100644 --- a/src/app/+collection-page/collection-page.component.html +++ b/src/app/+collection-page/collection-page.component.html @@ -5,15 +5,17 @@
- - - [alternateText]="'Collection Logo'"> - - + + + + + - - - -

{{'collection.page.browse.recent.head' | translate}}

diff --git a/src/app/+community-page/community-page.component.html b/src/app/+community-page/community-page.component.html index ed9d527067..dfd1ce93d9 100644 --- a/src/app/+community-page/community-page.component.html +++ b/src/app/+community-page/community-page.component.html @@ -3,9 +3,11 @@
- + + + @@ -23,10 +25,6 @@ - - - - diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index 63f8e9ef44..2ce0362a4e 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -1,24 +1,19 @@ import { distinctUntilChanged, - filter, first, - map, - mergeMap, - share, - switchMap, + filter, first,map, mergeMap, share, switchMap, take, tap } from 'rxjs/operators'; -import { merge as observableMerge, Observable, throwError as observableThrowError } from 'rxjs'; +import { merge as observableMerge, Observable, throwError as observableThrowError, combineLatest as observableCombineLatest } from 'rxjs'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { NormalizedCommunity } from '../cache/models/normalized-community.model'; import { ObjectCacheService } from '../cache/object-cache.service'; import { CommunityDataService } from './community-data.service'; import { DataService } from './data.service'; -import { DeleteRequest, FindAllOptions, FindByIDRequest, RestRequest } from './request.models'; +import { DeleteRequest, FindListOptions, FindByIDRequest, RestRequest } from './request.models'; import { PaginatedList } from './paginated-list'; import { RemoteData } from './remote-data'; -import { FindListOptions, FindByIDRequest } from './request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { configureRequest,