mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[CST-11178] show allowed correction types
This commit is contained in:
@@ -132,3 +132,13 @@ export const SUBSCRIPTIONS_MODULE_PATH = 'subscriptions';
|
|||||||
export function getSubscriptionsModuleRoute() {
|
export function getSubscriptionsModuleRoute() {
|
||||||
return `/${SUBSCRIPTIONS_MODULE_PATH}`;
|
return `/${SUBSCRIPTIONS_MODULE_PATH}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const EDIT_ITEM_PATH = 'edit-items';
|
||||||
|
export function getEditItemPageRoute() {
|
||||||
|
return `/${EDIT_ITEM_PATH}`;
|
||||||
|
}
|
||||||
|
export const CORRECTION_TYPE_PATH = 'corrections';
|
||||||
|
export function getCorrectionTypePageRoute(itemUuid: string, typeId: string) {
|
||||||
|
return `/items/${itemUuid}/${CORRECTION_TYPE_PATH}/${typeId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -185,6 +185,8 @@ import { FlatBrowseDefinition } from './shared/flat-browse-definition.model';
|
|||||||
import { ValueListBrowseDefinition } from './shared/value-list-browse-definition.model';
|
import { ValueListBrowseDefinition } from './shared/value-list-browse-definition.model';
|
||||||
import { NonHierarchicalBrowseDefinition } from './shared/non-hierarchical-browse-definition';
|
import { NonHierarchicalBrowseDefinition } from './shared/non-hierarchical-browse-definition';
|
||||||
import { BulkAccessConditionOptions } from './config/models/bulk-access-condition-options.model';
|
import { BulkAccessConditionOptions } from './config/models/bulk-access-condition-options.model';
|
||||||
|
import { CorrectionTypeMode } from './submission/models/correction-type-mode.model';
|
||||||
|
import { CorrectionTypeDataService } from './submission/correctiontype-data.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -308,6 +310,7 @@ const PROVIDERS = [
|
|||||||
OrcidQueueDataService,
|
OrcidQueueDataService,
|
||||||
OrcidHistoryDataService,
|
OrcidHistoryDataService,
|
||||||
SupervisionOrderDataService
|
SupervisionOrderDataService
|
||||||
|
CorrectionTypeDataService,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -387,6 +390,7 @@ export const models =
|
|||||||
Subscription,
|
Subscription,
|
||||||
ItemRequest,
|
ItemRequest,
|
||||||
BulkAccessConditionOptions
|
BulkAccessConditionOptions
|
||||||
|
CorrectionTypeMode
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
89
src/app/core/submission/correctiontype-data.service.ts
Normal file
89
src/app/core/submission/correctiontype-data.service.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { dataService } from '../data/base/data-service.decorator';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { IdentifiableDataService } from '../data/base/identifiable-data.service';
|
||||||
|
import { SearchDataImpl } from '../data/base/search-data';
|
||||||
|
import { CorrectionTypeMode } from './models/correction-type-mode.model';
|
||||||
|
import { Observable, map } from 'rxjs';
|
||||||
|
import { RemoteData } from '../data/remote-data';
|
||||||
|
import { PaginatedList } from '../data/paginated-list.model';
|
||||||
|
import { FindListOptions } from '../data/find-list-options.model';
|
||||||
|
import { RequestParam } from '../cache/models/request-param.model';
|
||||||
|
import { getAllSucceededRemoteDataPayload, getPaginatedListPayload } from '../shared/operators';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that provides methods to make REST requests with correctiontypes endpoint.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
@dataService(CorrectionTypeMode.type)
|
||||||
|
export class CorrectionTypeDataService extends IdentifiableDataService<CorrectionTypeMode> {
|
||||||
|
protected linkPath = 'correctiontypes';
|
||||||
|
protected searchByTopic = 'findByTopic';
|
||||||
|
protected searchFindByItem = 'findByItem';
|
||||||
|
private searchData: SearchDataImpl<CorrectionTypeMode>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
) {
|
||||||
|
super('correctiontypes', requestService, rdbService, objectCache, halService);
|
||||||
|
|
||||||
|
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the correction type by id
|
||||||
|
* @param id the id of the correction type
|
||||||
|
* @param useCachedVersionIfAvailable use the cached version if available
|
||||||
|
* @param reRequestOnStale re-request on stale
|
||||||
|
* @returns {Observable<RemoteData<CorrectionTypeMode>>} the correction type
|
||||||
|
*/
|
||||||
|
getCorrectionTypeById(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true): Observable<RemoteData<CorrectionTypeMode>> {
|
||||||
|
return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for the correction types for the item
|
||||||
|
* @param itemUuid the uuid of the item
|
||||||
|
* @param useCachedVersionIfAvailable use the cached version if available
|
||||||
|
* @returns the list of correction types for the item
|
||||||
|
*/
|
||||||
|
findByItem(itemUuid: string, useCachedVersionIfAvailable): Observable<RemoteData<PaginatedList<CorrectionTypeMode>>> {
|
||||||
|
const options = new FindListOptions();
|
||||||
|
options.searchParams = [new RequestParam('uuid', itemUuid)];
|
||||||
|
return this.searchData.searchBy(this.searchFindByItem, options, useCachedVersionIfAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the correction type for the topic
|
||||||
|
* @param topic the topic of the correction type to search for
|
||||||
|
* @param useCachedVersionIfAvailable use the cached version if available
|
||||||
|
* @param reRequestOnStale re-request on stale
|
||||||
|
* @returns the correction type for the topic
|
||||||
|
*/
|
||||||
|
findByTopic(topic: string, useCachedVersionIfAvailable = true, reRequestOnStale = true): Observable<CorrectionTypeMode> {
|
||||||
|
const options = new FindListOptions();
|
||||||
|
options.searchParams = [
|
||||||
|
{
|
||||||
|
fieldName: 'topic',
|
||||||
|
fieldValue: topic,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.searchData.searchBy(this.searchByTopic, options, useCachedVersionIfAvailable, reRequestOnStale).pipe(
|
||||||
|
getAllSucceededRemoteDataPayload(),
|
||||||
|
getPaginatedListPayload(),
|
||||||
|
map((list: CorrectionTypeMode[]) => {
|
||||||
|
return list[0];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
35
src/app/core/submission/models/correction-type-mode.model.ts
Normal file
35
src/app/core/submission/models/correction-type-mode.model.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { autoserialize, deserialize } from 'cerialize';
|
||||||
|
import { typedObject } from '../../cache/builders/build-decorators';
|
||||||
|
import { CacheableObject } from '../../cache/cacheable-object.model';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||||
|
import { HALLink } from '../../shared/hal-link.model';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
export class CorrectionTypeMode extends CacheableObject {
|
||||||
|
static type = new ResourceType('correctiontype');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object type
|
||||||
|
*/
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
topic: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
discoveryConfiguration: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
creationForm: string;
|
||||||
|
|
||||||
|
@deserialize
|
||||||
|
_links: {
|
||||||
|
self: HALLink;
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
<ng-container *ngIf="(isAvailable() | async)">
|
||||||
|
<button ngbDropdownItem
|
||||||
|
*ngFor="let type of (getCorrectionTypes() | async)"
|
||||||
|
[routerLink]="[getTypeRoute(type.id)]"
|
||||||
|
[innerHTML]="('context-menu.actions.correction-type.btn.' + type.id | translate)">
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
@@ -0,0 +1,116 @@
|
|||||||
|
import { Item } from './../../../core/shared/item.model';
|
||||||
|
import { DSpaceObject } from './../../../core/shared/dspace-object.model';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CorrectionTypeMenuComponent } from './correction-type-menu.component';
|
||||||
|
import { NotificationsServiceStub } from '../../testing/notifications-service.stub';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
|
||||||
|
import { createPaginatedList } from '../../testing/utils.test';
|
||||||
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { CorrectionTypeDataService } from '../../../core/submission/correctiontype-data.service';
|
||||||
|
import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { CorrectionTypeMode } from '../../../core/submission/models/correction-type-mode.model';
|
||||||
|
|
||||||
|
describe('CorrectionTypeMenuComponent', () => {
|
||||||
|
let component: CorrectionTypeMenuComponent;
|
||||||
|
let fixture: ComponentFixture<CorrectionTypeMenuComponent>;
|
||||||
|
let componentAsAny: any;
|
||||||
|
|
||||||
|
let correctionTypeService: any;
|
||||||
|
let dso: DSpaceObject;
|
||||||
|
const notificationService = new NotificationsServiceStub();
|
||||||
|
const correctionType: CorrectionTypeMode = Object.assign(new CorrectionTypeMode(), {
|
||||||
|
id: 'addpersonalpath',
|
||||||
|
creationForm:'manageRelation',
|
||||||
|
discoveryConfiguration: 'RELATION.PersonPath.Items',
|
||||||
|
topic: '/DSPACEUSERS/RELATIONADD/PERSONALPATH'
|
||||||
|
});
|
||||||
|
|
||||||
|
const correctionTypeObjRDList$ = createSuccessfulRemoteDataObject$(createPaginatedList([correctionType]));
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
dso = Object.assign(new Item(), {
|
||||||
|
id: 'test-item',
|
||||||
|
_links: {
|
||||||
|
self: { href: 'test-item-selflink' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
correctionTypeService = jasmine.createSpyObj('CorrectionTypeDataService', {
|
||||||
|
findByItem: jasmine.createSpy('findByItem')
|
||||||
|
});
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ CorrectionTypeMenuComponent ],
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useClass: TranslateLoaderMock
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RouterTestingModule.withRoutes([])],
|
||||||
|
providers: [
|
||||||
|
{ provide: CorrectionTypeDataService, useValue: correctionTypeService },
|
||||||
|
{ provide: 'contextMenuObjectProvider', useValue: dso },
|
||||||
|
{ provide: 'contextMenuObjectTypeProvider', useValue: DSpaceObjectType.ITEM },
|
||||||
|
{ provide: NotificationsService, useValue: notificationService }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CorrectionTypeMenuComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when correction types are available', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
correctionTypeService.findByItem.and.returnValue(correctionTypeObjRDList$);
|
||||||
|
fixture = TestBed.createComponent(CorrectionTypeMenuComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
componentAsAny = fixture.componentInstance;
|
||||||
|
component.contextMenuObject = dso;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should init properly', () => {
|
||||||
|
expect(componentAsAny.correctionTypes$.value).toEqual([correctionType]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a button', () => {
|
||||||
|
const link = fixture.debugElement.query(By.css('button'));
|
||||||
|
expect(link).not.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when is no data are available', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
correctionTypeService.findByItem.and.returnValue(createSuccessfulRemoteDataObject$(createPaginatedList([])));
|
||||||
|
fixture = TestBed.createComponent(CorrectionTypeMenuComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
componentAsAny = fixture.componentInstance;
|
||||||
|
component.contextMenuObject = dso;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should init edit mode properly', () => {
|
||||||
|
expect(componentAsAny.correctionTypes$.value).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render a button', () => {
|
||||||
|
const link = fixture.debugElement.query(By.css('button'));
|
||||||
|
expect(link).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,105 @@
|
|||||||
|
import { getAllSucceededRemoteDataPayload, getPaginatedListPayload } from './../../../core/shared/operators';
|
||||||
|
import { CorrectionTypeDataService } from './../../../core/submission/correctiontype-data.service';
|
||||||
|
import { DSpaceObject } from './../../../core/shared/dspace-object.model';
|
||||||
|
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import { ContextMenuEntryComponent } from '../context-menu-entry.component';
|
||||||
|
import { ContextMenuEntryType } from '../context-menu-entry-type';
|
||||||
|
import { BehaviorSubject, Observable, Subscription, map, startWith, tap } from 'rxjs';
|
||||||
|
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { CorrectionTypeMode } from '../../../core/submission/models/correction-type-mode.model';
|
||||||
|
import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model';
|
||||||
|
import { NotificationsService } from '../../notifications/notifications.service';
|
||||||
|
import { hasValue, isNotEmpty } from '../../empty.util';
|
||||||
|
import { rendersContextMenuEntriesForType } from '../context-menu.decorator';
|
||||||
|
import { getCorrectionTypePageRoute } from '../../../app-routing-paths';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-correction-type-menu',
|
||||||
|
templateUrl: './correction-type-menu.component.html',
|
||||||
|
})
|
||||||
|
@rendersContextMenuEntriesForType(DSpaceObjectType.ITEM)
|
||||||
|
export class CorrectionTypeMenuComponent extends ContextMenuEntryComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The menu entry type
|
||||||
|
*/
|
||||||
|
public static menuEntryType: ContextMenuEntryType = ContextMenuEntryType.CorrectionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if a request operation is pending
|
||||||
|
* @type {BehaviorSubject<boolean>}
|
||||||
|
*/
|
||||||
|
public processing$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to NgbModal
|
||||||
|
*/
|
||||||
|
public modalRef: NgbModalRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of Edit Modes available on this item
|
||||||
|
* for the current user
|
||||||
|
*/
|
||||||
|
private correctionTypes$: BehaviorSubject<CorrectionTypeMode[]> = new BehaviorSubject<CorrectionTypeMode[]>([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable to track subscription and unsubscribe it onDestroy
|
||||||
|
*/
|
||||||
|
private sub: Subscription;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject('contextMenuObjectProvider') protected injectedContextMenuObject: DSpaceObject,
|
||||||
|
@Inject('contextMenuObjectTypeProvider') protected injectedContextMenuObjectType: DSpaceObjectType,
|
||||||
|
private correctionTypeService: CorrectionTypeDataService,
|
||||||
|
public notificationService: NotificationsService
|
||||||
|
) {
|
||||||
|
super(injectedContextMenuObject, injectedContextMenuObjectType, ContextMenuEntryType.EditSubmission);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.notificationService.claimedProfile.subscribe(() => {
|
||||||
|
this.getData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if edit mode is available
|
||||||
|
*/
|
||||||
|
getCorrectionTypes(): Observable<CorrectionTypeMode[]> {
|
||||||
|
return this.correctionTypes$;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if edit mode is available
|
||||||
|
*/
|
||||||
|
isAvailable(): Observable<boolean> {
|
||||||
|
return this.correctionTypes$.asObservable().pipe(
|
||||||
|
map((type) => isNotEmpty(type) && type.length > 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): void {
|
||||||
|
this.sub = this.correctionTypeService.findByItem(this.contextMenuObject.id, true).pipe(
|
||||||
|
tap((types) => console.log(types)),
|
||||||
|
getAllSucceededRemoteDataPayload(),
|
||||||
|
getPaginatedListPayload(),
|
||||||
|
startWith([])
|
||||||
|
).subscribe((types: CorrectionTypeMode[]) => {
|
||||||
|
console.log(types);
|
||||||
|
this.correctionTypes$.next(types);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTypeRoute(id: string) {
|
||||||
|
return getCorrectionTypePageRoute(this.contextMenuObject.id, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the subscription is unsubscribed from when this component is destroyed
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (hasValue(this.sub)) {
|
||||||
|
this.sub.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user