Skip to content

Commit

Permalink
Merge pull request DSpace#2837 from 4Science/DURACOM-235
Browse files Browse the repository at this point in the history
Enhanced community/colletion logo edit
  • Loading branch information
tdonohue authored May 14, 2024
2 parents 74f89f2 + b7d454f commit f59510d
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 235 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
SimpleChange,
SimpleChanges,
} from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicFormControlModel,
DynamicFormOptionConfig,
Expand All @@ -30,7 +31,7 @@ import {

import { AuthService } from '../../core/auth/auth.service';
import { ObjectCacheService } from '../../core/cache/object-cache.service';
import { CommunityDataService } from '../../core/data/community-data.service';
import { CollectionDataService } from '../../core/data/collection-data.service';
import { EntityTypeDataService } from '../../core/data/entity-type-data.service';
import { RequestService } from '../../core/data/request.service';
import { Collection } from '../../core/shared/collection.model';
Expand Down Expand Up @@ -95,12 +96,13 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> imp
protected translate: TranslateService,
protected notificationsService: NotificationsService,
protected authService: AuthService,
protected dsoService: CommunityDataService,
protected dsoService: CollectionDataService,
protected requestService: RequestService,
protected objectCache: ObjectCacheService,
protected entityTypeService: EntityTypeDataService,
protected chd: ChangeDetectorRef) {
super(formService, translate, notificationsService, authService, requestService, objectCache);
protected chd: ChangeDetectorRef,
protected modalService: NgbModal) {
super(formService, translate, notificationsService, authService, requestService, objectCache, modalService);
}

ngOnInit(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
</div>
</div>
<ds-collection-form (submitForm)="onSubmit($event)"
(back)="navigateToHome()"
(finish)="navigateToNewPage()"></ds-collection-form>
[isCreation]="true"
(back)="navigateToHome()"></ds-collection-form>
</div>

<div class="container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
</div>
</div>
<ds-collection-form [dso]="(dsoRD$ | async)?.payload"
[isCreation]="false"
(submitForm)="onSubmit($event)"
(back)="navigateToHomePage()"
(finish)="navigateToHomePage()"></ds-collection-form>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SimpleChange,
SimpleChanges,
} from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicFormControlModel,
DynamicFormService,
Expand Down Expand Up @@ -108,8 +109,9 @@ export class CommunityFormComponent extends ComColFormComponent<Community> imple
protected authService: AuthService,
protected dsoService: CommunityDataService,
protected requestService: RequestService,
protected objectCache: ObjectCacheService) {
super(formService, translate, notificationsService, authService, requestService, objectCache);
protected objectCache: ObjectCacheService,
protected modalService: NgbModal) {
super(formService, translate, notificationsService, authService, requestService, objectCache, modalService);
}

ngOnChanges(changes: SimpleChanges) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<div class="row">
<div class="col-12 pb-4">
<ng-container *ngVar="(parentRD$ | async)?.payload as parent">
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.create.head' | translate }}</h2>
<h2 *ngIf="!parent" id="header" class="border-bottom p-2">{{ 'community.create.head' | translate }}</h2>
<h2 *ngIf="parent" id="sub-header"
class="border-bottom pb-2">{{ 'community.create.sub-head' | translate:{ parent: dsoNameService.getName(parent) } }}</h2>
</ng-container>
</div>
</div>
<ds-community-form (submitForm)="onSubmit($event)"
(back)="navigateToHome()"
(finish)="navigateToNewPage()"></ds-community-form>
[isCreation]="true"
(back)="navigateToHome()"></ds-community-form>
</div>

<div class="container">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<ds-community-form [dso]="(dsoRD$ | async)?.payload"
[isCreation]="false"
(submitForm)="onSubmit($event)"
(back)="navigateToHomePage()"
(finish)="navigateToHomePage()"></ds-community-form>

Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,17 @@
<span>{{type.value + '.edit.logo.label' | translate}}</span>
</div>
<ng-container *ngVar="(dso?.logo | async)?.payload as logo">
<div class="col-12 d-inline-block alert" [ngClass]="{'alert-danger': markLogoForDeletion}" id="logo-section" *ngIf="logo">
<div class="col-12 d-inline-block alert" id="logo-section" *ngIf="logo">
<div class="row">
<div class="col-8 d-inline-block">
<ds-comcol-page-logo [alternateText]="type.value + '.logo.alt'" [logo]="logo"></ds-comcol-page-logo>
</div>
<div class="col-4 d-inline-block">
<div *ngIf="logo" class="btn-group btn-group-sm float-right" role="group">
<button *ngIf="!markLogoForDeletion" type="button" class="btn btn-danger"
title="{{type.value + '.edit.logo.delete.title' | translate}}"
(click)="deleteLogo()">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
<button *ngIf="markLogoForDeletion" type="button" class="btn btn-warning"
title="{{type.value + '.edit.logo.delete-undo.title' | translate}}"
(click)="undoDeleteLogo()">
<i class="fas fa-undo" aria-hidden="true"></i>
<div *ngIf="logo" class="float-right">
<button
(click)="confirmLogoDeleteWithModal()"
class="btn btn-danger"
type="button">{{ 'community.edit.logo.delete.title' | translate }}
</button>
</div>
</div>
Expand All @@ -43,7 +38,8 @@
[formModel]="formModel"
[displayCancel]="false"
(submitForm)="onSubmit()">
<button before (click)="back.emit()" class="btn btn-outline-secondary" type="button">
<button (click)="back.emit()" before class="btn btn-outline-secondary" type="button">
<i class="fas fa-arrow-left" aria-hidden="true"></i> {{ type.value + '.edit.return' | translate }}
</button>
</ds-form>

Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ import { hasValue } from '../../../empty.util';
import { FormComponent } from '../../../form/form.component';
import { AuthServiceMock } from '../../../mocks/auth.service.mock';
import { NotificationsService } from '../../../notifications/notifications.service';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$,
} from '../../../remote-data.utils';
import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
import { NotificationsServiceStub } from '../../../testing/notifications-service.stub';
import { UploaderComponent } from '../../../upload/uploader/uploader.component';
import { VarDirective } from '../../../utils/var.directive';
Expand Down Expand Up @@ -80,6 +77,7 @@ describe('ComColFormComponent', () => {
const dsoService = Object.assign({
getLogoEndpoint: () => observableOf(logoEndpoint),
deleteLogo: () => createSuccessfulRemoteDataObject$({}),
findById: () => createSuccessfulRemoteDataObject$({}),
});
const notificationsService = new NotificationsServiceStub();

Expand All @@ -89,6 +87,7 @@ describe('ComColFormComponent', () => {

const requestServiceStub = jasmine.createSpyObj('requestService', {
removeByHrefSubstring: {},
setStaleByHrefSubstring: {},
});
const objectCacheStub = jasmine.createSpyObj('objectCache', {
remove: {},
Expand Down Expand Up @@ -175,8 +174,6 @@ describe('ComColFormComponent', () => {
type: Community.type,
},
),
uploader: undefined,
deleteLogo: false,
operations: operations,
},
);
Expand All @@ -185,32 +182,22 @@ describe('ComColFormComponent', () => {

describe('onCompleteItem', () => {
beforeEach(() => {
spyOn(comp.finish, 'emit');
comp.onCompleteItem();
});

it('should show a success notification', () => {
expect(notificationsService.success).toHaveBeenCalled();
});

it('should emit finish', () => {
expect(comp.finish.emit).toHaveBeenCalled();
});
});

describe('onUploadError', () => {
beforeEach(() => {
spyOn(comp.finish, 'emit');
comp.onUploadError();
});

it('should show an error notification', () => {
expect(notificationsService.error).toHaveBeenCalled();
});

it('should emit finish', () => {
expect(comp.finish.emit).toHaveBeenCalled();
});
});
});

Expand All @@ -231,6 +218,11 @@ describe('ComColFormComponent', () => {
it('should initialize the uploadFilesOptions with a POST method', () => {
expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.POST);
});

it('should not show the delete logo button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
expect(button).toBeFalsy();
});
});

describe('and the dso contains a logo', () => {
Expand All @@ -249,96 +241,71 @@ describe('ComColFormComponent', () => {
expect(comp.uploadFilesOptions.url).toEqual(logoEndpoint);
});

it('should initialize the uploadFilesOptions with a PUT method', () => {
expect(comp.uploadFilesOptions.method).toEqual(RestRequestMethod.PUT);
it('should show the delete logo button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
expect(button).toBeTruthy();
});

describe('submit with logo marked for deletion', () => {
describe('when the delete logo button is clicked', () => {
beforeEach(() => {
spyOn(dsoService, 'deleteLogo').and.callThrough();
comp.markLogoForDeletion = true;
});

it('should call dsoService.deleteLogo on the DSO', () => {
comp.onSubmit();
spyOn(dsoService, 'deleteLogo').and.returnValue(createSuccessfulRemoteDataObject$({}));
spyOn(comp, 'handleLogoDeletion').and.callThrough();
spyOn(comp, 'createConfirmationModal').and.callThrough();
spyOn(comp, 'subscribeToConfirmationResponse').and.callThrough();
const deleteButton = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
deleteButton.nativeElement.click();
fixture.detectChanges();

expect(dsoService.deleteLogo).toHaveBeenCalledWith(comp.dso);
});

describe('when dsoService.deleteLogo returns a successful response', () => {
beforeEach(() => {
dsoService.deleteLogo.and.returnValue(createSuccessfulRemoteDataObject$({}));
comp.onSubmit();
});
it('should create a confirmation modal with the correct labels and properties', () => {
const modalServiceSpy = spyOn((comp as any).modalService, 'open').and.callThrough();

it('should display a success notification', () => {
expect(notificationsService.success).toHaveBeenCalled();
});
});
const modalRef = comp.createConfirmationModal();

describe('when dsoService.deleteLogo returns an error response', () => {
beforeEach(() => {
dsoService.deleteLogo.and.returnValue(createFailedRemoteDataObject$('Error', 500));
comp.onSubmit();
});
expect(modalServiceSpy).toHaveBeenCalled();

it('should display an error notification', () => {
expect(notificationsService.error).toHaveBeenCalled();
});
});
});
expect(modalRef).toBeDefined();
expect(modalRef.componentInstance).toBeDefined();

describe('deleteLogo', () => {
beforeEach(() => {
comp.deleteLogo();
fixture.detectChanges();
expect(modalRef.componentInstance.headerLabel).toBe('community-collection.edit.logo.delete.title');
expect(modalRef.componentInstance.infoLabel).toBe('confirmation-modal.delete-community-collection-logo.info');
expect(modalRef.componentInstance.cancelLabel).toBe('form.cancel');
expect(modalRef.componentInstance.confirmLabel).toBe('community-collection.edit.logo.delete.title');
expect(modalRef.componentInstance.confirmIcon).toBe('fas fa-trash');
});

it('should set markLogoForDeletion to true', () => {
expect(comp.markLogoForDeletion).toEqual(true);
it('should call createConfirmationModal method', () => {
expect(comp.createConfirmationModal).toHaveBeenCalled();
});

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 call subscribeToConfirmationResponse method', () => {
expect(comp.subscribeToConfirmationResponse).toHaveBeenCalled();
});

it('should hide the delete button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
expect(button).not.toBeTruthy();
});
describe('when the modal is closed', () => {

it('should show the undo button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-warning'));
expect(button).toBeTruthy();
});
});
let modalRef;

describe('undoDeleteLogo', () => {
beforeEach(() => {
comp.markLogoForDeletion = true;
comp.undoDeleteLogo();
fixture.detectChanges();
});
beforeEach(() => {
modalRef = comp.createConfirmationModal();
comp.subscribeToConfirmationResponse(modalRef);
});

it('should set markLogoForDeletion to false', () => {
expect(comp.markLogoForDeletion).toEqual(false);
});
it('should call handleLogoDeletion and dsoService.deleteLogo methods when deletion is confirmed', waitForAsync(() => {
modalRef.componentInstance.confirmPressed();

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();
});
expect(comp.handleLogoDeletion).toHaveBeenCalled();
expect(dsoService.deleteLogo).toHaveBeenCalled();

it('should show the delete button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-danger'));
expect(button).toBeTruthy();
});
}));

it('should not call handleLogoDeletion and dsoService.deleteLogo methods when deletion is refused', waitForAsync(() => {
modalRef.componentInstance.cancelPressed();

expect(comp.handleLogoDeletion).not.toHaveBeenCalled();
expect(dsoService.deleteLogo).not.toHaveBeenCalled();
}));

it('should hide the undo button', () => {
const button = fixture.debugElement.query(By.css('#logo-section .btn-warning'));
expect(button).not.toBeTruthy();
});
});
});
Expand Down
Loading

0 comments on commit f59510d

Please sign in to comment.