mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
[835] Auto-save in new Item Submission form breaks the form
Submission form Save button disabled when no pending operations are present
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { getTestScheduler } from 'jasmine-marbles';
|
||||
import { getTestScheduler, hot } from 'jasmine-marbles';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { getMockRequestService } from '../../shared/mocks/request.service.mock';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { SubmissionPatchRequest } from '../data/request.models';
|
||||
@@ -22,6 +21,7 @@ import {
|
||||
} from './json-patch-operations.actions';
|
||||
import { RequestEntry } from '../data/request.reducer';
|
||||
import { createFailedRemoteDataObject, createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||
import { _deepClone } from 'fast-json-patch/lib/helpers';
|
||||
|
||||
class TestService extends JsonPatchOperationsService<SubmitDataResponseDefinitionObject, SubmissionPatchRequest> {
|
||||
protected linkPath = '';
|
||||
@@ -196,6 +196,32 @@ describe('JsonPatchOperationsService test suite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasPendingOperations', () => {
|
||||
|
||||
it('should return true when there are pending operations', () => {
|
||||
|
||||
const expected = hot('(x|)', { x: true });
|
||||
|
||||
const result = service.hasPendingOperations(testJsonPatchResourceType);
|
||||
expect(result).toBeObservable(expected);
|
||||
|
||||
});
|
||||
|
||||
it('should return false when there are not pending operations', () => {
|
||||
|
||||
const mockStateNoOp = _deepClone(mockState);
|
||||
mockStateNoOp['json/patch'][testJsonPatchResourceType].children = [];
|
||||
store.select.and.returnValue(observableOf(mockStateNoOp['json/patch'][testJsonPatchResourceType]));
|
||||
|
||||
const expected = hot('(x|)', { x: false });
|
||||
|
||||
const result = service.hasPendingOperations(testJsonPatchResourceType);
|
||||
expect(result).toBeObservable(expected);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('jsonPatchByResourceID', () => {
|
||||
|
||||
it('should call submitJsonPatchOperations method', () => {
|
||||
|
@@ -161,6 +161,18 @@ export abstract class JsonPatchOperationsService<ResponseDefinitionDomain, Patch
|
||||
return this.submitJsonPatchOperations(href$, resourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the jsonPatch operation related to the specified resource type.
|
||||
* @param resourceType
|
||||
*/
|
||||
public hasPendingOperations(resourceType: string): Observable<boolean> {
|
||||
return this.store.select(jsonPatchOperationsByResourceType(resourceType)).pipe(
|
||||
map((val) => !isEmpty(val) && Object.values(val.children)
|
||||
.filter((section) => !isEmpty((section as any).body)).length > 0),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new JSON Patch request with all operations related to the specified resource id
|
||||
*
|
||||
|
@@ -20,6 +20,7 @@ export class SubmissionServiceStub {
|
||||
getSubmissionStatus = jasmine.createSpy('getSubmissionStatus');
|
||||
getSubmissionSaveProcessingStatus = jasmine.createSpy('getSubmissionSaveProcessingStatus');
|
||||
getSubmissionDepositProcessingStatus = jasmine.createSpy('getSubmissionDepositProcessingStatus');
|
||||
hasNotSavedModification = jasmine.createSpy('hasNotSavedModification');
|
||||
isSectionHidden = jasmine.createSpy('isSectionHidden');
|
||||
isSubmissionLoading = jasmine.createSpy('isSubmissionLoading');
|
||||
notifyNewSection = jasmine.createSpy('notifyNewSection');
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<button type="button"
|
||||
class="btn btn-info"
|
||||
id="save"
|
||||
[disabled]="(processingSaveStatus | async)"
|
||||
[disabled]="(processingSaveStatus | async) || !(hasNotSavedModification | async)"
|
||||
(click)="save($event)">
|
||||
<span>{{'submission.general.save' | translate}}</span>
|
||||
</button>
|
||||
|
@@ -224,6 +224,22 @@ describe('SubmissionFormFooterComponent Component', () => {
|
||||
expect(depositBtn.nativeElement.disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should disable save button when all modifications had been saved', () => {
|
||||
comp.hasNotSavedModification = observableOf(false);
|
||||
fixture.detectChanges();
|
||||
|
||||
const saveBtn: any = fixture.debugElement.query(By.css('#save'));
|
||||
expect(saveBtn.nativeElement.disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should enable save button when there are not saved modifications', () => {
|
||||
comp.hasNotSavedModification = observableOf(true);
|
||||
fixture.detectChanges();
|
||||
|
||||
const saveBtn: any = fixture.debugElement.query(By.css('#save'));
|
||||
expect(saveBtn.nativeElement.disabled).toBeFalsy();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -49,6 +49,11 @@ export class SubmissionFormFooterComponent implements OnChanges {
|
||||
*/
|
||||
public submissionIsInvalid: Observable<boolean> = observableOf(true);
|
||||
|
||||
/**
|
||||
* A boolean representing if submission form has unsaved modifications
|
||||
*/
|
||||
public hasNotSavedModification: Observable<boolean>;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
@@ -73,6 +78,7 @@ export class SubmissionFormFooterComponent implements OnChanges {
|
||||
this.processingSaveStatus = this.submissionService.getSubmissionSaveProcessingStatus(this.submissionId);
|
||||
this.processingDepositStatus = this.submissionService.getSubmissionDepositProcessingStatus(this.submissionId);
|
||||
this.showDepositAndDiscard = observableOf(this.submissionService.getSubmissionScope() === SubmissionScopeType.WorkspaceItem);
|
||||
this.hasNotSavedModification = this.submissionService.hasNotSavedModification();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,6 +46,8 @@ import { SearchService } from '../core/shared/search/search.service';
|
||||
import { Item } from '../core/shared/item.model';
|
||||
import { storeModuleConfig } from '../app.reducer';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { SubmissionJsonPatchOperationsService } from '../core/submission/submission-json-patch-operations.service';
|
||||
import { SubmissionJsonPatchOperationsServiceStub } from '../shared/testing/submission-json-patch-operations-service.stub';
|
||||
|
||||
describe('SubmissionService test suite', () => {
|
||||
const collectionId = '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f';
|
||||
@@ -345,6 +347,7 @@ describe('SubmissionService test suite', () => {
|
||||
const router = new RouterMock();
|
||||
const selfUrl = 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826';
|
||||
const submissionDefinition: any = mockSubmissionDefinition;
|
||||
const submissionJsonPatchOperationsService = new SubmissionJsonPatchOperationsServiceStub();
|
||||
|
||||
let scheduler: TestScheduler;
|
||||
let service: SubmissionService;
|
||||
@@ -371,6 +374,7 @@ describe('SubmissionService test suite', () => {
|
||||
{ provide: ActivatedRoute, useValue: new MockActivatedRoute() },
|
||||
{ provide: SearchService, useValue: searchService },
|
||||
{ provide: RequestService, useValue: requestServce },
|
||||
{ provide: SubmissionJsonPatchOperationsService, useValue: submissionJsonPatchOperationsService },
|
||||
NotificationsService,
|
||||
RouteService,
|
||||
SubmissionService,
|
||||
@@ -753,6 +757,20 @@ describe('SubmissionService test suite', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasNotSavedModification', () => {
|
||||
it('should call jsonPatchOperationService hasPendingOperation observable', () => {
|
||||
(service as any).jsonPatchOperationService.hasPendingOperations = jasmine.createSpy('hasPendingOperations')
|
||||
.and.returnValue(observableOf(true));
|
||||
|
||||
scheduler = getTestScheduler();
|
||||
scheduler.schedule(() => service.hasNotSavedModification());
|
||||
scheduler.flush();
|
||||
|
||||
expect((service as any).jsonPatchOperationService.hasPendingOperations).toHaveBeenCalledWith('sections');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSectionHidden', () => {
|
||||
it('should return true/false when section is hidden/visible', () => {
|
||||
let section: any = {
|
||||
|
@@ -45,6 +45,7 @@ import { RequestService } from '../core/data/request.service';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
import { Item } from '../core/shared/item.model';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { SubmissionJsonPatchOperationsService } from '../core/submission/submission-json-patch-operations.service';
|
||||
|
||||
/**
|
||||
* A service that provides methods used in submission process.
|
||||
@@ -82,7 +83,8 @@ export class SubmissionService {
|
||||
protected store: Store<SubmissionState>,
|
||||
protected translate: TranslateService,
|
||||
protected searchService: SearchService,
|
||||
protected requestService: RequestService) {
|
||||
protected requestService: RequestService,
|
||||
protected jsonPatchOperationService: SubmissionJsonPatchOperationsService) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,6 +431,16 @@ export class SubmissionService {
|
||||
startWith(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether submission unsaved modification are present
|
||||
*
|
||||
* @return Observable<boolean>
|
||||
* observable with submission unsaved modification presence
|
||||
*/
|
||||
hasNotSavedModification(): Observable<boolean> {
|
||||
return this.jsonPatchOperationService.hasPendingOperations('sections');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the visibility status of the specified section
|
||||
*
|
||||
|
Reference in New Issue
Block a user