mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-10 19:43:04 +00:00
refactor, fix tests
This commit is contained in:
@@ -1 +1 @@
|
|||||||
<ds-suggestion-target [source]="'openaire'"></ds-suggestion-target>
|
<ds-publication-claim [source]="'openaire'"></ds-publication-claim>
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-publication-claim-page.component';
|
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page.component';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
describe('AdminNotificationsSuggestionTargetsPageComponent', () => {
|
describe('AdminNotificationsPublicationClaimPageComponent', () => {
|
||||||
let component: AdminNotificationsSuggestionTargetsPageComponent;
|
let component: AdminNotificationsPublicationClaimPageComponent;
|
||||||
let fixture: ComponentFixture<AdminNotificationsSuggestionTargetsPageComponent>;
|
let fixture: ComponentFixture<AdminNotificationsPublicationClaimPageComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@@ -16,10 +16,10 @@ describe('AdminNotificationsSuggestionTargetsPageComponent', () => {
|
|||||||
TranslateModule.forRoot()
|
TranslateModule.forRoot()
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AdminNotificationsSuggestionTargetsPageComponent
|
AdminNotificationsPublicationClaimPageComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AdminNotificationsSuggestionTargetsPageComponent
|
AdminNotificationsPublicationClaimPageComponent
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
})
|
})
|
||||||
@@ -27,7 +27,7 @@ describe('AdminNotificationsSuggestionTargetsPageComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(AdminNotificationsSuggestionTargetsPageComponent);
|
fixture = TestBed.createComponent(AdminNotificationsPublicationClaimPageComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
@@ -5,6 +5,6 @@ import { Component } from '@angular/core';
|
|||||||
templateUrl: './admin-notifications-publication-claim-page.component.html',
|
templateUrl: './admin-notifications-publication-claim-page.component.html',
|
||||||
styleUrls: ['./admin-notifications-publication-claim-page.component.scss']
|
styleUrls: ['./admin-notifications-publication-claim-page.component.scss']
|
||||||
})
|
})
|
||||||
export class AdminNotificationsSuggestionTargetsPageComponent {
|
export class AdminNotificationsPublicationClaimPageComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ import { AuthenticatedGuard } from '../../core/auth/authenticated.guard';
|
|||||||
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
|
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||||
import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service';
|
import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service';
|
||||||
import { PUBLICATION_CLAIMS_PATH } from './admin-notifications-routing-paths';
|
import { PUBLICATION_CLAIMS_PATH } from './admin-notifications-routing-paths';
|
||||||
import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
|
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
|
||||||
import { AdminNotificationsPublicationClaimPageResolver } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page-resolver.service';
|
import { AdminNotificationsPublicationClaimPageResolver } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page-resolver.service';
|
||||||
import { QUALITY_ASSURANCE_EDIT_PATH } from './admin-notifications-routing-paths';
|
import { QUALITY_ASSURANCE_EDIT_PATH } from './admin-notifications-routing-paths';
|
||||||
import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
|
import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
|
||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
{
|
{
|
||||||
canActivate: [ AuthenticatedGuard ],
|
canActivate: [ AuthenticatedGuard ],
|
||||||
path: `${PUBLICATION_CLAIMS_PATH}`,
|
path: `${PUBLICATION_CLAIMS_PATH}`,
|
||||||
component: AdminNotificationsSuggestionTargetsPageComponent,
|
component: AdminNotificationsPublicationClaimPageComponent,
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
resolve: {
|
resolve: {
|
||||||
breadcrumb: I18nBreadcrumbResolver,
|
breadcrumb: I18nBreadcrumbResolver,
|
||||||
|
@@ -3,7 +3,7 @@ import { NgModule } from '@angular/core';
|
|||||||
import { CoreModule } from '../../core/core.module';
|
import { CoreModule } from '../../core/core.module';
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module';
|
import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module';
|
||||||
import { AdminNotificationsSuggestionTargetsPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
|
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
|
||||||
import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
|
import { AdminQualityAssuranceTopicsPageComponent } from './admin-quality-assurance-topics-page/admin-quality-assurance-topics-page.component';
|
||||||
import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component';
|
import { AdminQualityAssuranceEventsPageComponent } from './admin-quality-assurance-events-page/admin-quality-assurance-events-page.component';
|
||||||
import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component';
|
import { AdminQualityAssuranceSourcePageComponent } from './admin-quality-assurance-source-page-component/admin-quality-assurance-source-page.component';
|
||||||
@@ -18,7 +18,7 @@ import { NotificationsModule } from '../../notifications/notifications.module';
|
|||||||
NotificationsModule
|
NotificationsModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AdminNotificationsSuggestionTargetsPageComponent,
|
AdminNotificationsPublicationClaimPageComponent,
|
||||||
AdminQualityAssuranceTopicsPageComponent,
|
AdminQualityAssuranceTopicsPageComponent,
|
||||||
AdminQualityAssuranceEventsPageComponent,
|
AdminQualityAssuranceEventsPageComponent,
|
||||||
AdminQualityAssuranceSourcePageComponent
|
AdminQualityAssuranceSourcePageComponent
|
||||||
|
@@ -29,11 +29,11 @@ export const EMBED_SEPARATOR = '%2F';
|
|||||||
/**
|
/**
|
||||||
* Common functionality for data services.
|
* Common functionality for data services.
|
||||||
* Specific functionality that not all services would need
|
* Specific functionality that not all services would need
|
||||||
* is implemented in "DataService feature" classes (e.g. {@link CreateData}
|
* is implemented in "UpdateDataServiceImpl feature" classes (e.g. {@link CreateData}
|
||||||
*
|
*
|
||||||
* All DataService (or DataService feature) classes must
|
* All UpdateDataServiceImpl (or UpdateDataServiceImpl feature) classes must
|
||||||
* - extend this class (or {@link IdentifiableDataService})
|
* - extend this class (or {@link IdentifiableDataService})
|
||||||
* - implement any DataService features it requires in order to forward calls to it
|
* - implement any UpdateDataServiceImpl features it requires in order to forward calls to it
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* export class SomeDataService extends BaseDataService<Something> implements CreateData<Something>, SearchData<Something> {
|
* export class SomeDataService extends BaseDataService<Something> implements CreateData<Something>, SearchData<Something> {
|
||||||
@@ -385,7 +385,7 @@ export class BaseDataService<T extends CacheableObject> implements HALDataServic
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the links to traverse from the root of the api to the
|
* Return the links to traverse from the root of the api to the
|
||||||
* endpoint this DataService represents
|
* endpoint this UpdateDataServiceImpl represents
|
||||||
*
|
*
|
||||||
* e.g. if the api root links to 'foo', and the endpoint at 'foo'
|
* e.g. if the api root links to 'foo', and the endpoint at 'foo'
|
||||||
* links to 'bar' the linkPath for the BarDataService would be
|
* links to 'bar' the linkPath for the BarDataService would be
|
||||||
|
@@ -37,7 +37,7 @@ export interface CreateData<T extends CacheableObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService feature to create objects.
|
* A UpdateDataServiceImpl feature to create objects.
|
||||||
*
|
*
|
||||||
* Concrete data services can use this feature by implementing {@link CreateData}
|
* Concrete data services can use this feature by implementing {@link CreateData}
|
||||||
* and delegating its method to an inner instance of this class.
|
* and delegating its method to an inner instance of this class.
|
||||||
|
@@ -42,7 +42,7 @@ export interface FindAllData<T extends CacheableObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService feature to list all objects.
|
* A UpdateDataServiceImpl feature to list all objects.
|
||||||
*
|
*
|
||||||
* Concrete data services can use this feature by implementing {@link FindAllData}
|
* Concrete data services can use this feature by implementing {@link FindAllData}
|
||||||
* and delegating its method to an inner instance of this class.
|
* and delegating its method to an inner instance of this class.
|
||||||
|
@@ -54,7 +54,7 @@ export interface PatchData<T extends CacheableObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService feature to patch and update objects.
|
* A UpdateDataServiceImpl feature to patch and update objects.
|
||||||
*
|
*
|
||||||
* Concrete data services can use this feature by implementing {@link PatchData}
|
* Concrete data services can use this feature by implementing {@link PatchData}
|
||||||
* and delegating its method to an inner instance of this class.
|
* and delegating its method to an inner instance of this class.
|
||||||
|
@@ -31,7 +31,7 @@ export interface PutData<T extends CacheableObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService feature to send PUT requests.
|
* A UpdateDataServiceImpl feature to send PUT requests.
|
||||||
*
|
*
|
||||||
* Concrete data services can use this feature by implementing {@link PutData}
|
* Concrete data services can use this feature by implementing {@link PutData}
|
||||||
* and delegating its method to an inner instance of this class.
|
* and delegating its method to an inner instance of this class.
|
||||||
|
@@ -51,7 +51,7 @@ export interface SearchData<T extends CacheableObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService feature to search for objects.
|
* A UpdateDataServiceImpl feature to search for objects.
|
||||||
*
|
*
|
||||||
* Concrete data services can use this feature by implementing {@link SearchData}
|
* Concrete data services can use this feature by implementing {@link SearchData}
|
||||||
* and delegating its method to an inner instance of this class.
|
* and delegating its method to an inner instance of this class.
|
||||||
|
@@ -17,8 +17,8 @@ import { HALDataService } from './base/hal-data-service.interface';
|
|||||||
import { dataService } from './base/data-service.decorator';
|
import { dataService } from './base/data-service.decorator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DataService with only findByHref methods. Its purpose is to be used for resources that don't
|
* A UpdateDataServiceImpl with only findByHref methods. Its purpose is to be used for resources that don't
|
||||||
* need to be retrieved by ID, or have any way to update them, but require a DataService in order
|
* need to be retrieved by ID, or have any way to update them, but require a UpdateDataServiceImpl in order
|
||||||
* for their links to be resolved by the LinkService.
|
* for their links to be resolved by the LinkService.
|
||||||
*
|
*
|
||||||
* an @dataService annotation can be added for any number of these resource types
|
* an @dataService annotation can be added for any number of these resource types
|
||||||
|
@@ -42,45 +42,60 @@ import {
|
|||||||
} from './request.models';
|
} from './request.models';
|
||||||
import { RequestService } from './request.service';
|
import { RequestService } from './request.service';
|
||||||
import { RestRequestMethod } from './rest-request-method';
|
import { RestRequestMethod } from './rest-request-method';
|
||||||
import { UpdateDataService } from './update-data.service';
|
|
||||||
import { GenericConstructor } from '../shared/generic-constructor';
|
import { GenericConstructor } from '../shared/generic-constructor';
|
||||||
import { NoContent } from '../shared/NoContent.model';
|
import { NoContent } from '../shared/NoContent.model';
|
||||||
import { CacheableObject } from '../cache/cacheable-object.model';
|
import { CacheableObject } from '../cache/cacheable-object.model';
|
||||||
import { CoreState } from '../core-state.model';
|
import { CoreState } from '../core-state.model';
|
||||||
import { FindListOptions } from './find-list-options.model';
|
import { FindListOptions } from './find-list-options.model';
|
||||||
|
import { BaseDataService } from "./base/base-data.service";
|
||||||
|
import { FindAllData, FindAllDataImpl } from "./base/find-all-data";
|
||||||
|
import { SearchData, SearchDataImpl } from "./base/search-data";
|
||||||
|
import { CreateData, CreateDataImpl } from "./base/create-data";
|
||||||
|
|
||||||
export abstract class DataService<T extends CacheableObject> implements UpdateDataService<T> {
|
export interface UpdateDataService<T> {
|
||||||
protected abstract requestService: RequestService;
|
patch(dso: T, operations: Operation[]): Observable<RemoteData<T>>;
|
||||||
protected abstract rdbService: RemoteDataBuildService;
|
update(object: T): Observable<RemoteData<T>>;
|
||||||
|
commitUpdates(method?: RestRequestMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specific functionalities that not all services would need.
|
||||||
|
* Goal of the class is to update remote objects, handling custom methods that don't belong to BaseDataService
|
||||||
|
*
|
||||||
|
* Custom methods are:
|
||||||
|
*
|
||||||
|
* patch - Sends a patch request to modify current object
|
||||||
|
* update - Add a new patch to the object cache, diff between given object and cache
|
||||||
|
* commitUpdates - Sends the updates to the server
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
export abstract class UpdateDataServiceImpl<T extends CacheableObject> extends BaseDataService<T> implements UpdateDataService<T>, FindAllData<T>, SearchData<T>, CreateData<T> {
|
||||||
protected abstract store: Store<CoreState>;
|
protected abstract store: Store<CoreState>;
|
||||||
protected abstract linkPath: string;
|
|
||||||
protected abstract halService: HALEndpointService;
|
|
||||||
protected abstract objectCache: ObjectCacheService;
|
|
||||||
protected abstract notificationsService: NotificationsService;
|
|
||||||
protected abstract http: HttpClient;
|
protected abstract http: HttpClient;
|
||||||
protected abstract comparator: ChangeAnalyzer<T>;
|
protected abstract comparator: ChangeAnalyzer<T>;
|
||||||
|
|
||||||
/**
|
private findAllData: FindAllDataImpl<T>;
|
||||||
* Allows subclasses to reset the response cache time.
|
private searchData: SearchDataImpl<T>;
|
||||||
*/
|
private createData: CreateData<T>;
|
||||||
protected responseMsToLive: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the endpoint for browsing
|
constructor(
|
||||||
* @param options The [[FindListOptions]] object
|
protected linkPath: string,
|
||||||
* @param linkPath The link path for the object
|
protected requestService: RequestService,
|
||||||
* @returns {Observable<string>}
|
protected rdbService: RemoteDataBuildService,
|
||||||
*/
|
protected objectCache: ObjectCacheService,
|
||||||
getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable<string> {
|
protected halService: HALEndpointService,
|
||||||
return this.getEndpoint();
|
protected notificationsService: NotificationsService,
|
||||||
|
protected responseMsToLive: number,
|
||||||
|
) {
|
||||||
|
super(linkPath, requestService, rdbService, objectCache, halService, responseMsToLive);
|
||||||
|
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||||
|
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService ,this.responseMsToLive);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the base endpoint for all requests
|
|
||||||
*/
|
|
||||||
protected getEndpoint(): Observable<string> {
|
|
||||||
return this.halService.getEndpoint(this.linkPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the HREF with given options object
|
* Create the HREF with given options object
|
||||||
@@ -92,16 +107,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||||
*/
|
*/
|
||||||
public getFindAllHref(options: FindListOptions = {}, linkPath?: string, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
public getFindAllHref(options: FindListOptions = {}, linkPath?: string, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
||||||
let endpoint$: Observable<string>;
|
return this.findAllData.getFindAllHref(options, linkPath, ...linksToFollow)
|
||||||
const args = [];
|
|
||||||
|
|
||||||
endpoint$ = this.getBrowseEndpoint(options).pipe(
|
|
||||||
filter((href: string) => isNotEmpty(href)),
|
|
||||||
map((href: string) => isNotEmpty(linkPath) ? `${href}/${linkPath}` : href),
|
|
||||||
distinctUntilChanged()
|
|
||||||
);
|
|
||||||
|
|
||||||
return endpoint$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args, ...linksToFollow)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,149 +120,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||||
*/
|
*/
|
||||||
public getSearchByHref(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
public getSearchByHref(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
||||||
let result$: Observable<string>;
|
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow)
|
||||||
const args = [];
|
|
||||||
|
|
||||||
result$ = this.getSearchEndpoint(searchMethod);
|
|
||||||
|
|
||||||
return result$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args, ...linksToFollow)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn an options object into a query string and combine it with the given HREF
|
|
||||||
*
|
|
||||||
* @param href The HREF to which the query string should be appended
|
|
||||||
* @param options The [[FindListOptions]] object
|
|
||||||
* @param extraArgs Array with additional params to combine with query string
|
|
||||||
* @return {Observable<string>}
|
|
||||||
* Return an observable that emits created HREF
|
|
||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
|
||||||
*/
|
|
||||||
public buildHrefFromFindOptions(href: string, options: FindListOptions, extraArgs: string[] = [], ...linksToFollow: FollowLinkConfig<T>[]): string {
|
|
||||||
let args = [...extraArgs];
|
|
||||||
|
|
||||||
if (hasValue(options.currentPage) && typeof options.currentPage === 'number') {
|
|
||||||
/* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */
|
|
||||||
args = this.addHrefArg(href, args, `page=${options.currentPage - 1}`);
|
|
||||||
}
|
|
||||||
if (hasValue(options.elementsPerPage)) {
|
|
||||||
args = this.addHrefArg(href, args, `size=${options.elementsPerPage}`);
|
|
||||||
}
|
|
||||||
if (hasValue(options.sort)) {
|
|
||||||
args = this.addHrefArg(href, args, `sort=${options.sort.field},${options.sort.direction}`);
|
|
||||||
}
|
|
||||||
if (hasValue(options.startsWith)) {
|
|
||||||
args = this.addHrefArg(href, args, `startsWith=${options.startsWith}`);
|
|
||||||
}
|
|
||||||
if (hasValue(options.searchParams)) {
|
|
||||||
options.searchParams.forEach((param: RequestParam) => {
|
|
||||||
args = this.addHrefArg(href, args, `${param.fieldName}=${param.fieldValue}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
args = this.addEmbedParams(href, args, ...linksToFollow);
|
|
||||||
if (isNotEmpty(args)) {
|
|
||||||
return new URLCombiner(href, `?${args.join('&')}`).toString();
|
|
||||||
} else {
|
|
||||||
return href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn an array of RequestParam into a query string and combine it with the given HREF
|
|
||||||
*
|
|
||||||
* @param href The HREF to which the query string should be appended
|
|
||||||
* @param params Array with additional params to combine with query string
|
|
||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
|
||||||
*
|
|
||||||
* @return {Observable<string>}
|
|
||||||
* Return an observable that emits created HREF
|
|
||||||
*/
|
|
||||||
buildHrefWithParams(href: string, params: RequestParam[], ...linksToFollow: FollowLinkConfig<T>[]): string {
|
|
||||||
|
|
||||||
let args = [];
|
|
||||||
if (hasValue(params)) {
|
|
||||||
params.forEach((param: RequestParam) => {
|
|
||||||
args = this.addHrefArg(href, args, `${param.fieldName}=${param.fieldValue}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
args = this.addEmbedParams(href, args, ...linksToFollow);
|
|
||||||
|
|
||||||
if (isNotEmpty(args)) {
|
|
||||||
return new URLCombiner(href, `?${args.join('&')}`).toString();
|
|
||||||
} else {
|
|
||||||
return href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Adds the embed options to the link for the request
|
|
||||||
* @param href The href the params are to be added to
|
|
||||||
* @param args params for the query string
|
|
||||||
* @param linksToFollow links we want to embed in query string if shouldEmbed is true
|
|
||||||
*/
|
|
||||||
protected addEmbedParams(href: string, args: string[], ...linksToFollow: FollowLinkConfig<T>[]) {
|
|
||||||
linksToFollow.forEach((linkToFollow: FollowLinkConfig<T>) => {
|
|
||||||
if (hasValue(linkToFollow) && linkToFollow.shouldEmbed) {
|
|
||||||
const embedString = 'embed=' + String(linkToFollow.name);
|
|
||||||
// Add the embeds size if given in the FollowLinkConfig.FindListOptions
|
|
||||||
if (hasValue(linkToFollow.findListOptions) && hasValue(linkToFollow.findListOptions.elementsPerPage)) {
|
|
||||||
args = this.addHrefArg(href, args,
|
|
||||||
'embed.size=' + String(linkToFollow.name) + '=' + linkToFollow.findListOptions.elementsPerPage);
|
|
||||||
}
|
|
||||||
// Adds the nested embeds and their size if given
|
|
||||||
if (isNotEmpty(linkToFollow.linksToFollow)) {
|
|
||||||
args = this.addNestedEmbeds(embedString, href, args, ...linkToFollow.linksToFollow);
|
|
||||||
} else {
|
|
||||||
args = this.addHrefArg(href, args, embedString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new argument to the list of arguments, only if it doesn't already exist in the given href,
|
|
||||||
* or the current list of arguments
|
|
||||||
*
|
|
||||||
* @param href The href the arguments are to be added to
|
|
||||||
* @param currentArgs The current list of arguments
|
|
||||||
* @param newArg The new argument to add
|
|
||||||
* @return The next list of arguments, with newArg included if it wasn't already.
|
|
||||||
* Note this function will not modify any of the input params.
|
|
||||||
*/
|
|
||||||
protected addHrefArg(href: string, currentArgs: string[], newArg: string): string[] {
|
|
||||||
if (href.includes(newArg) || currentArgs.includes(newArg)) {
|
|
||||||
return [...currentArgs];
|
|
||||||
} else {
|
|
||||||
return [...currentArgs, newArg];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the nested followLinks to the embed param, separated by a /, and their sizes, recursively
|
|
||||||
* @param embedString embedString so far (recursive)
|
|
||||||
* @param href The href the params are to be added to
|
|
||||||
* @param args params for the query string
|
|
||||||
* @param linksToFollow links we want to embed in query string if shouldEmbed is true
|
|
||||||
*/
|
|
||||||
protected addNestedEmbeds(embedString: string, href: string, args: string[], ...linksToFollow: FollowLinkConfig<T>[]): string[] {
|
|
||||||
let nestEmbed = embedString;
|
|
||||||
linksToFollow.forEach((linkToFollow: FollowLinkConfig<T>) => {
|
|
||||||
if (hasValue(linkToFollow) && linkToFollow.shouldEmbed) {
|
|
||||||
nestEmbed = nestEmbed + '/' + String(linkToFollow.name);
|
|
||||||
// Add the nested embeds size if given in the FollowLinkConfig.FindListOptions
|
|
||||||
if (hasValue(linkToFollow.findListOptions) && hasValue(linkToFollow.findListOptions.elementsPerPage)) {
|
|
||||||
const nestedEmbedSize = 'embed.size=' + nestEmbed.split('=')[1] + '=' + linkToFollow.findListOptions.elementsPerPage;
|
|
||||||
args = this.addHrefArg(href, args, nestedEmbedSize);
|
|
||||||
}
|
|
||||||
if (hasValue(linkToFollow.linksToFollow) && isNotEmpty(linkToFollow.linksToFollow)) {
|
|
||||||
args = this.addNestedEmbeds(nestEmbed, href, args, ...linkToFollow.linksToFollow);
|
|
||||||
} else {
|
|
||||||
args = this.addHrefArg(href, args, nestEmbed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,7 +138,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
* Return an observable that emits object list
|
* Return an observable that emits object list
|
||||||
*/
|
*/
|
||||||
findAll(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
findAll(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
||||||
return this.findAllByHref(this.getFindAllHref(options), options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -337,118 +201,6 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable of {@link RemoteData} of an object, based on an href, with a list of
|
|
||||||
* {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object
|
|
||||||
* @param href$ The url of object we want to retrieve. Can be a string or
|
|
||||||
* an Observable<string>
|
|
||||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
|
||||||
* no valid cached version. Defaults to true
|
|
||||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
|
||||||
* requested after the response becomes stale
|
|
||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
|
||||||
* {@link HALLink}s should be automatically resolved
|
|
||||||
*/
|
|
||||||
findByHref(href$: string | Observable<string>, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<T>> {
|
|
||||||
if (typeof href$ === 'string') {
|
|
||||||
href$ = observableOf(href$);
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestHref$ = href$.pipe(
|
|
||||||
isNotEmptyOperator(),
|
|
||||||
take(1),
|
|
||||||
map((href: string) => this.buildHrefFromFindOptions(href, {}, [], ...linksToFollow))
|
|
||||||
);
|
|
||||||
|
|
||||||
this.createAndSendGetRequest(requestHref$, useCachedVersionIfAvailable);
|
|
||||||
|
|
||||||
return this.rdbService.buildSingle<T>(requestHref$, ...linksToFollow).pipe(
|
|
||||||
// This skip ensures that if a stale object is present in the cache when you do a
|
|
||||||
// call it isn't immediately returned, but we wait until the remote data for the new request
|
|
||||||
// is created. If useCachedVersionIfAvailable is false it also ensures you don't get a
|
|
||||||
// cached completed object
|
|
||||||
skipWhile((rd: RemoteData<T>) => useCachedVersionIfAvailable ? rd.isStale : rd.hasCompleted),
|
|
||||||
this.reRequestStaleRemoteData(reRequestOnStale, () =>
|
|
||||||
this.findByHref(href$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list
|
|
||||||
* of {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object
|
|
||||||
* @param href$ The url of object we want to retrieve. Can be a string or
|
|
||||||
* an Observable<string>
|
|
||||||
* @param findListOptions Find list options object
|
|
||||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
|
||||||
* no valid cached version. Defaults to true
|
|
||||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
|
||||||
* requested after the response becomes stale
|
|
||||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
|
||||||
* {@link HALLink}s should be automatically resolved
|
|
||||||
*/
|
|
||||||
findAllByHref(href$: string | Observable<string>, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
|
||||||
if (typeof href$ === 'string') {
|
|
||||||
href$ = observableOf(href$);
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestHref$ = href$.pipe(
|
|
||||||
isNotEmptyOperator(),
|
|
||||||
take(1),
|
|
||||||
map((href: string) => this.buildHrefFromFindOptions(href, findListOptions, [], ...linksToFollow))
|
|
||||||
);
|
|
||||||
|
|
||||||
this.createAndSendGetRequest(requestHref$, useCachedVersionIfAvailable);
|
|
||||||
|
|
||||||
return this.rdbService.buildList<T>(requestHref$, ...linksToFollow).pipe(
|
|
||||||
// This skip ensures that if a stale object is present in the cache when you do a
|
|
||||||
// call it isn't immediately returned, but we wait until the remote data for the new request
|
|
||||||
// is created. If useCachedVersionIfAvailable is false it also ensures you don't get a
|
|
||||||
// cached completed object
|
|
||||||
skipWhile((rd: RemoteData<PaginatedList<T>>) => useCachedVersionIfAvailable ? rd.isStale : rd.hasCompleted),
|
|
||||||
this.reRequestStaleRemoteData(reRequestOnStale, () =>
|
|
||||||
this.findAllByHref(href$, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a GET request for the given href, and send it.
|
|
||||||
*
|
|
||||||
* @param href$ The url of object we want to retrieve. Can be a string or
|
|
||||||
* an Observable<string>
|
|
||||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
|
||||||
* no valid cached version. Defaults to true
|
|
||||||
*/
|
|
||||||
protected createAndSendGetRequest(href$: string | Observable<string>, useCachedVersionIfAvailable = true): void {
|
|
||||||
if (isNotEmpty(href$)) {
|
|
||||||
if (typeof href$ === 'string') {
|
|
||||||
href$ = observableOf(href$);
|
|
||||||
}
|
|
||||||
|
|
||||||
href$.pipe(
|
|
||||||
isNotEmptyOperator(),
|
|
||||||
take(1)
|
|
||||||
).subscribe((href: string) => {
|
|
||||||
const requestId = this.requestService.generateRequestId();
|
|
||||||
const request = new GetRequest(requestId, href);
|
|
||||||
if (hasValue(this.responseMsToLive)) {
|
|
||||||
request.responseMsToLive = this.responseMsToLive;
|
|
||||||
}
|
|
||||||
this.requestService.send(request, useCachedVersionIfAvailable);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return object search endpoint by given search method
|
|
||||||
*
|
|
||||||
* @param searchMethod The search method for the object
|
|
||||||
*/
|
|
||||||
protected getSearchEndpoint(searchMethod: string): Observable<string> {
|
|
||||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
|
||||||
filter((href: string) => isNotEmpty(href)),
|
|
||||||
map((href: string) => `${href}/search/${searchMethod}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a new FindListRequest with given search method
|
* Make a new FindListRequest with given search method
|
||||||
*
|
*
|
||||||
@@ -464,9 +216,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
* Return an observable that emits response from the server
|
* Return an observable that emits response from the server
|
||||||
*/
|
*/
|
||||||
searchBy(searchMethod: string, options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
searchBy(searchMethod: string, options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
||||||
const hrefObs = this.getSearchByHref(searchMethod, options, ...linksToFollow);
|
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow)
|
||||||
|
|
||||||
return this.findAllByHref(hrefObs, undefined, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -548,38 +298,7 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
* Array with additional params to combine with query string
|
* Array with additional params to combine with query string
|
||||||
*/
|
*/
|
||||||
create(object: T, ...params: RequestParam[]): Observable<RemoteData<T>> {
|
create(object: T, ...params: RequestParam[]): Observable<RemoteData<T>> {
|
||||||
const requestId = this.requestService.generateRequestId();
|
return this.createData.create(object, ...params)
|
||||||
const endpoint$ = this.getEndpoint().pipe(
|
|
||||||
isNotEmptyOperator(),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
map((endpoint: string) => this.buildHrefWithParams(endpoint, params))
|
|
||||||
);
|
|
||||||
|
|
||||||
const serializedObject = new DSpaceSerializer(getClassForType(object.type)).serialize(object);
|
|
||||||
|
|
||||||
endpoint$.pipe(
|
|
||||||
take(1)
|
|
||||||
).subscribe((endpoint: string) => {
|
|
||||||
const request = new CreateRequest(requestId, endpoint, JSON.stringify(serializedObject));
|
|
||||||
if (hasValue(this.responseMsToLive)) {
|
|
||||||
request.responseMsToLive = this.responseMsToLive;
|
|
||||||
}
|
|
||||||
this.requestService.send(request);
|
|
||||||
});
|
|
||||||
|
|
||||||
const result$ = this.rdbService.buildFromRequestUUID<T>(requestId);
|
|
||||||
|
|
||||||
// TODO a dataservice is not the best place to show a notification,
|
|
||||||
// this should move up to the components that use this method
|
|
||||||
result$.pipe(
|
|
||||||
takeWhile((rd: RemoteData<T>) => rd.isLoading, true)
|
|
||||||
).subscribe((rd: RemoteData<T>) => {
|
|
||||||
if (rd.hasFailed) {
|
|
||||||
this.notificationsService.error('Server Error:', rd.errorMessage, new NotificationOptions(-1));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result$;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -732,16 +451,4 @@ export abstract class DataService<T extends CacheableObject> implements UpdateDa
|
|||||||
commitUpdates(method?: RestRequestMethod) {
|
commitUpdates(method?: RestRequestMethod) {
|
||||||
this.requestService.commit(method);
|
this.requestService.commit(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the links to traverse from the root of the api to the
|
|
||||||
* endpoint this DataService represents
|
|
||||||
*
|
|
||||||
* e.g. if the api root links to 'foo', and the endpoint at 'foo'
|
|
||||||
* links to 'bar' the linkPath for the BarDataService would be
|
|
||||||
* 'foo/bar'
|
|
||||||
*/
|
|
||||||
getLinkPath(): string {
|
|
||||||
return this.linkPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,13 +0,0 @@
|
|||||||
import { Observable } from 'rxjs';
|
|
||||||
import { RemoteData } from './remote-data';
|
|
||||||
import { RestRequestMethod } from './rest-request-method';
|
|
||||||
import { Operation } from 'fast-json-patch';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a data service to update a given object
|
|
||||||
*/
|
|
||||||
export interface UpdateDataService<T> {
|
|
||||||
patch(dso: T, operations: Operation[]): Observable<RemoteData<T>>;
|
|
||||||
update(object: T): Observable<RemoteData<T>>;
|
|
||||||
commitUpdates(method?: RestRequestMethod);
|
|
||||||
}
|
|
@@ -128,7 +128,7 @@ describe('VersionDataService test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getHistoryFromVersion', () => {
|
describe('getHistoryFromVersion', () => {
|
||||||
it('should proxy the call to DataService.findByHref', () => {
|
it('should proxy the call to UpdateDataServiceImpl.findByHref', () => {
|
||||||
scheduler.schedule(() => service.getHistoryFromVersion(mockVersion, true, true));
|
scheduler.schedule(() => service.getHistoryFromVersion(mockVersion, true, true));
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
|
|
||||||
|
@@ -315,7 +315,7 @@ describe('EPersonDataService', () => {
|
|||||||
service.deleteEPerson(EPersonMock).subscribe();
|
service.deleteEPerson(EPersonMock).subscribe();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call DataService.delete with the EPerson\'s UUID', () => {
|
it('should call UpdateDataServiceImpl.delete with the EPerson\'s UUID', () => {
|
||||||
expect(service.delete).toHaveBeenCalledWith(EPersonMock.id);
|
expect(service.delete).toHaveBeenCalledWith(EPersonMock.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -126,7 +126,7 @@ describe('WorkflowItemDataService test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('findByItem', () => {
|
describe('findByItem', () => {
|
||||||
it('should proxy the call to DataService.findByHref', () => {
|
it('should proxy the call to UpdateDataServiceImpl.findByHref', () => {
|
||||||
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
|
|
||||||
|
@@ -141,7 +141,7 @@ describe('WorkspaceitemDataService test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('findByItem', () => {
|
describe('findByItem', () => {
|
||||||
it('should proxy the call to DataService.findByHref', () => {
|
it('should proxy the call to UpdateDataServiceImpl.findByHref', () => {
|
||||||
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
scheduler.schedule(() => service.findByItem('1234-1234', true, true, pageInfo));
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
const searchUrl = service.getIDHref('item', [new RequestParam('uuid', encodeURIComponent('1234-1234'))]);
|
const searchUrl = service.getIDHref('item', [new RequestParam('uuid', encodeURIComponent('1234-1234'))]);
|
||||||
|
@@ -11,7 +11,7 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
|||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { dataService } from '../cache/builders/build-decorators';
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
import { RequestService } from '../data/request.service';
|
import { RequestService } from '../data/request.service';
|
||||||
import { DataService } from '../data/data.service';
|
import { UpdateDataServiceImpl } from '../data/update-data-service';
|
||||||
import { ChangeAnalyzer } from '../data/change-analyzer';
|
import { ChangeAnalyzer } from '../data/change-analyzer';
|
||||||
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||||
import { RemoteData } from '../data/remote-data';
|
import { RemoteData } from '../data/remote-data';
|
||||||
@@ -31,13 +31,9 @@ import { SuggestionTargetDataService } from './target/suggestion-target-data.ser
|
|||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A private DataService implementation to delegate specific methods to.
|
* A private UpdateDataServiceImpl implementation to delegate specific methods to.
|
||||||
*/
|
*/
|
||||||
export class SuggestionDataServiceImpl extends DataService<Suggestion> {
|
export class SuggestionDataServiceImpl extends UpdateDataServiceImpl<Suggestion> {
|
||||||
/**
|
|
||||||
* The REST endpoint.
|
|
||||||
*/
|
|
||||||
protected linkPath = 'suggestions';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize service variables
|
* Initialize service variables
|
||||||
@@ -49,6 +45,7 @@ export class SuggestionDataServiceImpl extends DataService<Suggestion> {
|
|||||||
* @param {NotificationsService} notificationsService
|
* @param {NotificationsService} notificationsService
|
||||||
* @param {HttpClient} http
|
* @param {HttpClient} http
|
||||||
* @param {ChangeAnalyzer<Suggestion>} comparator
|
* @param {ChangeAnalyzer<Suggestion>} comparator
|
||||||
|
* @param responseMsToLive
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
@@ -58,8 +55,10 @@ export class SuggestionDataServiceImpl extends DataService<Suggestion> {
|
|||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient,
|
protected http: HttpClient,
|
||||||
protected comparator: ChangeAnalyzer<Suggestion>) {
|
protected comparator: ChangeAnalyzer<Suggestion>,
|
||||||
super();
|
protected responseMsToLive: number,
|
||||||
|
) {
|
||||||
|
super('suggestions', requestService, rdbService, objectCache, halService, notificationsService ,responseMsToLive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,20 +72,22 @@ export class SuggestionsDataService {
|
|||||||
protected searchFindByTargetAndSourceMethod = 'findByTargetAndSource';
|
protected searchFindByTargetAndSourceMethod = 'findByTargetAndSource';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A private DataService implementation to delegate specific methods to.
|
* A private UpdateDataServiceImpl implementation to delegate specific methods to.
|
||||||
*/
|
*/
|
||||||
private suggestionsDataService: SuggestionDataServiceImpl;
|
private suggestionsDataService: SuggestionDataServiceImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A private DataService implementation to delegate specific methods to.
|
* A private UpdateDataServiceImpl implementation to delegate specific methods to.
|
||||||
*/
|
*/
|
||||||
private suggestionSourcesDataService: SuggestionSourceDataService;
|
private suggestionSourcesDataService: SuggestionSourceDataService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A private DataService implementation to delegate specific methods to.
|
* A private UpdateDataServiceImpl implementation to delegate specific methods to.
|
||||||
*/
|
*/
|
||||||
private suggestionTargetsDataService: SuggestionTargetDataService;
|
private suggestionTargetsDataService: SuggestionTargetDataService;
|
||||||
|
|
||||||
|
private responseMsToLive = 10 * 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize service variables
|
* Initialize service variables
|
||||||
* @param {RequestService} requestService
|
* @param {RequestService} requestService
|
||||||
@@ -98,6 +99,7 @@ export class SuggestionsDataService {
|
|||||||
* @param {DefaultChangeAnalyzer<Suggestion>} comparatorSuggestions
|
* @param {DefaultChangeAnalyzer<Suggestion>} comparatorSuggestions
|
||||||
* @param {DefaultChangeAnalyzer<SuggestionSource>} comparatorSources
|
* @param {DefaultChangeAnalyzer<SuggestionSource>} comparatorSources
|
||||||
* @param {DefaultChangeAnalyzer<SuggestionTarget>} comparatorTargets
|
* @param {DefaultChangeAnalyzer<SuggestionTarget>} comparatorTargets
|
||||||
|
* @param responseMsToLive
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
@@ -110,7 +112,7 @@ export class SuggestionsDataService {
|
|||||||
protected comparatorSources: DefaultChangeAnalyzer<SuggestionSource>,
|
protected comparatorSources: DefaultChangeAnalyzer<SuggestionSource>,
|
||||||
protected comparatorTargets: DefaultChangeAnalyzer<SuggestionTarget>,
|
protected comparatorTargets: DefaultChangeAnalyzer<SuggestionTarget>,
|
||||||
) {
|
) {
|
||||||
this.suggestionsDataService = new SuggestionDataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorSuggestions);
|
this.suggestionsDataService = new SuggestionDataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorSuggestions, this.responseMsToLive);
|
||||||
this.suggestionSourcesDataService = new SuggestionSourceDataService(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorSources);
|
this.suggestionSourcesDataService = new SuggestionSourceDataService(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorSources);
|
||||||
this.suggestionTargetsDataService = new SuggestionTargetDataService(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorTargets);
|
this.suggestionTargetsDataService = new SuggestionTargetDataService(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparatorTargets);
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,6 @@ import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
|||||||
import {
|
import {
|
||||||
getFirstCompletedRemoteData,
|
getFirstCompletedRemoteData,
|
||||||
} from '../../core/shared/operators';
|
} from '../../core/shared/operators';
|
||||||
import { UpdateDataService } from '../../core/data/update-data.service';
|
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@@ -22,6 +21,7 @@ import { ArrayMoveChangeAnalyzer } from '../../core/data/array-move-change-analy
|
|||||||
import { DATA_SERVICE_FACTORY } from '../../core/data/base/data-service.decorator';
|
import { DATA_SERVICE_FACTORY } from '../../core/data/base/data-service.decorator';
|
||||||
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
import { GenericConstructor } from '../../core/shared/generic-constructor';
|
||||||
import { HALDataService } from '../../core/data/base/hal-data-service.interface';
|
import { HALDataService } from '../../core/data/base/hal-data-service.interface';
|
||||||
|
import { UpdateDataService } from "../../core/data/update-data-service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-dso-edit-metadata',
|
selector: 'ds-dso-edit-metadata',
|
||||||
|
@@ -2,7 +2,7 @@ import { ThemedComponent } from '../../shared/theme-support/themed.component';
|
|||||||
import { DsoEditMetadataComponent } from './dso-edit-metadata.component';
|
import { DsoEditMetadataComponent } from './dso-edit-metadata.component';
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { UpdateDataService } from '../../core/data/update-data.service';
|
import { UpdateDataService } from "../../core/data/update-data-service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-themed-dso-edit-metadata',
|
selector: 'ds-themed-dso-edit-metadata',
|
||||||
|
@@ -541,7 +541,7 @@ export class MenuResolver implements Resolve<boolean> {
|
|||||||
{
|
{
|
||||||
id: 'notifications',
|
id: 'notifications',
|
||||||
active: false,
|
active: false,
|
||||||
visible: authorized && canSeeQA,
|
visible: authorized && true,
|
||||||
model: {
|
model: {
|
||||||
type: MenuItemType.TEXT,
|
type: MenuItemType.TEXT,
|
||||||
text: 'menu.section.notifications'
|
text: 'menu.section.notifications'
|
||||||
|
@@ -26,7 +26,7 @@ import { QualityAssuranceSourceService } from './qa/source/quality-assurance-sou
|
|||||||
import {
|
import {
|
||||||
QualityAssuranceSourceDataService
|
QualityAssuranceSourceDataService
|
||||||
} from '../core/notifications/qa/source/quality-assurance-source-data.service';
|
} from '../core/notifications/qa/source/quality-assurance-source-data.service';
|
||||||
import { SuggestionTargetsComponent } from '../suggestion-notifications/suggestion-targets/suggestion-targets.component';
|
import { PublicationClaimComponent } from '../suggestion-notifications/suggestion-targets/publication-claim/publication-claim.component';
|
||||||
import { SuggestionActionsComponent } from '../suggestion-notifications/suggestion-actions/suggestion-actions.component';
|
import { SuggestionActionsComponent } from '../suggestion-notifications/suggestion-actions/suggestion-actions.component';
|
||||||
import {
|
import {
|
||||||
SuggestionListElementComponent
|
SuggestionListElementComponent
|
||||||
@@ -65,7 +65,7 @@ const COMPONENTS = [
|
|||||||
QualityAssuranceTopicsComponent,
|
QualityAssuranceTopicsComponent,
|
||||||
QualityAssuranceEventsComponent,
|
QualityAssuranceEventsComponent,
|
||||||
QualityAssuranceSourceComponent,
|
QualityAssuranceSourceComponent,
|
||||||
SuggestionTargetsComponent,
|
PublicationClaimComponent,
|
||||||
SuggestionActionsComponent,
|
SuggestionActionsComponent,
|
||||||
SuggestionListElementComponent,
|
SuggestionListElementComponent,
|
||||||
SuggestionEvidencesComponent,
|
SuggestionEvidencesComponent,
|
||||||
|
@@ -96,7 +96,7 @@ export class EpersonGroupListComponent implements OnInit, OnDestroy {
|
|||||||
private pageConfigSub: Subscription;
|
private pageConfigSub: Subscription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize instance variables and inject the properly DataService
|
* Initialize instance variables and inject the properly UpdateDataServiceImpl
|
||||||
*
|
*
|
||||||
* @param {DSONameService} dsoNameService
|
* @param {DSONameService} dsoNameService
|
||||||
* @param {Injector} parentInjector
|
* @param {Injector} parentInjector
|
||||||
|
@@ -13,7 +13,7 @@ import { CacheableObject } from '../../core/cache/cacheable-object.model';
|
|||||||
import { IdentifiableDataService } from '../../core/data/base/identifiable-data.service';
|
import { IdentifiableDataService } from '../../core/data/base/identifiable-data.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to return DataService for given ResourceType
|
* Class to return UpdateDataServiceImpl for given ResourceType
|
||||||
*/
|
*/
|
||||||
export class MyDSpaceActionsServiceFactory<T extends CacheableObject, TService extends IdentifiableDataService<T>> {
|
export class MyDSpaceActionsServiceFactory<T extends CacheableObject, TService extends IdentifiableDataService<T>> {
|
||||||
public getConstructor(type: ResourceType): TService {
|
public getConstructor(type: ResourceType): TService {
|
||||||
|
@@ -47,7 +47,7 @@ export abstract class MyDSpaceActionsComponent<T extends DSpaceObject, TService
|
|||||||
public processing$ = new BehaviorSubject<boolean>(false);
|
public processing$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of DataService related to mydspace object
|
* Instance of UpdateDataServiceImpl related to mydspace object
|
||||||
*/
|
*/
|
||||||
protected objectDataService: TService;
|
protected objectDataService: TService;
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
{{ ignoreSuggestionLabel() | translate}}</button>
|
{{ ignoreSuggestionLabel() | translate}}</button>
|
||||||
<button *ngIf="!isBulk" (click)="toggleSeeEvidences()" [disabled]="!hasEvidence" class="btn btn-info ml-2">
|
<button *ngIf="!isBulk" (click)="toggleSeeEvidences()" [disabled]="!hasEvidence" class="btn btn-info ml-2">
|
||||||
<i class="fa fa-eye"></i>
|
<i class="fa fa-eye"></i>
|
||||||
<ng-container *ngIf="!seeEvidence"> {{ 'reciter.suggestion.seeEvidence' | translate}}</ng-container>
|
<ng-container *ngIf="!seeEvidence"> {{ 'suggestion.seeEvidence' | translate}}</ng-container>
|
||||||
<ng-container *ngIf="seeEvidence"> {{ 'reciter.suggestion.hideEvidence' | translate}}</ng-container>
|
<ng-container *ngIf="seeEvidence"> {{ 'suggestion.hideEvidence' | translate}}</ng-container>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h1 id="header" class="border-bottom pb-2">{{'reciter.suggestion.title'| translate}}</h1>
|
<h1 id="header" class="border-bottom pb-2">{{'suggestion.title'| translate}}</h1>
|
||||||
|
|
||||||
<ds-loading class="container" *ngIf="(isTargetsLoading() | async)" message="{{'reciter.suggestion.loading' | translate}}"></ds-loading>
|
<ds-loading class="container" *ngIf="(isTargetsLoading() | async)" message="{{'suggestion.loading' | translate}}"></ds-loading>
|
||||||
<ds-pagination *ngIf="!(isTargetsLoading() | async)"
|
<ds-pagination *ngIf="!(isTargetsLoading() | async)"
|
||||||
[paginationOptions]="paginationConfig"
|
[paginationOptions]="paginationConfig"
|
||||||
[collectionSize]="(totalElements$ | async)"
|
[collectionSize]="(totalElements$ | async)"
|
||||||
@@ -11,17 +11,17 @@
|
|||||||
[retainScrollPosition]="false"
|
[retainScrollPosition]="false"
|
||||||
(paginationChange)="getSuggestionTargets()">
|
(paginationChange)="getSuggestionTargets()">
|
||||||
|
|
||||||
<ds-loading class="container" *ngIf="(isTargetsProcessing() | async)" message="'reciter.suggestion.loading' | translate"></ds-loading>
|
<ds-loading class="container" *ngIf="(isTargetsProcessing() | async)" message="'suggestion.loading' | translate"></ds-loading>
|
||||||
<ng-container *ngIf="!(isTargetsProcessing() | async)">
|
<ng-container *ngIf="!(isTargetsProcessing() | async)">
|
||||||
<div *ngIf="!(targets$|async) || (targets$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert">
|
<div *ngIf="!(targets$|async) || (targets$|async)?.length == 0" class="alert alert-info w-100 mb-2 mt-2" role="alert">
|
||||||
{{'reciter.suggestion.noTargets' | translate}}
|
{{'suggestion.noTargets' | translate}}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="(targets$|async) && (targets$|async)?.length != 0" class="table-responsive mt-2">
|
<div *ngIf="(targets$|async) && (targets$|async)?.length != 0" class="table-responsive mt-2">
|
||||||
<table id="epeople" class="table table-striped table-hover table-bordered">
|
<table id="epeople" class="table table-striped table-hover table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-center">
|
<tr class="text-center">
|
||||||
<th scope="col">{{'reciter.suggestion.table.name' | translate}}</th>
|
<th scope="col">{{'suggestion.table.name' | translate}}</th>
|
||||||
<th scope="col">{{'reciter.suggestion.table.actions' | translate}}</th>
|
<th scope="col">{{'suggestion.table.actions' | translate}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -33,9 +33,9 @@
|
|||||||
<div class="btn-group edit-field">
|
<div class="btn-group edit-field">
|
||||||
<button (click)="redirectToSuggestions(targetElement.id, targetElement.display)"
|
<button (click)="redirectToSuggestions(targetElement.id, targetElement.display)"
|
||||||
class="btn btn-outline-primary btn-sm"
|
class="btn btn-outline-primary btn-sm"
|
||||||
title="{{('reciter.suggestion.button.review.title' | translate: { total: targetElement.total.toString() }) +
|
title="{{('suggestion.button.review.title' | translate: { total: targetElement.total.toString() }) +
|
||||||
targetElement.display}}">
|
targetElement.display}}">
|
||||||
<span>{{'reciter.suggestion.button.review' | translate: { total: targetElement.total.toString() } }} </span>
|
<span>{{'suggestion.button.review' | translate: { total: targetElement.total.toString() } }} </span>
|
||||||
<i class="fas fa-lightbulb"></i>
|
<i class="fas fa-lightbulb"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
@@ -4,23 +4,23 @@ import { Router } from '@angular/router';
|
|||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { distinctUntilChanged, take } from 'rxjs/operators';
|
import { distinctUntilChanged, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { SuggestionTarget } from '../../core/suggestion-notifications/models/suggestion-target.model';
|
import { SuggestionTarget } from '../../../core/suggestion-notifications/models/suggestion-target.model';
|
||||||
import { hasValue } from '../../shared/empty.util';
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
|
||||||
import { SuggestionTargetsStateService } from './suggestion-targets.state.service';
|
import { SuggestionTargetsStateService } from '../suggestion-targets.state.service';
|
||||||
import { getSuggestionPageRoute } from '../../suggestions-page/suggestions-page-routing-paths';
|
import { getSuggestionPageRoute } from '../../../suggestions-page/suggestions-page-routing-paths';
|
||||||
import { SuggestionsService } from '../suggestions.service';
|
import { SuggestionsService } from '../../suggestions.service';
|
||||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display the Suggestion Target list.
|
* Component to display the Suggestion Target list.
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-suggestion-target',
|
selector: 'ds-publication-claim',
|
||||||
templateUrl: './suggestion-targets.component.html',
|
templateUrl: './publication-claim.component.html',
|
||||||
styleUrls: ['./suggestion-targets.component.scss'],
|
styleUrls: ['./publication-claim.component.scss'],
|
||||||
})
|
})
|
||||||
export class SuggestionTargetsComponent implements OnInit {
|
export class PublicationClaimComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The source for which to list targets
|
* The source for which to list targets
|
@@ -156,7 +156,7 @@ describe('SuggestionsService test', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should delete suggestions', () => {
|
it('should delete suggestions', () => {
|
||||||
spyOn(service, 'notMine');
|
spyOn(service, 'ignoreSuggestion');
|
||||||
service.ignoreSuggestionMultiple([mockSuggestionPublicationOne]);
|
service.ignoreSuggestionMultiple([mockSuggestionPublicationOne]);
|
||||||
expect(service.ignoreSuggestion).toHaveBeenCalledWith(mockSuggestionPublicationOne.id);
|
expect(service.ignoreSuggestion).toHaveBeenCalledWith(mockSuggestionPublicationOne.id);
|
||||||
});
|
});
|
||||||
|
@@ -18,7 +18,7 @@ import { combineLatest, Subject } from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class SuggestionsPopupComponent implements OnInit, OnDestroy {
|
export class SuggestionsPopupComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
labelPrefix = 'mydspace.';
|
labelPrefix = 'notification.';
|
||||||
|
|
||||||
subscription;
|
subscription;
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ export class SuggestionsPopupComponent implements OnInit, OnDestroy {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private showNotificationForNewSuggestions(suggestionTarget: SuggestionTarget): void {
|
private showNotificationForNewSuggestions(suggestionTarget: SuggestionTarget): void {
|
||||||
const content = this.translateService.instant(this.labelPrefix + 'notification.suggestion',
|
const content = this.translateService.instant(this.labelPrefix + 'suggestion',
|
||||||
this.suggestionsService.getNotificationSuggestionInterpolation(suggestionTarget));
|
this.suggestionsService.getNotificationSuggestionInterpolation(suggestionTarget));
|
||||||
this.notificationsService.success('', content, {timeOut:0}, true);
|
this.notificationsService.success('', content, {timeOut:0}, true);
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ import { NoContent } from '../core/shared/NoContent.model';
|
|||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
import { WorkspaceItem } from '../core/submission/models/workspaceitem.model';
|
import { WorkspaceItem } from '../core/submission/models/workspaceitem.model';
|
||||||
import {FindListOptions} from '../core/data/find-list-options.model';
|
import {FindListOptions} from '../core/data/find-list-options.model';
|
||||||
import {SuggestionConfig} from '../../config/layout-config.interfaces';
|
import {SuggestionConfig} from '../../config/suggestion-config.interfaces';
|
||||||
import { ResearcherProfileDataService } from '../core/profile/researcher-profile-data.service';
|
import { ResearcherProfileDataService } from '../core/profile/researcher-profile-data.service';
|
||||||
import {
|
import {
|
||||||
SuggestionSourceDataService
|
SuggestionSourceDataService
|
||||||
@@ -229,7 +229,7 @@ export class SuggestionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a bulk notMine operation.
|
* Perform a bulk ignoreSuggestion operation.
|
||||||
* @param suggestions the array containing the suggestions
|
* @param suggestions the array containing the suggestions
|
||||||
*/
|
*/
|
||||||
public ignoreSuggestionMultiple(suggestions: Suggestion[]): Observable<SuggestionBulkResult> {
|
public ignoreSuggestionMultiple(suggestions: Suggestion[]): Observable<SuggestionBulkResult> {
|
||||||
|
@@ -41,7 +41,6 @@ describe('SuggestionPageComponent', () => {
|
|||||||
let scheduler: TestScheduler;
|
let scheduler: TestScheduler;
|
||||||
const mockSuggestionsService = getMockSuggestionsService();
|
const mockSuggestionsService = getMockSuggestionsService();
|
||||||
const mockSuggestionsTargetStateService = getMockSuggestionNotificationsStateService();
|
const mockSuggestionsTargetStateService = getMockSuggestionNotificationsStateService();
|
||||||
const suggestionTargetsList: PaginatedList<Suggestion> = buildPaginatedList(new PageInfo(), [mockSuggestionPublicationOne, mockSuggestionPublicationTwo]);
|
|
||||||
const router = new RouterStub();
|
const router = new RouterStub();
|
||||||
const routeStub = {
|
const routeStub = {
|
||||||
data: observableOf({
|
data: observableOf({
|
||||||
@@ -139,7 +138,7 @@ describe('SuggestionPageComponent', () => {
|
|||||||
scheduler.schedule(() => fixture.detectChanges());
|
scheduler.schedule(() => fixture.detectChanges());
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
component.ignoreSuggestion('1');
|
component.ignoreSuggestion('1');
|
||||||
expect(mockSuggestionsService.notMine).toHaveBeenCalledWith('1');
|
expect(mockSuggestionsService.ignoreSuggestion).toHaveBeenCalledWith('1');
|
||||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||||
expect(component.updatePage).toHaveBeenCalled();
|
expect(component.updatePage).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -150,7 +149,7 @@ describe('SuggestionPageComponent', () => {
|
|||||||
scheduler.schedule(() => fixture.detectChanges());
|
scheduler.schedule(() => fixture.detectChanges());
|
||||||
scheduler.flush();
|
scheduler.flush();
|
||||||
component.ignoreSuggestionAllSelected();
|
component.ignoreSuggestionAllSelected();
|
||||||
expect(mockSuggestionsService.notMineMultiple).toHaveBeenCalled();
|
expect(mockSuggestionsService.ignoreSuggestionMultiple).toHaveBeenCalled();
|
||||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||||
expect(component.updatePage).toHaveBeenCalled();
|
expect(component.updatePage).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
@@ -28,6 +28,11 @@ import {redirectOn4xx} from '../core/shared/authorized.operators';
|
|||||||
templateUrl: './suggestions-page.component.html',
|
templateUrl: './suggestions-page.component.html',
|
||||||
styleUrls: ['./suggestions-page.component.scss'],
|
styleUrls: ['./suggestions-page.component.scss'],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component used to visualize one of the suggestions from the publication claim page or from the notification pop up
|
||||||
|
*/
|
||||||
|
|
||||||
export class SuggestionsPageComponent implements OnInit {
|
export class SuggestionsPageComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,15 +144,6 @@ export class SuggestionsPageComponent implements OnInit {
|
|||||||
this.processing$.next(false);
|
this.processing$.next(false);
|
||||||
this.suggestionsRD$.next(results);
|
this.suggestionsRD$.next(results);
|
||||||
this.suggestionService.clearSuggestionRequests();
|
this.suggestionService.clearSuggestionRequests();
|
||||||
// navigate to the mydspace if no suggestions remains
|
|
||||||
|
|
||||||
// if (results.totalElements === 0) {
|
|
||||||
// const content = this.translateService.instant('reciter.suggestion.empty',
|
|
||||||
// this.suggestionService.getNotificationSuggestionInterpolation(this.suggestionTarget));
|
|
||||||
// this.notificationService.success('', content, {timeOut:0}, true);
|
|
||||||
// TODO if the target is not the current use route to the suggestion target page
|
|
||||||
// this.router.navigate(['/mydspace']);
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3084,9 +3084,9 @@
|
|||||||
|
|
||||||
"mydspace.import": "Import",
|
"mydspace.import": "Import",
|
||||||
|
|
||||||
"mydspace.notification.suggestion": "We found <b>{{count}} publications</b><br> in the {{source}} that seems to be related to your profile.<br> Please <a href='/suggestions/{{suggestionId}}'>review the suggestions</a>",
|
"notification.suggestion": "We found <b>{{count}} publications</b><br> in the {{source}} that seems to be related to your profile.<br> Please <a href='/suggestions/{{suggestionId}}'>review the suggestions</a>",
|
||||||
|
|
||||||
"mydspace.notification.suggestion.page": "We found <b>{{count}} {{type}}</b> in the {{source}} that seems to be related to your profile. Please <a href='/suggestions/{{suggestionId}}'>review the suggestions.</a>",
|
"notification.suggestion.page": "We found <b>{{count}} {{type}}</b> in the {{source}} that seems to be related to your profile. Please <a href='/suggestions/{{suggestionId}}'>review the suggestions.</a>",
|
||||||
|
|
||||||
"nav.browse.header": "All of DSpace",
|
"nav.browse.header": "All of DSpace",
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ import { AuthConfig } from './auth-config.interfaces';
|
|||||||
import { UIServerConfig } from './ui-server-config.interface';
|
import { UIServerConfig } from './ui-server-config.interface';
|
||||||
import { MediaViewerConfig } from './media-viewer-config.interface';
|
import { MediaViewerConfig } from './media-viewer-config.interface';
|
||||||
import { BrowseByConfig } from './browse-by-config.interface';
|
import { BrowseByConfig } from './browse-by-config.interface';
|
||||||
import { SuggestionConfig } from './layout-config.interfaces';
|
import { SuggestionConfig } from './suggestion-config.interfaces';
|
||||||
import { BundleConfig } from './bundle-config.interface';
|
import { BundleConfig } from './bundle-config.interface';
|
||||||
import { ActuatorsConfig } from './actuators.config';
|
import { ActuatorsConfig } from './actuators.config';
|
||||||
import { InfoConfig } from './info-config.interface';
|
import { InfoConfig } from './info-config.interface';
|
||||||
@@ -23,7 +23,7 @@ import { HomeConfig } from './homepage-config.interface';
|
|||||||
import { MarkdownConfig } from './markdown-config.interface';
|
import { MarkdownConfig } from './markdown-config.interface';
|
||||||
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
import { FilterVocabularyConfig } from './filter-vocabulary-config';
|
||||||
import { DiscoverySortConfig } from './discovery-sort.config';
|
import { DiscoverySortConfig } from './discovery-sort.config';
|
||||||
import {QualityAssuranceConfig} from './quality-assurance.config';
|
import { QualityAssuranceConfig } from './quality-assurance.config';
|
||||||
|
|
||||||
interface AppConfig extends Config {
|
interface AppConfig extends Config {
|
||||||
ui: UIServerConfig;
|
ui: UIServerConfig;
|
||||||
|
@@ -14,7 +14,7 @@ import { ServerConfig } from './server-config.interface';
|
|||||||
import { SubmissionConfig } from './submission-config.interface';
|
import { SubmissionConfig } from './submission-config.interface';
|
||||||
import { ThemeConfig } from './theme.config';
|
import { ThemeConfig } from './theme.config';
|
||||||
import { UIServerConfig } from './ui-server-config.interface';
|
import { UIServerConfig } from './ui-server-config.interface';
|
||||||
import {SuggestionConfig} from './layout-config.interfaces';
|
import {SuggestionConfig} from './suggestion-config.interfaces';
|
||||||
import { BundleConfig } from './bundle-config.interface';
|
import { BundleConfig } from './bundle-config.interface';
|
||||||
import { ActuatorsConfig } from './actuators.config';
|
import { ActuatorsConfig } from './actuators.config';
|
||||||
import { InfoConfig } from './info-config.interface';
|
import { InfoConfig } from './info-config.interface';
|
||||||
@@ -304,6 +304,8 @@ export class DefaultAppConfig implements AppConfig {
|
|||||||
// source: 'suggestionSource',
|
// source: 'suggestionSource',
|
||||||
// collectionId: 'collectionUUID'
|
// collectionId: 'collectionUUID'
|
||||||
// }
|
// }
|
||||||
|
// If not mapped the suggestion service won't be able to approve and import the related suggestion
|
||||||
|
// or load the fixed suggestions collections that can be configured here adding the source and the UUID of the collection
|
||||||
];
|
];
|
||||||
|
|
||||||
// Theme Config
|
// Theme Config
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
import { Config } from './config.interface';
|
|
||||||
|
|
||||||
export interface UrnConfig extends Config {
|
|
||||||
name: string;
|
|
||||||
baseUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CrisRefConfig extends Config {
|
|
||||||
entityType: string;
|
|
||||||
icon: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CrisLayoutMetadataBoxConfig extends Config {
|
|
||||||
defaultMetadataLabelColStyle: string;
|
|
||||||
defaultMetadataValueColStyle: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CrisLayoutTypeConfig {
|
|
||||||
orientation: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NavbarConfig extends Config {
|
|
||||||
showCommunityCollection: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CrisItemPageConfig extends Config {
|
|
||||||
[entity: string]: CrisLayoutTypeConfig;
|
|
||||||
default: CrisLayoutTypeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface CrisLayoutConfig extends Config {
|
|
||||||
urn: UrnConfig[];
|
|
||||||
crisRef: CrisRefConfig[];
|
|
||||||
itemPage: CrisItemPageConfig;
|
|
||||||
metadataBox: CrisLayoutMetadataBoxConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LayoutConfig extends Config {
|
|
||||||
navbar: NavbarConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SuggestionConfig extends Config {
|
|
||||||
source: string;
|
|
||||||
collectionId: string;
|
|
||||||
}
|
|
6
src/config/suggestion-config.interfaces.ts
Normal file
6
src/config/suggestion-config.interfaces.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { Config } from "./config.interface";
|
||||||
|
|
||||||
|
export interface SuggestionConfig extends Config {
|
||||||
|
source: string;
|
||||||
|
collectionId: string;
|
||||||
|
}
|
Reference in New Issue
Block a user