mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 10:34:15 +00:00
63667: Extract update tracker
This commit is contained in:
@@ -138,6 +138,7 @@ import { RoleDirective } from './roles/role.directive';
|
|||||||
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component';
|
||||||
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component';
|
||||||
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
import { ItemDetailPreviewFieldComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||||
|
import { AbstractTrackableComponent } from './trackable/abstract-trackable.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -257,7 +258,8 @@ const COMPONENTS = [
|
|||||||
ItemSearchResultListElementComponent,
|
ItemSearchResultListElementComponent,
|
||||||
TypedItemSearchResultListElementComponent,
|
TypedItemSearchResultListElementComponent,
|
||||||
ItemTypeSwitcherComponent,
|
ItemTypeSwitcherComponent,
|
||||||
BrowseByComponent
|
BrowseByComponent,
|
||||||
|
AbstractTrackableComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
@@ -311,6 +313,7 @@ const SHARED_ITEM_PAGE_COMPONENTS = [
|
|||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
TruncatableService,
|
TruncatableService,
|
||||||
MockAdminGuard,
|
MockAdminGuard,
|
||||||
|
AbstractTrackableComponent,
|
||||||
{
|
{
|
||||||
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
|
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
|
||||||
useValue: dsDynamicFormControlMapFn
|
useValue: dsDynamicFormControlMapFn
|
||||||
|
101
src/app/shared/trackable/abstract-trackable.component.spec.ts
Normal file
101
src/app/shared/trackable/abstract-trackable.component.spec.ts
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { AbstractTrackableComponent } from './abstract-trackable.component';
|
||||||
|
import { INotification, Notification } from '../notifications/models/notification.model';
|
||||||
|
import { NotificationType } from '../notifications/models/notification-type';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
|
||||||
|
import { NotificationsService } from '../notifications/notifications.service';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { TestScheduler } from 'rxjs/testing';
|
||||||
|
import { getTestScheduler } from 'jasmine-marbles';
|
||||||
|
|
||||||
|
describe('AbstractTrackableComponent', () => {
|
||||||
|
let comp: AbstractTrackableComponent;
|
||||||
|
let fixture: ComponentFixture<AbstractTrackableComponent>;
|
||||||
|
let objectUpdatesService;
|
||||||
|
let scheduler: TestScheduler;
|
||||||
|
|
||||||
|
const infoNotification: INotification = new Notification('id', NotificationType.Info, 'info');
|
||||||
|
const warningNotification: INotification = new Notification('id', NotificationType.Warning, 'warning');
|
||||||
|
const successNotification: INotification = new Notification('id', NotificationType.Success, 'success');
|
||||||
|
|
||||||
|
const notificationsService = jasmine.createSpyObj('notificationsService',
|
||||||
|
{
|
||||||
|
info: infoNotification,
|
||||||
|
warning: warningNotification,
|
||||||
|
success: successNotification
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const url = 'http://test-url.com/test-url';
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
|
||||||
|
{
|
||||||
|
saveAddFieldUpdate: {},
|
||||||
|
discardFieldUpdates: {},
|
||||||
|
reinstateFieldUpdates: observableOf(true),
|
||||||
|
initialize: {},
|
||||||
|
hasUpdates: observableOf(true),
|
||||||
|
isReinstatable: observableOf(false), // should always return something --> its in ngOnInit
|
||||||
|
isValidPage: observableOf(true)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scheduler = getTestScheduler();
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot()],
|
||||||
|
declarations: [AbstractTrackableComponent],
|
||||||
|
providers: [
|
||||||
|
{provide: ObjectUpdatesService, useValue: objectUpdatesService},
|
||||||
|
{provide: NotificationsService, useValue: notificationsService},
|
||||||
|
], schemas: [
|
||||||
|
NO_ERRORS_SCHEMA
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AbstractTrackableComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
comp.url = url;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should discard object updates', () => {
|
||||||
|
comp.discard();
|
||||||
|
|
||||||
|
expect(objectUpdatesService.discardFieldUpdates).toHaveBeenCalledWith(url, infoNotification);
|
||||||
|
});
|
||||||
|
it('should undo the discard of object updates', () => {
|
||||||
|
comp.reinstate();
|
||||||
|
|
||||||
|
expect(objectUpdatesService.reinstateFieldUpdates).toHaveBeenCalledWith(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isReinstatable', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
objectUpdatesService.isReinstatable.and.returnValue(observableOf(true));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an observable that emits true', () => {
|
||||||
|
const expected = '(a|)';
|
||||||
|
scheduler.expectObservable(comp.isReinstatable()).toBe(expected, {a: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasChanges', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
objectUpdatesService.hasUpdates.and.returnValue(observableOf(true));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an observable that emits true', () => {
|
||||||
|
const expected = '(a|)';
|
||||||
|
scheduler.expectObservable(comp.hasChanges()).toBe(expected, {a: true});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
78
src/app/shared/trackable/abstract-trackable.component.ts
Normal file
78
src/app/shared/trackable/abstract-trackable.component.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
|
||||||
|
import { NotificationsService } from '../notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Component that is able to track changes made in the inheriting component using the ObjectUpdateService
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-abstract-trackable',
|
||||||
|
template: ''
|
||||||
|
})
|
||||||
|
export class AbstractTrackableComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time span for being able to undo discarding changes
|
||||||
|
*/
|
||||||
|
public discardTimeOut: number;
|
||||||
|
public message: string;
|
||||||
|
public url: string;
|
||||||
|
public notificationsPrefix = 'static-pages.form.notification';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public objectUpdatesService: ObjectUpdatesService,
|
||||||
|
public notificationsService: NotificationsService,
|
||||||
|
public translateService: TranslateService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the object updates service to discard all current changes to this item
|
||||||
|
* Shows a notification to remind the user that they can undo this
|
||||||
|
*/
|
||||||
|
discard() {
|
||||||
|
const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), {timeOut: this.discardTimeOut});
|
||||||
|
this.objectUpdatesService.discardFieldUpdates(this.url, undoNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request the object updates service to undo discarding all changes to this item
|
||||||
|
*/
|
||||||
|
reinstate() {
|
||||||
|
this.objectUpdatesService.reinstateFieldUpdates(this.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether or not the object is currently reinstatable
|
||||||
|
*/
|
||||||
|
isReinstatable(): Observable<boolean> {
|
||||||
|
return this.objectUpdatesService.isReinstatable(this.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether or not there are currently updates for this object
|
||||||
|
*/
|
||||||
|
hasChanges(): Observable<boolean> {
|
||||||
|
return this.objectUpdatesService.hasUpdates(this.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get translated notification title
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
private getNotificationTitle(key: string) {
|
||||||
|
return this.translateService.instant(this.notificationsPrefix + key + '.title');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get translated notification content
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
private getNotificationContent(key: string) {
|
||||||
|
return this.translateService.instant(this.notificationsPrefix + key + '.content');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user