mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge branch 'DSpace:main' into feat/i18n
This commit is contained in:
@@ -212,7 +212,7 @@
|
||||
<span> {{'ldn-service.control-constaint-select-none' | translate}} </span>
|
||||
</button>
|
||||
<button (click)="selectInboundItemFilter(constraint.id, i); $event.stopPropagation()"
|
||||
*ngFor="let constraint of (itemfiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||
*ngFor="let constraint of (itemFiltersRD$ | async)?.payload?.page; let internalIndex = index"
|
||||
class="dropdown-item collection-item text-truncate w-100"
|
||||
ngbDropdownItem
|
||||
type="button">
|
||||
@@ -263,14 +263,18 @@
|
||||
|
||||
<span (click)="addInboundPattern()"
|
||||
class="add-pattern-link mb-2">{{ 'ldn-new-service.form.label.addPattern' | translate }}</span>
|
||||
<hr>
|
||||
<div class="form-group row">
|
||||
<div class="col text-right space-children-mr">
|
||||
<ng-content select="[before]"></ng-content>
|
||||
<button (click)="resetFormAndLeave()" class="btn btn-outline-secondary" type="button">
|
||||
<span> {{ 'submission.general.back.submit' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<div class="submission-form-footer my-1 position-sticky d-flex justify-content-between" role="group">
|
||||
<button (click)="resetFormAndLeave()" class="btn btn-primary" type="button">
|
||||
<span> {{ 'submission.general.back.submit' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" type="submit">
|
||||
<span><i class="fas fa-save"></i> {{ 'ldn-new-service.form.label.submit' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -294,7 +298,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div *ngIf="!isNewService">
|
||||
<button (click)="closeModal()" class="btn btn-danger mr-2"
|
||||
<button (click)="closeModal()" class="btn btn-outline-secondary mr-2"
|
||||
id="delete-confirm-edit">{{ 'service.detail.return' | translate }}
|
||||
</button>
|
||||
<button *ngIf="!isNewService" (click)="patchService()"
|
||||
@@ -302,7 +306,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="isNewService">
|
||||
<button (click)="closeModal()" class="btn btn-danger mr-2 "
|
||||
<button (click)="closeModal()" class="btn btn-outline-secondary mr-2 "
|
||||
id="delete-confirm-new">{{ 'service.refuse.create' | translate }}
|
||||
</button>
|
||||
<button (click)="createService()"
|
||||
|
@@ -145,7 +145,7 @@ describe('LdnServiceFormEditComponent', () => {
|
||||
|
||||
it('should init properties correctly', fakeAsync(() => {
|
||||
spyOn(component, 'fetchServiceData');
|
||||
spyOn(component, 'setItemfilters');
|
||||
spyOn(component, 'setItemFilters');
|
||||
component.ngOnInit();
|
||||
tick(100);
|
||||
expect((component as any).serviceId).toEqual(testId);
|
||||
@@ -153,7 +153,7 @@ describe('LdnServiceFormEditComponent', () => {
|
||||
expect(component.areControlsInitialized).toBeTruthy();
|
||||
expect(component.formModel.controls.notifyServiceInboundPatterns).toBeDefined();
|
||||
expect(component.fetchServiceData).toHaveBeenCalledWith(testId);
|
||||
expect(component.setItemfilters).toHaveBeenCalled();
|
||||
expect(component.setItemFilters).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should unsubscribe on destroy', () => {
|
||||
|
@@ -92,7 +92,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
public inboundPatterns: string[] = notifyPatterns;
|
||||
public isNewService: boolean;
|
||||
public areControlsInitialized: boolean;
|
||||
public itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
||||
public itemFiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
|
||||
public config: FindListOptions = Object.assign(new FindListOptions(), {
|
||||
elementsPerPage: 20,
|
||||
});
|
||||
@@ -104,12 +104,12 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
private deletedInboundPatterns: number[] = [];
|
||||
private modalRef: any;
|
||||
private ldnService: LdnService;
|
||||
private selectPatternDefaultLabeli18Key = 'ldn-service.form.label.placeholder.default-select';
|
||||
private selectPatternDefaultLabelI18Key = 'ldn-service.form.label.placeholder.default-select';
|
||||
private routeSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
protected ldnServicesService: LdnServicesService,
|
||||
private ldnItemfiltersService: LdnItemfiltersService,
|
||||
private ldnItemFiltersService: LdnItemfiltersService,
|
||||
private formBuilder: FormBuilder,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
@@ -147,7 +147,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
this.fetchServiceData(this.serviceId);
|
||||
}
|
||||
});
|
||||
this.setItemfilters();
|
||||
this.setItemFilters();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@@ -157,8 +157,8 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Sets item filters using LDN item filters service
|
||||
*/
|
||||
setItemfilters() {
|
||||
this.itemfiltersRD$ = this.ldnItemfiltersService.findAll().pipe(
|
||||
setItemFilters() {
|
||||
this.itemFiltersRD$ = this.ldnItemFiltersService.findAll().pipe(
|
||||
getFirstCompletedRemoteData());
|
||||
}
|
||||
|
||||
@@ -168,21 +168,12 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
createService() {
|
||||
this.formModel.markAllAsTouched();
|
||||
const notifyServiceInboundPatterns = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||
const hasInboundPattern = notifyServiceInboundPatterns?.length > 0 ? this.checkPatterns(notifyServiceInboundPatterns) : false;
|
||||
|
||||
if (this.formModel.invalid) {
|
||||
this.closeModal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasInboundPattern) {
|
||||
this.notificationService.warning(this.translateService.get('ldn-service-notification.created.warning.title'));
|
||||
this.closeModal();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.formModel.value.notifyServiceInboundPatterns = this.formModel.value.notifyServiceInboundPatterns.map((pattern: {
|
||||
pattern: string;
|
||||
patternLabel: string,
|
||||
@@ -272,20 +263,24 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters pattern objects, initializes form groups, assigns labels, and adds them to the specified form array so the correct string is shown in the dropdown..
|
||||
* Filters pattern objects, initializes form groups, assigns labels, and adds them to the specified form array so the correct string is shown in the dropdown.
|
||||
* @param formArrayName - The name of the form array to be populated
|
||||
*/
|
||||
filterPatternObjectsAndAssignLabel(formArrayName: string) {
|
||||
const PatternsArray = this.formModel.get(formArrayName) as FormArray;
|
||||
PatternsArray.clear();
|
||||
|
||||
const servicesToUse = this.ldnService.notifyServiceInboundPatterns;
|
||||
const servicesToUse = [...this.ldnService.notifyServiceInboundPatterns];
|
||||
if (servicesToUse.length === 0) {
|
||||
servicesToUse.push({ pattern: '', constraint: '', automatic: 'false' });
|
||||
}
|
||||
|
||||
servicesToUse.forEach((patternObj: NotifyServicePattern) => {
|
||||
const patternFormGroup = this.initializeInboundPatternFormGroup();
|
||||
const patternLabel = patternObj?.pattern ? 'ldn-service.form.pattern.' + patternObj?.pattern + '.label' : 'ldn-service.form.label.placeholder.default-select';
|
||||
const newPatternObjWithLabel = Object.assign(new NotifyServicePattern(), {
|
||||
...patternObj,
|
||||
patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternObj?.pattern + '.label'),
|
||||
patternLabel: this.translateService.instant(patternLabel),
|
||||
});
|
||||
patternFormGroup.patchValue(newPatternObjWithLabel);
|
||||
|
||||
@@ -412,7 +407,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches the LDN service by retrieving and sending patch operations geenrated in generatePatchOperations()
|
||||
* Patches the LDN service by retrieving and sending patch operations generated in generatePatchOperations()
|
||||
*/
|
||||
patchService() {
|
||||
this.deleteMarkedInboundPatterns();
|
||||
@@ -425,17 +420,6 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
const notifyServiceInboundPatterns = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
|
||||
const deletedInboundPatternsLength = this.deletedInboundPatterns.length;
|
||||
// If no inbound patterns are specified, close the modal and return
|
||||
// notify the user that no patterns are specified
|
||||
if (notifyServiceInboundPatterns.length === deletedInboundPatternsLength) {
|
||||
this.notificationService.warning(this.translateService.get('ldn-service-notification.created.warning.title'));
|
||||
this.deletedInboundPatterns = [];
|
||||
this.closeModal();
|
||||
return;
|
||||
}
|
||||
|
||||
this.ldnServicesService.patch(this.ldnService, patchOperations).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
).subscribe(
|
||||
@@ -571,7 +555,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
|
||||
private createInboundPatternFormGroup(): FormGroup {
|
||||
const inBoundFormGroup = {
|
||||
pattern: '',
|
||||
patternLabel: this.translateService.instant(this.selectPatternDefaultLabeli18Key),
|
||||
patternLabel: this.translateService.instant(this.selectPatternDefaultLabelI18Key),
|
||||
constraint: '',
|
||||
constraintFormatted: '',
|
||||
automatic: false,
|
||||
|
@@ -82,10 +82,10 @@
|
||||
<div>
|
||||
{{ 'service.overview.delete.body' | translate }}
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div class="mt-4 text-right">
|
||||
<button (click)="closeModal()"
|
||||
[attr.aria-label]="'ldn-service-overview-close-modal' | translate"
|
||||
class="btn btn-primary mr-2">{{ 'service.detail.delete.cancel' | translate }}</button>
|
||||
class="btn btn-outline-secondary mr-2">{{ 'service.detail.delete.cancel' | translate }}</button>
|
||||
<button (click)="deleteSelected(this.selectedServiceId.toString(), ldnServicesService)"
|
||||
class="btn btn-danger"
|
||||
[attr.aria-label]="'ldn-service-overview-select-delete' | translate"
|
||||
|
@@ -11,6 +11,8 @@ export const notifyPatterns = [
|
||||
|
||||
'request-review',
|
||||
|
||||
'announce-relationship',
|
||||
|
||||
];
|
||||
|
||||
|
||||
|
@@ -7,6 +7,8 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { APP_CONFIG } from '../../../config/app-config.interface';
|
||||
import { environment } from '../../../environments/environment.test';
|
||||
import { buildPaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { SearchService } from '../../core/shared/search/search.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
@@ -28,9 +30,89 @@ describe('AdminNotifyDashboardComponent', () => {
|
||||
let searchResult3;
|
||||
let results;
|
||||
|
||||
const mockBoxes = [
|
||||
{ title: 'admin-notify-dashboard.received-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] },
|
||||
{ title: 'admin-notify-dashboard.generated-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] },
|
||||
const mockBoxes = [
|
||||
{
|
||||
title: 'admin-notify-dashboard.received-ldn',
|
||||
boxes: [
|
||||
{
|
||||
color: '#B8DAFF',
|
||||
title: 'admin-notify-dashboard.NOTIFY.incoming.accepted',
|
||||
config: 'NOTIFY.incoming.accepted',
|
||||
description: 'admin-notify-dashboard.NOTIFY.incoming.accepted.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#D4EDDA',
|
||||
title: 'admin-notify-dashboard.NOTIFY.incoming.processed',
|
||||
config: 'NOTIFY.incoming.processed',
|
||||
description: 'admin-notify-dashboard.NOTIFY.incoming.processed.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#FDBBC7',
|
||||
title: 'admin-notify-dashboard.NOTIFY.incoming.failure',
|
||||
config: 'NOTIFY.incoming.failure',
|
||||
description: 'admin-notify-dashboard.NOTIFY.incoming.failure.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#FDBBC7',
|
||||
title: 'admin-notify-dashboard.NOTIFY.incoming.untrusted',
|
||||
config: 'NOTIFY.incoming.untrusted',
|
||||
description: 'admin-notify-dashboard.NOTIFY.incoming.untrusted.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#43515F',
|
||||
title: 'admin-notify-dashboard.NOTIFY.incoming.involvedItems',
|
||||
textColor: '#fff',
|
||||
config: 'NOTIFY.incoming.involvedItems',
|
||||
description: 'admin-notify-dashboard.NOTIFY.incoming.involvedItems.description',
|
||||
count: undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'admin-notify-dashboard.generated-ldn',
|
||||
boxes: [
|
||||
{
|
||||
color: '#D4EDDA',
|
||||
title: 'admin-notify-dashboard.NOTIFY.outgoing.delivered',
|
||||
config: 'NOTIFY.outgoing.delivered',
|
||||
description: 'admin-notify-dashboard.NOTIFY.outgoing.delivered.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#B8DAFF',
|
||||
title: 'admin-notify-dashboard.NOTIFY.outgoing.queued',
|
||||
config: 'NOTIFY.outgoing.queued',
|
||||
description: 'admin-notify-dashboard.NOTIFY.outgoing.queued.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#FDEEBB',
|
||||
title: 'admin-notify-dashboard.NOTIFY.outgoing.queued_for_retry',
|
||||
config: 'NOTIFY.outgoing.queued_for_retry',
|
||||
description: 'admin-notify-dashboard.NOTIFY.outgoing.queued_for_retry.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#FDBBC7',
|
||||
title: 'admin-notify-dashboard.NOTIFY.outgoing.failure',
|
||||
config: 'NOTIFY.outgoing.failure',
|
||||
description: 'admin-notify-dashboard.NOTIFY.outgoing.failure.description',
|
||||
count: undefined,
|
||||
},
|
||||
{
|
||||
color: '#43515F',
|
||||
title: 'admin-notify-dashboard.NOTIFY.outgoing.involvedItems',
|
||||
textColor: '#fff',
|
||||
config: 'NOTIFY.outgoing.involvedItems',
|
||||
description: 'admin-notify-dashboard.NOTIFY.outgoing.involvedItems.description',
|
||||
count: undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -45,6 +127,7 @@ describe('AdminNotifyDashboardComponent', () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), NgbNavModule, AdminNotifyDashboardComponent],
|
||||
providers: [
|
||||
{ provide: APP_CONFIG, useValue: environment },
|
||||
{ provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results) } },
|
||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
||||
],
|
||||
|
@@ -4,17 +4,21 @@ import {
|
||||
} from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
Inject,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
forkJoin,
|
||||
Observable,
|
||||
} from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { environment } from '../../../environments/environment';
|
||||
import {
|
||||
APP_CONFIG,
|
||||
AppConfig,
|
||||
} from '../../../config/app-config.interface';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
|
||||
import { SearchService } from '../../core/shared/search/search.service';
|
||||
@@ -51,20 +55,25 @@ import {
|
||||
/**
|
||||
* Component used for visual representation and search of LDN messages for Admins
|
||||
*/
|
||||
export class AdminNotifyDashboardComponent implements OnInit{
|
||||
export class AdminNotifyDashboardComponent implements OnInit {
|
||||
|
||||
public notifyMetricsRows$: Observable<AdminNotifyMetricsRow[]>;
|
||||
public notifyMetricsRows$: BehaviorSubject<AdminNotifyMetricsRow[]> = new BehaviorSubject<AdminNotifyMetricsRow[]>([]);
|
||||
|
||||
private metricsConfig: AdminNotifyMetricsRow[];
|
||||
|
||||
private metricsConfig = environment.notifyMetrics;
|
||||
private singleResultOptions = Object.assign(new PaginationComponentOptions(), {
|
||||
id: 'single-result-options',
|
||||
pageSize: 1,
|
||||
});
|
||||
|
||||
constructor(private searchService: SearchService) {
|
||||
constructor(
|
||||
@Inject(APP_CONFIG) protected appConfig: AppConfig,
|
||||
private searchService: SearchService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.metricsConfig = this.appConfig.notifyMetrics;
|
||||
const mertricsRowsConfigurations = this.metricsConfig
|
||||
.map(row => row.boxes)
|
||||
.map(boxes => boxes.map(box => box.config).filter(config => !!config));
|
||||
@@ -74,15 +83,18 @@ export class AdminNotifyDashboardComponent implements OnInit{
|
||||
{ configuration: config, pagination: this.singleResultOptions },
|
||||
));
|
||||
|
||||
this.notifyMetricsRows$ = forkJoin(searchConfigurations.map(config => this.searchService.search(config)
|
||||
.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
map(response => this.mapSearchObjectsToMetricsBox(response.payload)),
|
||||
forkJoin(
|
||||
searchConfigurations.map(config => this.searchService.search(config)
|
||||
.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
map(response => this.mapSearchObjectsToMetricsBox(config.configuration, response.payload)),
|
||||
),
|
||||
),
|
||||
),
|
||||
).pipe(
|
||||
map(metricBoxes => this.mapUpdatedBoxesToMetricsRows(metricBoxes)),
|
||||
);
|
||||
).subscribe((metricBoxes: AdminNotifyMetricsRow[]) => {
|
||||
this.notifyMetricsRows$.next(metricBoxes);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,13 +103,12 @@ export class AdminNotifyDashboardComponent implements OnInit{
|
||||
* @param searchObject The object to map
|
||||
* @private
|
||||
*/
|
||||
private mapSearchObjectsToMetricsBox(searchObject: SearchObjects<DSpaceObject>): AdminNotifyMetricsBox {
|
||||
private mapSearchObjectsToMetricsBox(configuration: string, searchObject: SearchObjects<DSpaceObject>): AdminNotifyMetricsBox {
|
||||
const count = searchObject.pageInfo.totalElements;
|
||||
const objectConfig = searchObject.configuration;
|
||||
const metricsBoxes = [].concat(...this.metricsConfig.map((config) => config.boxes));
|
||||
const metricsBoxes = [].concat(...this.metricsConfig.map((config: AdminNotifyMetricsRow) => config.boxes));
|
||||
|
||||
return {
|
||||
...metricsBoxes.find(box => box.config === objectConfig),
|
||||
...metricsBoxes.find(box => box.config === configuration),
|
||||
count,
|
||||
};
|
||||
}
|
||||
|
@@ -27,12 +27,12 @@ import { WORKSPACEITEM } from './eperson/models/workspaceitem.resource-type';
|
||||
import { FEEDBACK } from './feedback/models/feedback.resource-type';
|
||||
import { METADATA_FIELD } from './metadata/metadata-field.resource-type';
|
||||
import { METADATA_SCHEMA } from './metadata/metadata-schema.resource-type';
|
||||
import { SUGGESTION } from './notifications/models/suggestion-objects.resource-type';
|
||||
import { SUGGESTION_SOURCE } from './notifications/models/suggestion-source-object.resource-type';
|
||||
import { SUGGESTION_TARGET } from './notifications/models/suggestion-target-object.resource-type';
|
||||
import { QUALITY_ASSURANCE_EVENT_OBJECT } from './notifications/qa/models/quality-assurance-event-object.resource-type';
|
||||
import { QUALITY_ASSURANCE_SOURCE_OBJECT } from './notifications/qa/models/quality-assurance-source-object.resource-type';
|
||||
import { QUALITY_ASSURANCE_TOPIC_OBJECT } from './notifications/qa/models/quality-assurance-topic-object.resource-type';
|
||||
import { SUGGESTION } from './notifications/suggestions/models/suggestion-objects.resource-type';
|
||||
import { SUGGESTION_SOURCE } from './notifications/suggestions/models/suggestion-source-object.resource-type';
|
||||
import { SUGGESTION_TARGET } from './notifications/suggestions/models/suggestion-target-object.resource-type';
|
||||
import { ORCID_HISTORY } from './orcid/model/orcid-history.resource-type';
|
||||
import { ORCID_QUEUE } from './orcid/model/orcid-queue.resource-type';
|
||||
import { RESEARCHER_PROFILE } from './profile/model/researcher-profile.resource-type';
|
||||
@@ -131,9 +131,9 @@ export const LAZY_DATA_SERVICES: LazyDataServicesMap = new Map([
|
||||
[QUALITY_ASSURANCE_EVENT_OBJECT.value, () => import('./notifications/qa/events/quality-assurance-event-data.service').then(m => m.QualityAssuranceEventDataService)],
|
||||
[QUALITY_ASSURANCE_SOURCE_OBJECT.value, () => import('./notifications/qa/source/quality-assurance-source-data.service').then(m => m.QualityAssuranceSourceDataService)],
|
||||
[QUALITY_ASSURANCE_TOPIC_OBJECT.value, () => import('./notifications/qa/topics/quality-assurance-topic-data.service').then(m => m.QualityAssuranceTopicDataService)],
|
||||
[SUGGESTION.value, () => import('./notifications/suggestions-data.service').then(m => m.SuggestionsDataService)],
|
||||
[SUGGESTION_SOURCE.value, () => import('./notifications/source/suggestion-source-data.service').then(m => m.SuggestionSourceDataService)],
|
||||
[SUGGESTION_TARGET.value, () => import('./notifications/target/suggestion-target-data.service').then(m => m.SuggestionTargetDataService)],
|
||||
[SUGGESTION.value, () => import('./notifications/suggestions/suggestion-data.service').then(m => m.SuggestionDataService)],
|
||||
[SUGGESTION_SOURCE.value, () => import('./notifications/suggestions/source/suggestion-source-data.service').then(m => m.SuggestionSourceDataService)],
|
||||
[SUGGESTION_TARGET.value, () => import('./notifications/suggestions/target/suggestion-target-data.service').then(m => m.SuggestionTargetDataService)],
|
||||
[DUPLICATE.value, () => import('./submission/submission-duplicate-data.service').then(m => m.SubmissionDuplicateDataService)],
|
||||
[CorrectionType.type.value, () => import('./submission/correctiontype-data.service').then(m => m.CorrectionTypeDataService)],
|
||||
]);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
|
||||
/**
|
||||
* The resource type for the Suggestion object
|
@@ -1,4 +1,4 @@
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
|
||||
/**
|
||||
* The resource type for the Suggestion Source object
|
@@ -3,11 +3,11 @@ import {
|
||||
deserialize,
|
||||
} from 'cerialize';
|
||||
|
||||
import { typedObject } from '../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../shared/hal-link.model';
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||
import { typedObject } from '../../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../../shared/hal-link.model';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../../utilities/equals.decorators';
|
||||
import { SUGGESTION_SOURCE } from './suggestion-source-object.resource-type';
|
||||
|
||||
/**
|
@@ -1,4 +1,4 @@
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
|
||||
/**
|
||||
* The resource type for the Suggestion Target object
|
@@ -3,11 +3,11 @@ import {
|
||||
deserialize,
|
||||
} from 'cerialize';
|
||||
|
||||
import { typedObject } from '../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../shared/hal-link.model';
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||
import { typedObject } from '../../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../../shared/hal-link.model';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../../utilities/equals.decorators';
|
||||
import { SUGGESTION_TARGET } from './suggestion-target-object.resource-type';
|
||||
|
||||
/**
|
@@ -4,15 +4,15 @@ import {
|
||||
deserialize,
|
||||
} from 'cerialize';
|
||||
|
||||
import { typedObject } from '../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../shared/hal-link.model';
|
||||
import { typedObject } from '../../../cache/builders/build-decorators';
|
||||
import { CacheableObject } from '../../../cache/cacheable-object.model';
|
||||
import { HALLink } from '../../../shared/hal-link.model';
|
||||
import {
|
||||
MetadataMap,
|
||||
MetadataMapSerializer,
|
||||
} from '../../shared/metadata.models';
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||
} from '../../../shared/metadata.models';
|
||||
import { ResourceType } from '../../../shared/resource-type';
|
||||
import { excludeFromEquals } from '../../../utilities/equals.decorators';
|
||||
import { SUGGESTION } from './suggestion-objects.resource-type';
|
||||
|
||||
/**
|
@@ -7,21 +7,21 @@ import {
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { RestResponse } from '../../cache/response.models';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { FindAllData } from '../../data/base/find-all-data';
|
||||
import { testFindAllDataImplementation } from '../../data/base/find-all-data.spec';
|
||||
import { DefaultChangeAnalyzer } from '../../data/default-change-analyzer.service';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { GetRequest } from '../../data/request.models';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../../../cache/object-cache.service';
|
||||
import { RestResponse } from '../../../cache/response.models';
|
||||
import { CoreState } from '../../../core-state.model';
|
||||
import { FindAllData } from '../../../data/base/find-all-data';
|
||||
import { testFindAllDataImplementation } from '../../../data/base/find-all-data.spec';
|
||||
import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service';
|
||||
import { RemoteData } from '../../../data/remote-data';
|
||||
import { GetRequest } from '../../../data/request.models';
|
||||
import { RequestService } from '../../../data/request.service';
|
||||
import { RequestEntry } from '../../../data/request-entry.model';
|
||||
import { RequestEntryState } from '../../../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../../../shared/hal-endpoint.service';
|
||||
import { SuggestionSource } from '../models/suggestion-source.model';
|
||||
import { SuggestionSourceDataService } from './suggestion-source-data.service';
|
||||
|
@@ -3,22 +3,22 @@ import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../../../cache/object-cache.service';
|
||||
import { CoreState } from '../../../core-state.model';
|
||||
import {
|
||||
FindAllData,
|
||||
FindAllDataImpl,
|
||||
} from '../../data/base/find-all-data';
|
||||
import { IdentifiableDataService } from '../../data/base/identifiable-data.service';
|
||||
import { DefaultChangeAnalyzer } from '../../data/default-change-analyzer.service';
|
||||
import { FindListOptions } from '../../data/find-list-options.model';
|
||||
import { PaginatedList } from '../../data/paginated-list.model';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
} from '../../../data/base/find-all-data';
|
||||
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
||||
import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service';
|
||||
import { FindListOptions } from '../../../data/find-list-options.model';
|
||||
import { PaginatedList } from '../../../data/paginated-list.model';
|
||||
import { RemoteData } from '../../../data/remote-data';
|
||||
import { RequestService } from '../../../data/request.service';
|
||||
import { HALEndpointService } from '../../../shared/hal-endpoint.service';
|
||||
import { SuggestionSource } from '../models/suggestion-source.model';
|
||||
|
||||
/**
|
@@ -6,22 +6,22 @@ import {
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
import { RemoteData } from '../data/remote-data';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { RequestEntry } from '../data/request-entry.model';
|
||||
import { RequestEntryState } from '../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { SuggestionsDataService } from './suggestions-data.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { RestResponse } from '../../cache/response.models';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { SuggestionDataService } from './suggestion-data.service';
|
||||
|
||||
describe('SuggestionDataService test', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: SuggestionsDataService;
|
||||
let service: SuggestionDataService;
|
||||
let requestService: RequestService;
|
||||
let rdbService: RemoteDataBuildService;
|
||||
let objectCache: ObjectCacheService;
|
||||
@@ -40,7 +40,7 @@ describe('SuggestionDataService test', () => {
|
||||
};
|
||||
|
||||
function initTestService() {
|
||||
return new SuggestionsDataService(
|
||||
return new SuggestionDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
objectCache,
|
@@ -2,32 +2,31 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import {
|
||||
DeleteData,
|
||||
DeleteDataImpl,
|
||||
} from '../data/base/delete-data';
|
||||
import { IdentifiableDataService } from '../data/base/identifiable-data.service';
|
||||
import { SearchDataImpl } from '../data/base/search-data';
|
||||
import { FindListOptions } from '../data/find-list-options.model';
|
||||
import { PaginatedList } from '../data/paginated-list.model';
|
||||
import { RemoteData } from '../data/remote-data';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
} from '../../data/base/delete-data';
|
||||
import { IdentifiableDataService } from '../../data/base/identifiable-data.service';
|
||||
import { SearchDataImpl } from '../../data/base/search-data';
|
||||
import { FindListOptions } from '../../data/find-list-options.model';
|
||||
import { PaginatedList } from '../../data/paginated-list.model';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NoContent } from '../../shared/NoContent.model';
|
||||
import { Suggestion } from './models/suggestion.model';
|
||||
|
||||
/**
|
||||
* The service handling all Suggestion Target REST requests.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SuggestionsDataService extends IdentifiableDataService<Suggestion> {
|
||||
export class SuggestionDataService extends IdentifiableDataService<Suggestion> {
|
||||
|
||||
protected searchFindBySourceMethod = 'findBySource';
|
||||
protected searchFindByTargetAndSourceMethod = 'findByTargetAndSource';
|
||||
|
||||
private deleteData: DeleteData<Suggestion>;
|
@@ -7,24 +7,24 @@ import {
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { RestResponse } from '../../cache/response.models';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { FindAllData } from '../../data/base/find-all-data';
|
||||
import { testFindAllDataImplementation } from '../../data/base/find-all-data.spec';
|
||||
import { SearchData } from '../../data/base/search-data';
|
||||
import { testSearchDataImplementation } from '../../data/base/search-data.spec';
|
||||
import { DefaultChangeAnalyzer } from '../../data/default-change-analyzer.service';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { GetRequest } from '../../data/request.models';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
|
||||
import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../../cache/object-cache.service';
|
||||
import { RestResponse } from '../../../cache/response.models';
|
||||
import { CoreState } from '../../../core-state.model';
|
||||
import { FindAllData } from '../../../data/base/find-all-data';
|
||||
import { testFindAllDataImplementation } from '../../../data/base/find-all-data.spec';
|
||||
import { SearchData } from '../../../data/base/search-data';
|
||||
import { testSearchDataImplementation } from '../../../data/base/search-data.spec';
|
||||
import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service';
|
||||
import { RemoteData } from '../../../data/remote-data';
|
||||
import { GetRequest } from '../../../data/request.models';
|
||||
import { RequestService } from '../../../data/request.service';
|
||||
import { RequestEntry } from '../../../data/request-entry.model';
|
||||
import { RequestEntryState } from '../../../data/request-entry-state.model';
|
||||
import { HALEndpointService } from '../../../shared/hal-endpoint.service';
|
||||
import { SuggestionTarget } from '../models/suggestion-target.model';
|
||||
import { SuggestionTargetDataService } from './suggestion-target-data.service';
|
||||
|
||||
@@ -131,7 +131,7 @@ describe('SuggestionTargetDataService test', () => {
|
||||
};
|
||||
const searchFindBySourceMethod = 'findBySource';
|
||||
const expected = new GetRequest(requestService.generateRequestId(), `${endpointURL}/search/${searchFindBySourceMethod}?source=testId`);
|
||||
scheduler.schedule(() => service.getTargets('testId', options).subscribe());
|
||||
scheduler.schedule(() => service.getTargetsBySource('testId', options).subscribe());
|
||||
scheduler.flush();
|
||||
|
||||
expect(requestService.send).toHaveBeenCalledWith(expected, true);
|
@@ -3,27 +3,27 @@ import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../../../cache/builders/remote-data-build.service';
|
||||
import { RequestParam } from '../../../cache/models/request-param.model';
|
||||
import { ObjectCacheService } from '../../../cache/object-cache.service';
|
||||
import { CoreState } from '../../../core-state.model';
|
||||
import {
|
||||
FindAllData,
|
||||
FindAllDataImpl,
|
||||
} from '../../data/base/find-all-data';
|
||||
import { IdentifiableDataService } from '../../data/base/identifiable-data.service';
|
||||
} from '../../../data/base/find-all-data';
|
||||
import { IdentifiableDataService } from '../../../data/base/identifiable-data.service';
|
||||
import {
|
||||
SearchData,
|
||||
SearchDataImpl,
|
||||
} from '../../data/base/search-data';
|
||||
import { DefaultChangeAnalyzer } from '../../data/default-change-analyzer.service';
|
||||
import { FindListOptions } from '../../data/find-list-options.model';
|
||||
import { PaginatedList } from '../../data/paginated-list.model';
|
||||
import { RemoteData } from '../../data/remote-data';
|
||||
import { RequestService } from '../../data/request.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
} from '../../../data/base/search-data';
|
||||
import { DefaultChangeAnalyzer } from '../../../data/default-change-analyzer.service';
|
||||
import { FindListOptions } from '../../../data/find-list-options.model';
|
||||
import { PaginatedList } from '../../../data/paginated-list.model';
|
||||
import { RemoteData } from '../../../data/remote-data';
|
||||
import { RequestService } from '../../../data/request.service';
|
||||
import { HALEndpointService } from '../../../shared/hal-endpoint.service';
|
||||
import { SuggestionTarget } from '../models/suggestion-target.model';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -55,19 +55,26 @@ export class SuggestionTargetDataService extends IdentifiableDataService<Suggest
|
||||
* The source for which to find targets.
|
||||
* @param options
|
||||
* 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
|
||||
* @param linksToFollow
|
||||
* List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved.
|
||||
*
|
||||
* @return Observable<RemoteData<PaginatedList<SuggestionTarget>>>
|
||||
* The list of Suggestion Target.
|
||||
*/
|
||||
public getTargets(
|
||||
public getTargetsBySource(
|
||||
source: string,
|
||||
options: FindListOptions = {},
|
||||
useCachedVersionIfAvailable = true,
|
||||
reRequestOnStale = true,
|
||||
...linksToFollow: FollowLinkConfig<SuggestionTarget>[]
|
||||
): Observable<RemoteData<PaginatedList<SuggestionTarget>>> {
|
||||
options.searchParams = [new RequestParam('source', source)];
|
||||
|
||||
return this.searchBy(this.searchFindBySourceMethod, options, true, true, ...linksToFollow);
|
||||
return this.searchBy(this.searchFindBySourceMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
@@ -30,11 +30,11 @@ import { EPerson } from './eperson/models/eperson.model';
|
||||
import { Group } from './eperson/models/group.model';
|
||||
import { MetadataField } from './metadata/metadata-field.model';
|
||||
import { MetadataSchema } from './metadata/metadata-schema.model';
|
||||
import { SuggestionSource } from './notifications/models/suggestion-source.model';
|
||||
import { SuggestionTarget } from './notifications/models/suggestion-target.model';
|
||||
import { QualityAssuranceEventObject } from './notifications/qa/models/quality-assurance-event.model';
|
||||
import { QualityAssuranceSourceObject } from './notifications/qa/models/quality-assurance-source.model';
|
||||
import { QualityAssuranceTopicObject } from './notifications/qa/models/quality-assurance-topic.model';
|
||||
import { SuggestionSource } from './notifications/suggestions/models/suggestion-source.model';
|
||||
import { SuggestionTarget } from './notifications/suggestions/models/suggestion-target.model';
|
||||
import { OrcidHistory } from './orcid/model/orcid-history.model';
|
||||
import { OrcidQueue } from './orcid/model/orcid-queue.model';
|
||||
import { ResearcherProfile } from './profile/model/researcher-profile.model';
|
||||
|
@@ -94,11 +94,11 @@
|
||||
</ds-item-page-uri-field>
|
||||
<ds-item-page-uri-field [item]="object"
|
||||
[fields]="['datacite.relation.isSupplementedBy']"
|
||||
[label]="'item.page.dataset'">
|
||||
[label]="'item.page.supplemented'">
|
||||
</ds-item-page-uri-field>
|
||||
<ds-item-page-uri-field [item]="object"
|
||||
[fields]="['datacite.relation.isReferencedBy']"
|
||||
[label]="'item.page.dataset'">
|
||||
[label]="'item.page.referenced'">
|
||||
</ds-item-page-uri-field>
|
||||
<div>
|
||||
<a class="btn btn-outline-primary" role="button" [routerLink]="[itemPageRoute + '/full']">
|
||||
|
@@ -80,11 +80,11 @@
|
||||
</ds-item-page-uri-field>
|
||||
<ds-item-page-uri-field [item]="object"
|
||||
[fields]="['datacite.relation.isSupplementedBy']"
|
||||
[label]="'item.page.dataset'">
|
||||
[label]="'item.page.supplemented'">
|
||||
</ds-item-page-uri-field>
|
||||
<ds-item-page-uri-field [item]="object"
|
||||
[fields]="['datacite.relation.isReferencedBy']"
|
||||
[label]="'item.page.dataset'">
|
||||
[label]="'item.page.referenced'">
|
||||
</ds-item-page-uri-field>
|
||||
<ds-item-page-cc-license-field [item]="object" [variant]="'full'">
|
||||
</ds-item-page-cc-license-field>
|
||||
|
@@ -12,7 +12,7 @@ import {
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
import { Suggestion } from '../../core/notifications/models/suggestion.model';
|
||||
import { Suggestion } from '../../core/notifications/suggestions/models/suggestion.model';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { ItemType } from '../../core/shared/item-relationships/item-type.model';
|
||||
import { ThemedCreateItemParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Suggestion } from '../../core/notifications/models/suggestion.model';
|
||||
import { Suggestion } from '../../core/notifications/suggestions/models/suggestion.model';
|
||||
|
||||
/**
|
||||
* A simple interface to unite a specific suggestion and the id of the chosen collection
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { SuggestionEvidences } from '../../../core/notifications/models/suggestion.model';
|
||||
import { SuggestionEvidences } from '../../../core/notifications/suggestions/models/suggestion.model';
|
||||
import { fadeIn } from '../../../shared/animations/fade';
|
||||
import { ObjectKeysPipe } from '../../../shared/utils/object-keys-pipe';
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
} from '@angular/core';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Suggestion } from 'src/app/core/notifications/models/suggestion.model';
|
||||
import { Suggestion } from 'src/app/core/notifications/suggestions/models/suggestion.model';
|
||||
|
||||
import { ItemSearchResultListElementComponent } from '../../../themes/custom/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
|
@@ -22,7 +22,7 @@ import {
|
||||
take,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { SuggestionTarget } from '../../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { PaginationService } from '../../../core/pagination/pagination.service';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component';
|
||||
@@ -55,14 +55,14 @@ export class PublicationClaimComponent implements OnInit {
|
||||
/**
|
||||
* The source for which to list targets
|
||||
*/
|
||||
@Input() source: string;
|
||||
@Input() source = '';
|
||||
|
||||
/**
|
||||
* The pagination system configuration for HTML listing.
|
||||
* @type {PaginationComponentOptions}
|
||||
*/
|
||||
public paginationConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
|
||||
id: 'stp',
|
||||
id: 'stp_' + this.source,
|
||||
pageSizeOptions: [5, 10, 20, 40, 60],
|
||||
});
|
||||
|
||||
@@ -99,11 +99,16 @@ export class PublicationClaimComponent implements OnInit {
|
||||
* Component initialization.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.targets$ = this.suggestionTargetsStateService.getSuggestionTargets();
|
||||
this.totalElements$ = this.suggestionTargetsStateService.getSuggestionTargetsTotals();
|
||||
this.targets$ = this.suggestionTargetsStateService.getSuggestionTargets(this.source);
|
||||
this.totalElements$ = this.suggestionTargetsStateService.getSuggestionTargetsTotals(this.source);
|
||||
}
|
||||
|
||||
/**
|
||||
* First Suggestion Targets loading after view initialization.
|
||||
*/
|
||||
ngAfterViewInit(): void {
|
||||
this.subs.push(
|
||||
this.suggestionTargetsStateService.isSuggestionTargetsLoaded().pipe(
|
||||
this.suggestionTargetsStateService.isSuggestionTargetsLoaded(this.source).pipe(
|
||||
take(1),
|
||||
).subscribe(() => {
|
||||
this.getSuggestionTargets();
|
||||
@@ -118,7 +123,7 @@ export class PublicationClaimComponent implements OnInit {
|
||||
* 'true' if the targets are loading, 'false' otherwise.
|
||||
*/
|
||||
public isTargetsLoading(): Observable<boolean> {
|
||||
return this.suggestionTargetsStateService.isSuggestionTargetsLoading();
|
||||
return this.suggestionTargetsStateService.isSuggestionTargetsLoading(this.source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +133,7 @@ export class PublicationClaimComponent implements OnInit {
|
||||
* 'true' if there are operations running on the targets (ex.: a REST call), 'false' otherwise.
|
||||
*/
|
||||
public isTargetsProcessing(): Observable<boolean> {
|
||||
return this.suggestionTargetsStateService.isSuggestionTargetsProcessing();
|
||||
return this.suggestionTargetsStateService.isSuggestionTargetsProcessing(this.source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +150,7 @@ export class PublicationClaimComponent implements OnInit {
|
||||
* Unsubscribe from all subscriptions.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.suggestionTargetsStateService.dispatchClearSuggestionTargetsAction();
|
||||
this.suggestionTargetsStateService.dispatchClearSuggestionTargetsAction(this.source);
|
||||
this.subs
|
||||
.filter((sub) => hasValue(sub))
|
||||
.forEach((sub) => sub.unsubscribe());
|
||||
|
116
src/app/notifications/suggestion-targets/selectors.ts
Normal file
116
src/app/notifications/suggestion-targets/selectors.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
createFeatureSelector,
|
||||
createSelector,
|
||||
MemoizedSelector,
|
||||
} from '@ngrx/store';
|
||||
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { subStateSelector } from '../../submission/selectors';
|
||||
import {
|
||||
suggestionNotificationsSelector,
|
||||
SuggestionNotificationsState,
|
||||
} from '../notifications.reducer';
|
||||
import {
|
||||
SuggestionTargetEntry,
|
||||
SuggestionTargetState,
|
||||
} from './suggestion-targets.reducer';
|
||||
|
||||
/**
|
||||
* Returns the Reciter Suggestion Target state.
|
||||
* @function _getSuggestionTargetState
|
||||
* @param {AppState} state Top level state.
|
||||
* @return {SuggestionNotificationsState}
|
||||
*/
|
||||
const _getSuggestionTargetState = createFeatureSelector<SuggestionNotificationsState>('suggestionNotifications');
|
||||
|
||||
// Suggestion Targets selectors
|
||||
|
||||
/**
|
||||
* Returns the Suggestion Targets State.
|
||||
* @function suggestionTargetStateSelector
|
||||
* @return {SuggestionNotificationsState}
|
||||
*/
|
||||
export function suggestionTargetStateSelector(): MemoizedSelector<SuggestionNotificationsState, SuggestionTargetState> {
|
||||
return subStateSelector<SuggestionNotificationsState, SuggestionTargetState>(suggestionNotificationsSelector, 'suggestionTarget');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Reciter Suggestion source state
|
||||
* @function suggestionSourceSelector
|
||||
* @return {SuggestionTargetEntry}
|
||||
*/
|
||||
export function suggestionSourceSelector(source: string): MemoizedSelector<SuggestionNotificationsState, SuggestionTargetEntry> {
|
||||
return createSelector(suggestionTargetStateSelector(),(state: SuggestionTargetState) => state.sources[source]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Suggestion Targets list by source.
|
||||
* @function suggestionTargetObjectSelector
|
||||
* @return {SuggestionTarget[]}
|
||||
*/
|
||||
export function suggestionTargetObjectSelector(source: string): MemoizedSelector<SuggestionNotificationsState, SuggestionTarget[]> {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state.targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Suggestion Targets are loaded.
|
||||
* @function isSuggestionTargetLoadedSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isSuggestionTargetLoadedSelector = (source: string) => {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.loaded || false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the deduplication sets are processing.
|
||||
* @function isSuggestionTargetProcessingSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isSuggestionTargetProcessingSelector = (source: string) => {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.processing || false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the total available pages of Reciter Suggestion Targets.
|
||||
* @function getSuggestionTargetTotalPagesSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetTotalPagesSelector = (source: string) => {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.totalPages || 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current page of Suggestion Targets.
|
||||
* @function getSuggestionTargetCurrentPageSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetCurrentPageSelector = (source: string) => {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.currentPage || 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the total number of Suggestion Targets.
|
||||
* @function getSuggestionTargetTotalsSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetTotalsSelector = (source: string) => {
|
||||
return createSelector(suggestionSourceSelector(source), (state: SuggestionTargetEntry) => state?.totalElements || 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns Suggestion Targets for the current user.
|
||||
* @function getCurrentUserSuggestionTargetsSelector
|
||||
* @return {SuggestionTarget[]}
|
||||
*/
|
||||
export const getCurrentUserSuggestionTargetsSelector = () => {
|
||||
return createSelector(suggestionTargetStateSelector(), (state: SuggestionTargetState) => state?.currentUserTargets || []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not the user has consulted their suggestions
|
||||
* @function getCurrentUserSuggestionTargetsVisitedSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const getCurrentUserSuggestionTargetsVisitedSelector = () => {
|
||||
return createSelector(suggestionTargetStateSelector(), (state: SuggestionTargetState) => state?.currentUserTargetsVisited || false);
|
||||
};
|
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { type } from '../../shared/ngrx/type';
|
||||
|
||||
/**
|
||||
@@ -23,10 +23,8 @@ export const SuggestionTargetActionTypes = {
|
||||
MARK_USER_SUGGESTIONS_AS_VISITED: type('dspace/integration/openaire/suggestions/target/MARK_USER_SUGGESTIONS_AS_VISITED'),
|
||||
};
|
||||
|
||||
/* tslint:disable:max-classes-per-file */
|
||||
|
||||
/**
|
||||
* An ngrx action to retrieve all the Suggestion Targets.
|
||||
* A ngrx action to retrieve all the Suggestion Targets.
|
||||
*/
|
||||
export class RetrieveTargetsBySourceAction implements Action {
|
||||
type = SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE;
|
||||
@@ -56,18 +54,34 @@ export class RetrieveTargetsBySourceAction implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action for retrieving 'all Suggestion Targets' error.
|
||||
* A ngrx action for notifying error.
|
||||
*/
|
||||
export class RetrieveAllTargetsErrorAction implements Action {
|
||||
export class RetrieveTargetsBySourceErrorAction implements Action {
|
||||
type = SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE_ERROR;
|
||||
payload: {
|
||||
source: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new RetrieveTargetsBySourceAction.
|
||||
*
|
||||
* @param source
|
||||
* the source for which to retrieve suggestion targets
|
||||
*/
|
||||
constructor(source: string) {
|
||||
this.payload = {
|
||||
source,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to load the Suggestion Target objects.
|
||||
* A ngrx action to load the Suggestion Target objects.
|
||||
*/
|
||||
export class AddTargetAction implements Action {
|
||||
type = SuggestionTargetActionTypes.ADD_TARGETS;
|
||||
payload: {
|
||||
source: string;
|
||||
targets: SuggestionTarget[];
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
@@ -77,6 +91,8 @@ export class AddTargetAction implements Action {
|
||||
/**
|
||||
* Create a new AddTargetAction.
|
||||
*
|
||||
* @param source
|
||||
* the source of suggestion targets
|
||||
* @param targets
|
||||
* the list of targets
|
||||
* @param totalPages
|
||||
@@ -86,8 +102,9 @@ export class AddTargetAction implements Action {
|
||||
* @param totalElements
|
||||
* the total available Suggestion Targets
|
||||
*/
|
||||
constructor(targets: SuggestionTarget[], totalPages: number, currentPage: number, totalElements: number) {
|
||||
constructor(source: string, targets: SuggestionTarget[], totalPages: number, currentPage: number, totalElements: number) {
|
||||
this.payload = {
|
||||
source,
|
||||
targets,
|
||||
totalPages,
|
||||
currentPage,
|
||||
@@ -98,7 +115,7 @@ export class AddTargetAction implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to load the user Suggestion Target object.
|
||||
* A ngrx action to load the user Suggestion Target object.
|
||||
* Called by the ??? effect.
|
||||
*/
|
||||
export class AddUserSuggestionsAction implements Action {
|
||||
@@ -120,7 +137,7 @@ export class AddUserSuggestionsAction implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to reload the user Suggestion Target object.
|
||||
* A ngrx action to reload the user Suggestion Target object.
|
||||
* Called by the ??? effect.
|
||||
*/
|
||||
export class RefreshUserSuggestionsAction implements Action {
|
||||
@@ -135,7 +152,7 @@ export class RefreshUserSuggestionsErrorAction implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to Mark User Suggestions As Visited.
|
||||
* A ngrx action to Mark User Suggestions As Visited.
|
||||
* Called by the ??? effect.
|
||||
*/
|
||||
export class MarkUserSuggestionsAsVisitedAction implements Action {
|
||||
@@ -143,13 +160,26 @@ export class MarkUserSuggestionsAsVisitedAction implements Action {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ngrx action to clear targets state.
|
||||
* A ngrx action to clear targets state.
|
||||
*/
|
||||
export class ClearSuggestionTargetsAction implements Action {
|
||||
type = SuggestionTargetActionTypes.CLEAR_TARGETS;
|
||||
}
|
||||
payload: {
|
||||
source: string;
|
||||
};
|
||||
|
||||
/* tslint:enable:max-classes-per-file */
|
||||
/**
|
||||
* Create a new ClearSuggestionTargetsAction.
|
||||
*
|
||||
* @param source
|
||||
* the source of suggestion targets
|
||||
*/
|
||||
constructor(source: string) {
|
||||
this.payload = {
|
||||
source,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a type alias of all actions in this action group
|
||||
@@ -161,5 +191,5 @@ export type SuggestionTargetsActions
|
||||
| ClearSuggestionTargetsAction
|
||||
| MarkUserSuggestionsAsVisitedAction
|
||||
| RetrieveTargetsBySourceAction
|
||||
| RetrieveAllTargetsErrorAction
|
||||
| RetrieveTargetsBySourceErrorAction
|
||||
| RefreshUserSuggestionsAction;
|
||||
|
@@ -14,16 +14,21 @@ import {
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
AuthActionTypes,
|
||||
RetrieveAuthenticatedEpersonSuccessAction,
|
||||
} from '../../core/auth/auth.actions';
|
||||
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { SuggestionsService } from '../suggestions.service';
|
||||
import {
|
||||
AddTargetAction,
|
||||
AddUserSuggestionsAction,
|
||||
RefreshUserSuggestionsErrorAction,
|
||||
RetrieveAllTargetsErrorAction,
|
||||
RetrieveTargetsBySourceAction,
|
||||
RetrieveTargetsBySourceErrorAction,
|
||||
SuggestionTargetActionTypes,
|
||||
} from './suggestion-targets.actions';
|
||||
|
||||
@@ -45,13 +50,13 @@ export class SuggestionTargetsEffects {
|
||||
action.payload.currentPage,
|
||||
).pipe(
|
||||
map((targets: PaginatedList<SuggestionTarget>) =>
|
||||
new AddTargetAction(targets.page, targets.totalPages, targets.currentPage, targets.totalElements),
|
||||
new AddTargetAction(action.payload.source, targets.page, targets.totalPages, targets.currentPage, targets.totalElements),
|
||||
),
|
||||
catchError((error: unknown) => {
|
||||
if (error instanceof Error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
return of(new RetrieveAllTargetsErrorAction());
|
||||
return of(new RetrieveTargetsBySourceErrorAction(action.payload.source));
|
||||
}),
|
||||
);
|
||||
}),
|
||||
@@ -67,16 +72,27 @@ export class SuggestionTargetsEffects {
|
||||
}),
|
||||
), { dispatch: false });
|
||||
|
||||
/**
|
||||
* Show a notification on error.
|
||||
*/
|
||||
retrieveUserTargets$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(AuthActionTypes.RETRIEVE_AUTHENTICATED_EPERSON_SUCCESS),
|
||||
switchMap((action: RetrieveAuthenticatedEpersonSuccessAction) => {
|
||||
return this.suggestionsService.retrieveCurrentUserSuggestions(action.payload).pipe(
|
||||
map((suggestionTargets: SuggestionTarget[]) => new AddUserSuggestionsAction(suggestionTargets)),
|
||||
);
|
||||
})));
|
||||
|
||||
/**
|
||||
* Fetch the current user suggestion
|
||||
*/
|
||||
refreshUserSuggestionsAction$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(SuggestionTargetActionTypes.REFRESH_USER_SUGGESTIONS),
|
||||
switchMap(() => {
|
||||
return this.store$.select((state: any) => state.core.auth.userId)
|
||||
return this.store$.select((state: any) => state.core.auth.user)
|
||||
.pipe(
|
||||
switchMap((userId: string) => {
|
||||
return this.suggestionsService.retrieveCurrentUserSuggestions(userId)
|
||||
switchMap((user: EPerson) => {
|
||||
return this.suggestionsService.retrieveCurrentUserSuggestions(user.uuid)
|
||||
.pipe(
|
||||
map((suggestionTargets: SuggestionTarget[]) => new AddUserSuggestionsAction(suggestionTargets)),
|
||||
catchError((error: unknown) => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import {
|
||||
SuggestionTargetActionTypes,
|
||||
SuggestionTargetsActions,
|
||||
@@ -7,13 +7,21 @@ import {
|
||||
/**
|
||||
* The interface representing the OpenAIRE suggestion targets state.
|
||||
*/
|
||||
export interface SuggestionTargetState {
|
||||
export interface SuggestionTargetEntry {
|
||||
targets: SuggestionTarget[];
|
||||
processing: boolean;
|
||||
loaded: boolean;
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
totalElements: number;
|
||||
}
|
||||
|
||||
export interface SuggestionSourcesState {
|
||||
[source: string]: SuggestionTargetEntry;
|
||||
}
|
||||
|
||||
export interface SuggestionTargetState {
|
||||
sources: SuggestionSourcesState;
|
||||
currentUserTargets: SuggestionTarget[];
|
||||
currentUserTargetsVisited: boolean;
|
||||
}
|
||||
@@ -21,13 +29,17 @@ export interface SuggestionTargetState {
|
||||
/**
|
||||
* Used for the OpenAIRE Suggestion Target state initialization.
|
||||
*/
|
||||
const SuggestionTargetInitialState: SuggestionTargetState = {
|
||||
const suggestionSourceTargetsInitialState: SuggestionTargetEntry = {
|
||||
targets: [],
|
||||
processing: false,
|
||||
loaded: false,
|
||||
totalPages: 0,
|
||||
currentPage: 0,
|
||||
totalElements: 0,
|
||||
};
|
||||
|
||||
const SuggestionTargetInitialState: SuggestionTargetState = {
|
||||
sources: {},
|
||||
currentUserTargets: null,
|
||||
currentUserTargetsVisited: false,
|
||||
};
|
||||
@@ -45,25 +57,42 @@ const SuggestionTargetInitialState: SuggestionTargetState = {
|
||||
export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, action: SuggestionTargetsActions): SuggestionTargetState {
|
||||
switch (action.type) {
|
||||
case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE: {
|
||||
return Object.assign({}, state, {
|
||||
const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState);
|
||||
const newSourceState = Object.assign({}, sourceState, {
|
||||
targets: [],
|
||||
processing: true,
|
||||
});
|
||||
|
||||
return Object.assign({}, state, {
|
||||
sources:
|
||||
Object.assign({}, state.sources, {
|
||||
[action.payload.source]: newSourceState,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
case SuggestionTargetActionTypes.ADD_TARGETS: {
|
||||
return Object.assign({}, state, {
|
||||
targets: state.targets.concat(action.payload.targets),
|
||||
const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState);
|
||||
const newSourceState = Object.assign({}, sourceState, {
|
||||
targets: sourceState.targets.concat(action.payload.targets),
|
||||
processing: false,
|
||||
loaded: true,
|
||||
totalPages: action.payload.totalPages,
|
||||
currentPage: state.currentPage,
|
||||
currentPage: action.payload.currentPage,
|
||||
totalElements: action.payload.totalElements,
|
||||
});
|
||||
|
||||
return Object.assign({}, state, {
|
||||
sources:
|
||||
Object.assign({}, state.sources, {
|
||||
[action.payload.source]: newSourceState,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
case SuggestionTargetActionTypes.RETRIEVE_TARGETS_BY_SOURCE_ERROR: {
|
||||
return Object.assign({}, state, {
|
||||
const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState);
|
||||
const newSourceState = Object.assign({}, sourceState, {
|
||||
targets: [],
|
||||
processing: false,
|
||||
loaded: true,
|
||||
@@ -71,6 +100,13 @@ export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, a
|
||||
currentPage: 0,
|
||||
totalElements: 0,
|
||||
});
|
||||
|
||||
return Object.assign({}, state, {
|
||||
sources:
|
||||
Object.assign({}, state.sources, {
|
||||
[action.payload.source]: newSourceState,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
case SuggestionTargetActionTypes.ADD_USER_SUGGESTIONS: {
|
||||
@@ -86,7 +122,8 @@ export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, a
|
||||
}
|
||||
|
||||
case SuggestionTargetActionTypes.CLEAR_TARGETS: {
|
||||
return Object.assign({}, state, {
|
||||
const sourceState = state.sources[action.payload.source] || Object.assign({}, suggestionSourceTargetsInitialState);
|
||||
const newSourceState = Object.assign({}, sourceState, {
|
||||
targets: [],
|
||||
processing: false,
|
||||
loaded: false,
|
||||
@@ -94,6 +131,13 @@ export function SuggestionTargetsReducer(state = SuggestionTargetInitialState, a
|
||||
currentPage: 0,
|
||||
totalElements: 0,
|
||||
});
|
||||
|
||||
return Object.assign({}, state, {
|
||||
sources:
|
||||
Object.assign({}, state.sources, {
|
||||
[action.payload.source]: newSourceState,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
default: {
|
||||
|
@@ -6,17 +6,17 @@ import {
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionNotificationsState } from '../../notifications/notifications.reducer';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { SuggestionNotificationsState } from '../notifications.reducer';
|
||||
import {
|
||||
getCurrentUserSuggestionTargetsSelector,
|
||||
getCurrentUserSuggestionTargetsVisitedSelector,
|
||||
getSuggestionTargetCurrentPageSelector,
|
||||
getSuggestionTargetTotalsSelector,
|
||||
isReciterSuggestionTargetProcessingSelector,
|
||||
isSuggestionTargetLoadedSelector,
|
||||
isSuggestionTargetProcessingSelector,
|
||||
suggestionTargetObjectSelector,
|
||||
} from '../../suggestion-notifications/selectors';
|
||||
} from './selectors';
|
||||
import {
|
||||
ClearSuggestionTargetsAction,
|
||||
MarkUserSuggestionsAsVisitedAction,
|
||||
@@ -42,8 +42,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<SuggestionTarget>
|
||||
* The list of Suggestion Targets.
|
||||
*/
|
||||
public getSuggestionTargets(): Observable<SuggestionTarget[]> {
|
||||
return this.store.pipe(select(suggestionTargetObjectSelector()));
|
||||
public getSuggestionTargets(source: string): Observable<SuggestionTarget[]> {
|
||||
return this.store.pipe(select(suggestionTargetObjectSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,9 +52,9 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<boolean>
|
||||
* 'true' if the targets are loading, 'false' otherwise.
|
||||
*/
|
||||
public isSuggestionTargetsLoading(): Observable<boolean> {
|
||||
public isSuggestionTargetsLoading(source: string): Observable<boolean> {
|
||||
return this.store.pipe(
|
||||
select(isSuggestionTargetLoadedSelector),
|
||||
select(isSuggestionTargetLoadedSelector(source)),
|
||||
map((loaded: boolean) => !loaded),
|
||||
);
|
||||
}
|
||||
@@ -65,8 +65,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<boolean>
|
||||
* 'true' if the targets are loaded, 'false' otherwise.
|
||||
*/
|
||||
public isSuggestionTargetsLoaded(): Observable<boolean> {
|
||||
return this.store.pipe(select(isSuggestionTargetLoadedSelector));
|
||||
public isSuggestionTargetsLoaded(source: string): Observable<boolean> {
|
||||
return this.store.pipe(select(isSuggestionTargetLoadedSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,8 +75,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<boolean>
|
||||
* 'true' if there are operations running on the targets (ex.: a REST call), 'false' otherwise.
|
||||
*/
|
||||
public isSuggestionTargetsProcessing(): Observable<boolean> {
|
||||
return this.store.pipe(select(isReciterSuggestionTargetProcessingSelector));
|
||||
public isSuggestionTargetsProcessing(source: string): Observable<boolean> {
|
||||
return this.store.pipe(select(isSuggestionTargetProcessingSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,8 +85,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<number>
|
||||
* The number of the Suggestion Targets pages.
|
||||
*/
|
||||
public getSuggestionTargetsTotalPages(): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetTotalsSelector));
|
||||
public getSuggestionTargetsTotalPages(source: string): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetTotalsSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,8 +95,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<number>
|
||||
* The number of the current Suggestion Targets page.
|
||||
*/
|
||||
public getSuggestionTargetsCurrentPage(): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetCurrentPageSelector));
|
||||
public getSuggestionTargetsCurrentPage(source: string): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetCurrentPageSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,8 +105,8 @@ export class SuggestionTargetsStateService {
|
||||
* @return Observable<number>
|
||||
* The number of the Suggestion Targets.
|
||||
*/
|
||||
public getSuggestionTargetsTotals(): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetTotalsSelector));
|
||||
public getSuggestionTargetsTotals(source: string): Observable<number> {
|
||||
return this.store.pipe(select(getSuggestionTargetTotalsSelector(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +130,7 @@ export class SuggestionTargetsStateService {
|
||||
* The Suggestion Targets object.
|
||||
*/
|
||||
public getCurrentUserSuggestionTargets(): Observable<SuggestionTarget[]> {
|
||||
return this.store.pipe(select(getCurrentUserSuggestionTargetsSelector));
|
||||
return this.store.pipe(select(getCurrentUserSuggestionTargetsSelector()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +140,7 @@ export class SuggestionTargetsStateService {
|
||||
* True if user already visited, false otherwise.
|
||||
*/
|
||||
public hasUserVisitedSuggestions(): Observable<boolean> {
|
||||
return this.store.pipe(select(getCurrentUserSuggestionTargetsVisitedSelector));
|
||||
return this.store.pipe(select(getCurrentUserSuggestionTargetsVisitedSelector()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,9 +152,12 @@ export class SuggestionTargetsStateService {
|
||||
|
||||
/**
|
||||
* Dispatch an action to clear the Reciter Suggestion Targets state.
|
||||
*
|
||||
* @param source
|
||||
* the source of suggestion targets
|
||||
*/
|
||||
public dispatchClearSuggestionTargetsAction(): void {
|
||||
this.store.dispatch(new ClearSuggestionTargetsAction());
|
||||
public dispatchClearSuggestionTargetsAction(source: string): void {
|
||||
this.store.dispatch(new ClearSuggestionTargetsAction(source));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -11,7 +11,7 @@ import { RouterLink } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { SuggestionTargetsStateService } from '../suggestion-targets/suggestion-targets.state.service';
|
||||
import { SuggestionsService } from '../suggestions.service';
|
||||
|
||||
@@ -44,8 +44,8 @@ export class SuggestionsNotificationComponent implements OnInit {
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction();
|
||||
this.suggestionsRD$ = this.suggestionTargetsStateService.getCurrentUserSuggestionTargets();
|
||||
this.suggestionTargetsStateService.dispatchMarkUserSuggestionsAsVisitedAction();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,13 +16,14 @@ import {
|
||||
Observable,
|
||||
of,
|
||||
Subject,
|
||||
Subscription,
|
||||
} from 'rxjs';
|
||||
import {
|
||||
take,
|
||||
takeUntil,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { fromTopEnter } from '../../shared/animations/fromTop';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { SuggestionTargetsStateService } from '../suggestion-targets/suggestion-targets.state.service';
|
||||
@@ -53,7 +54,7 @@ export class SuggestionsPopupComponent implements OnInit, OnDestroy {
|
||||
|
||||
labelPrefix = 'notification.';
|
||||
|
||||
subscription;
|
||||
subscription: Subscription;
|
||||
|
||||
suggestionsRD$: Observable<SuggestionTarget[]>;
|
||||
|
||||
|
@@ -7,22 +7,23 @@ import {
|
||||
SortOptions,
|
||||
} from '../core/cache/models/sort-options.model';
|
||||
import { FindListOptions } from '../core/data/find-list-options.model';
|
||||
import { SuggestionTarget } from '../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionsDataService } from '../core/notifications/suggestions-data.service';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/target/suggestion-target-data.service';
|
||||
import { SuggestionTarget } from '../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { SuggestionDataService } from '../core/notifications/suggestions/suggestion-data.service';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/suggestions/target/suggestion-target-data.service';
|
||||
import { ResearcherProfile } from '../core/profile/model/researcher-profile.model';
|
||||
import { ResearcherProfileDataService } from '../core/profile/researcher-profile-data.service';
|
||||
import { ResourceType } from '../core/shared/resource-type';
|
||||
import { WorkspaceitemDataService } from '../core/submission/workspaceitem-data.service';
|
||||
import { mockSuggestionPublicationOne } from '../shared/mocks/publication-claim.mock';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
|
||||
import { followLink } from '../shared/utils/follow-link-config.model';
|
||||
import { SuggestionsService } from './suggestions.service';
|
||||
|
||||
describe('SuggestionsService test', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: SuggestionsService;
|
||||
let researcherProfileService: ResearcherProfileDataService;
|
||||
let suggestionsDataService: SuggestionsDataService;
|
||||
let suggestionsDataService: SuggestionDataService;
|
||||
let suggestionTargetDataService: SuggestionTargetDataService;
|
||||
let translateService: any = {
|
||||
instant: (str) => str,
|
||||
@@ -59,7 +60,7 @@ describe('SuggestionsService test', () => {
|
||||
});
|
||||
|
||||
suggestionTargetDataService = jasmine.createSpyObj('suggestionTargetsDataService', {
|
||||
getTargets: observableOf(null),
|
||||
getTargetsBySource: observableOf(null),
|
||||
findById: observableOf(null),
|
||||
});
|
||||
|
||||
@@ -89,7 +90,7 @@ describe('SuggestionsService test', () => {
|
||||
sort: sortOptions,
|
||||
};
|
||||
service.getTargets('source', 10, 1);
|
||||
expect(suggestionTargetDataService.getTargets).toHaveBeenCalledWith('source', findListOptions);
|
||||
expect(suggestionTargetDataService.getTargetsBySource).toHaveBeenCalledWith('source', findListOptions);
|
||||
});
|
||||
|
||||
it('should get suggestions', () => {
|
||||
@@ -115,7 +116,7 @@ describe('SuggestionsService test', () => {
|
||||
|
||||
it('should retrieve current user suggestions', () => {
|
||||
service.retrieveCurrentUserSuggestions('1234');
|
||||
expect(researcherProfileService.findById).toHaveBeenCalledWith('1234', true);
|
||||
expect(researcherProfileService.findById).toHaveBeenCalledWith('1234', true, true, followLink('item'));
|
||||
});
|
||||
|
||||
it('should approve and import suggestion', () => {
|
@@ -21,15 +21,14 @@ import {
|
||||
import { FindListOptions } from '../core/data/find-list-options.model';
|
||||
import { PaginatedList } from '../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { Suggestion } from '../core/notifications/models/suggestion.model';
|
||||
import { SuggestionTarget } from '../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionsDataService } from '../core/notifications/suggestions-data.service';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/target/suggestion-target-data.service';
|
||||
import { Suggestion } from '../core/notifications/suggestions/models/suggestion.model';
|
||||
import { SuggestionTarget } from '../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { SuggestionDataService } from '../core/notifications/suggestions/suggestion-data.service';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/suggestions/target/suggestion-target-data.service';
|
||||
import { ResearcherProfile } from '../core/profile/model/researcher-profile.model';
|
||||
import { ResearcherProfileDataService } from '../core/profile/researcher-profile-data.service';
|
||||
import { NoContent } from '../core/shared/NoContent.model';
|
||||
import {
|
||||
getAllSucceededRemoteDataPayload,
|
||||
getFinishedRemoteData,
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
@@ -42,6 +41,7 @@ import {
|
||||
hasValue,
|
||||
isNotEmpty,
|
||||
} from '../shared/empty.util';
|
||||
import { followLink } from '../shared/utils/follow-link-config.model';
|
||||
import { getSuggestionPageRoute } from '../suggestions-page/suggestions-page-routing-paths';
|
||||
|
||||
/**
|
||||
@@ -62,12 +62,12 @@ export class SuggestionsService {
|
||||
* Initialize the service variables.
|
||||
* @param {ResearcherProfileDataService} researcherProfileService
|
||||
* @param {SuggestionTargetDataService} suggestionTargetDataService
|
||||
* @param {SuggestionsDataService} suggestionsDataService
|
||||
* @param {SuggestionDataService} suggestionsDataService
|
||||
* @param translateService
|
||||
*/
|
||||
constructor(
|
||||
private researcherProfileService: ResearcherProfileDataService,
|
||||
private suggestionsDataService: SuggestionsDataService,
|
||||
private suggestionsDataService: SuggestionDataService,
|
||||
private suggestionTargetDataService: SuggestionTargetDataService,
|
||||
private translateService: TranslateService,
|
||||
) {
|
||||
@@ -94,7 +94,7 @@ export class SuggestionsService {
|
||||
sort: sortOptions,
|
||||
};
|
||||
|
||||
return this.suggestionTargetDataService.getTargets(source, findListOptions).pipe(
|
||||
return this.suggestionTargetDataService.getTargetsBySource(source, findListOptions).pipe(
|
||||
getFinishedRemoteData(),
|
||||
take(1),
|
||||
map((rd: RemoteData<PaginatedList<SuggestionTarget>>) => {
|
||||
@@ -121,7 +121,7 @@ export class SuggestionsService {
|
||||
* @return Observable<RemoteData<PaginatedList<Suggestion>>>
|
||||
* The list of Suggestion.
|
||||
*/
|
||||
public getSuggestions(targetId: string, elementsPerPage, currentPage, sortOptions: SortOptions): Observable<PaginatedList<Suggestion>> {
|
||||
public getSuggestions(targetId: string, elementsPerPage, currentPage, sortOptions: SortOptions): Observable<RemoteData<PaginatedList<Suggestion>>> {
|
||||
const [source, target] = targetId.split(':');
|
||||
|
||||
const findListOptions: FindListOptions = {
|
||||
@@ -130,9 +130,7 @@ export class SuggestionsService {
|
||||
sort: sortOptions,
|
||||
};
|
||||
|
||||
return this.suggestionsDataService.getSuggestionsByTargetAndSource(target, source, findListOptions).pipe(
|
||||
getAllSucceededRemoteDataPayload(),
|
||||
);
|
||||
return this.suggestionsDataService.getSuggestionsByTargetAndSource(target, source, findListOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +167,7 @@ export class SuggestionsService {
|
||||
if (hasNoValue(userUuid)) {
|
||||
return of([]);
|
||||
}
|
||||
return this.researcherProfileService.findById(userUuid, true).pipe(
|
||||
return this.researcherProfileService.findById(userUuid, true, true, followLink('item')).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
mergeMap((profile: RemoteData<ResearcherProfile> ) => {
|
||||
if (isNotEmpty(profile) && profile.hasSucceeded && isNotEmpty(profile.payload)) {
|
||||
|
@@ -1 +1 @@
|
||||
<ds-publication-claim [source]="'oaire'"></ds-publication-claim>
|
||||
<ds-publication-claim [source]="'openaire'"></ds-publication-claim>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { SuggestionTarget } from '../../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTarget } from '../../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { ResourceType } from '../../core/shared/resource-type';
|
||||
|
||||
// REST Mock ---------------------------------------------------------------------
|
||||
|
@@ -2,8 +2,8 @@
|
||||
// REST Mock ---------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
import { Suggestion } from '../../core/notifications/models/suggestion.model';
|
||||
import { SUGGESTION } from '../../core/notifications/models/suggestion-objects.resource-type';
|
||||
import { Suggestion } from '../../core/notifications/suggestions/models/suggestion.model';
|
||||
import { SUGGESTION } from '../../core/notifications/suggestions/models/suggestion-objects.resource-type';
|
||||
|
||||
export const mockSuggestionPublicationOne: Suggestion = {
|
||||
id: '24694773',
|
||||
|
@@ -2,7 +2,9 @@ import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
|
||||
import { SearchResult } from '../search/models/search-result.model';
|
||||
import { createPaginatedList } from '../testing/utils.test';
|
||||
|
||||
// REST Mock ---------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------------
|
||||
@@ -1345,7 +1347,7 @@ export function getMockSuggestionNotificationsStateService(): any {
|
||||
export function getMockSuggestionsService(): any {
|
||||
return jasmine.createSpyObj('SuggestionsService', {
|
||||
getTargets: jasmine.createSpy('getTargets'),
|
||||
getSuggestions: observableOf([]),
|
||||
getSuggestions: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
||||
clearSuggestionRequests: jasmine.createSpy('clearSuggestionRequests'),
|
||||
deleteReviewedSuggestion: jasmine.createSpy('deleteReviewedSuggestion'),
|
||||
retrieveCurrentUserSuggestions: jasmine.createSpy('retrieveCurrentUserSuggestions'),
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<div role="button"
|
||||
<div role="button" *ngIf="boxConfig"
|
||||
class="w-100 h-100 pt-4 pb-3 px-2 box-container"
|
||||
[ngStyle]="{'background-color': boxConfig.color}"
|
||||
[dsHoverClass]="'shadow-lg'"
|
||||
|
@@ -1,4 +1,7 @@
|
||||
import { NgStyle } from '@angular/common';
|
||||
import {
|
||||
NgIf,
|
||||
NgStyle,
|
||||
} from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
@@ -23,6 +26,7 @@ import { listableObjectComponent } from '../object-collection/shared/listable-ob
|
||||
NgStyle,
|
||||
HoverClassDirective,
|
||||
TranslateModule,
|
||||
NgIf,
|
||||
],
|
||||
})
|
||||
/**
|
||||
|
@@ -1,105 +0,0 @@
|
||||
import {
|
||||
createFeatureSelector,
|
||||
createSelector,
|
||||
MemoizedSelector,
|
||||
} from '@ngrx/store';
|
||||
|
||||
import { SuggestionTarget } from '../core/notifications/models/suggestion-target.model';
|
||||
import {
|
||||
suggestionNotificationsSelector,
|
||||
SuggestionNotificationsState,
|
||||
} from '../notifications/notifications.reducer';
|
||||
import { SuggestionTargetState } from '../notifications/suggestion-targets/suggestion-targets.reducer';
|
||||
import { subStateSelector } from '../submission/selectors';
|
||||
|
||||
/**
|
||||
* Returns the Reciter Suggestion Target state.
|
||||
* @function _getSuggestionTargetState
|
||||
* @param {AppState} state Top level state.
|
||||
* @return {SuggestionNotificationsState}
|
||||
*/
|
||||
const _getSuggestionTargetState = createFeatureSelector<SuggestionNotificationsState>('suggestionNotifications');
|
||||
|
||||
// Reciter Suggestion Targets
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the Suggestion Targets State.
|
||||
* @function suggestionTargetStateSelector
|
||||
* @return {SuggestionNotificationsState}
|
||||
*/
|
||||
export function suggestionTargetStateSelector(): MemoizedSelector<SuggestionNotificationsState, SuggestionTargetState> {
|
||||
return subStateSelector<SuggestionNotificationsState, SuggestionTargetState>(suggestionNotificationsSelector, 'suggestionTarget');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Suggestion Targets list.
|
||||
* @function suggestionTargetObjectSelector
|
||||
* @return {SuggestionTarget[]}
|
||||
*/
|
||||
export function suggestionTargetObjectSelector(): MemoizedSelector<SuggestionNotificationsState, SuggestionTarget[]> {
|
||||
return subStateSelector<SuggestionNotificationsState, SuggestionTarget[]>(suggestionTargetStateSelector(), 'targets');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Suggestion Targets are loaded.
|
||||
* @function isSuggestionTargetLoadedSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isSuggestionTargetLoadedSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.loaded,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the deduplication sets are processing.
|
||||
* @function isDeduplicationSetsProcessingSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isReciterSuggestionTargetProcessingSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.processing,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the total available pages of Reciter Suggestion Targets.
|
||||
* @function getSuggestionTargetTotalPagesSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetTotalPagesSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.totalPages,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the current page of Suggestion Targets.
|
||||
* @function getSuggestionTargetCurrentPageSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetCurrentPageSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.currentPage,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the total number of Suggestion Targets.
|
||||
* @function getSuggestionTargetTotalsSelector
|
||||
* @return {number}
|
||||
*/
|
||||
export const getSuggestionTargetTotalsSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.totalElements,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns Suggestion Targets for the current user.
|
||||
* @function getCurrentUserSuggestionTargetSelector
|
||||
* @return {SuggestionTarget[]}
|
||||
*/
|
||||
export const getCurrentUserSuggestionTargetsSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.currentUserTargets,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns whether or not the user has consulted their suggestions
|
||||
* @function getCurrentUserSuggestionTargetSelector
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const getCurrentUserSuggestionTargetsVisitedSelector = createSelector(_getSuggestionTargetState,
|
||||
(state: SuggestionNotificationsState) => state.suggestionTarget.currentUserTargetsVisited,
|
||||
);
|
@@ -2,7 +2,8 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ng-container *ngVar="(suggestionsRD$ | async) as suggestionsRD">
|
||||
<div *ngIf="suggestionsRD?.pageInfo?.totalElements > 0">
|
||||
<ds-loading *ngIf="(processing$ | async)"></ds-loading>
|
||||
<div *ngIf="(processing$ | async) !== true && suggestionsRD?.pageInfo?.totalElements > 0">
|
||||
|
||||
<h1>
|
||||
{{'suggestion.suggestionFor' | translate}}
|
||||
@@ -21,7 +22,6 @@
|
||||
(ignoreSuggestionClicked)="ignoreSuggestionAllSelected()"></ds-suggestion-actions>
|
||||
<i class='fas fa-circle-notch fa-spin' *ngIf="isBulkOperationPending"></i>
|
||||
</div>
|
||||
<ds-loading *ngIf="(processing$ | async)"></ds-loading>
|
||||
<ds-pagination *ngIf="(processing$ | async) !== true"
|
||||
[paginationOptions]="paginationOptions"
|
||||
[sortOptions]="paginationSortConfig"
|
||||
@@ -41,7 +41,9 @@
|
||||
</ul>
|
||||
</ds-pagination>
|
||||
</div>
|
||||
<div *ngIf="suggestionsRD?.pageInfo?.totalElements === 0">{{ 'suggestion.count.missing' | translate }}</div>
|
||||
<ds-alert *ngIf="(processing$ | async) !== true && (suggestionsRD?.pageInfo?.totalElements === 0 || !suggestionsRD)" [type]="'alert-info'">
|
||||
{{'suggestion.count.missing' | translate}}
|
||||
</ds-alert>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import {
|
||||
async,
|
||||
ComponentFixture,
|
||||
fakeAsync,
|
||||
TestBed,
|
||||
tick,
|
||||
waitForAsync,
|
||||
} from '@angular/core/testing';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import {
|
||||
@@ -70,7 +69,7 @@ describe('SuggestionPageComponent', () => {
|
||||
});
|
||||
const paginationService = new PaginationServiceStub();
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -106,7 +105,7 @@ describe('SuggestionPageComponent', () => {
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.flush();
|
||||
@@ -118,70 +117,72 @@ describe('SuggestionPageComponent', () => {
|
||||
});
|
||||
|
||||
it('should update page on pagination change', () => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
component.targetId$ = observableOf('testid');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.schedule(() => component.onPaginationChange());
|
||||
scheduler.flush();
|
||||
component.onPaginationChange();
|
||||
|
||||
expect(component.updatePage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update suggestion on page update', (done) => {
|
||||
it('should update suggestion on page update', () => {
|
||||
spyOn(component.processing$, 'next');
|
||||
spyOn(component.suggestionsRD$, 'next');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
component.targetId$ = observableOf('testid');
|
||||
scheduler.schedule(() => component.updatePage().subscribe());
|
||||
scheduler.flush();
|
||||
paginationService.getFindListOptions().subscribe(() => {
|
||||
expect(component.processing$.next).toHaveBeenCalled();
|
||||
expect(mockSuggestionsService.getSuggestions).toHaveBeenCalled();
|
||||
expect(component.suggestionsRD$.next).toHaveBeenCalled();
|
||||
expect(mockSuggestionsService.clearSuggestionRequests).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
component.updatePage();
|
||||
|
||||
expect(component.processing$.next).toHaveBeenCalledTimes(2);
|
||||
expect(mockSuggestionsService.getSuggestions).toHaveBeenCalled();
|
||||
expect(component.suggestionsRD$.next).toHaveBeenCalled();
|
||||
expect(mockSuggestionsService.clearSuggestionRequests).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should flag suggestion for deletion', fakeAsync(() => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
component.targetId$ = observableOf('testid');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.schedule(() => component.ignoreSuggestion('1'));
|
||||
scheduler.flush();
|
||||
component.ignoreSuggestion('1');
|
||||
|
||||
expect(mockSuggestionsService.ignoreSuggestion).toHaveBeenCalledWith('1');
|
||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||
tick(201);
|
||||
expect(component.updatePage).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should flag all suggestion for deletion', () => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
component.targetId$ = observableOf('testid');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.schedule(() => component.ignoreSuggestionAllSelected());
|
||||
scheduler.flush();
|
||||
component.ignoreSuggestionAllSelected();
|
||||
|
||||
expect(mockSuggestionsService.ignoreSuggestionMultiple).toHaveBeenCalled();
|
||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||
expect(component.updatePage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should approve and import', () => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
component.targetId$ = observableOf('testid');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.schedule(() => component.approveAndImport({ collectionId: '1234' } as unknown as SuggestionApproveAndImport));
|
||||
scheduler.flush();
|
||||
component.approveAndImport({ collectionId: '1234' } as unknown as SuggestionApproveAndImport);
|
||||
|
||||
expect(mockSuggestionsService.approveAndImport).toHaveBeenCalled();
|
||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||
expect(component.updatePage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should approve and import multiple suggestions', () => {
|
||||
spyOn(component, 'updatePage').and.stub();
|
||||
spyOn(component, 'updatePage').and.callThrough();
|
||||
component.targetId$ = observableOf('testid');
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
scheduler.schedule(() => component.approveAndImportAllSelected({ collectionId: '1234' } as unknown as SuggestionApproveAndImport));
|
||||
scheduler.flush();
|
||||
component.approveAndImportAllSelected({ collectionId: '1234' } as unknown as SuggestionApproveAndImport);
|
||||
|
||||
expect(mockSuggestionsService.approveAndImportMultiple).toHaveBeenCalled();
|
||||
expect(mockSuggestionsTargetStateService.dispatchRefreshUserSuggestionsAction).toHaveBeenCalled();
|
||||
expect(component.updatePage).toHaveBeenCalled();
|
||||
|
@@ -26,7 +26,7 @@ import {
|
||||
distinctUntilChanged,
|
||||
map,
|
||||
switchMap,
|
||||
take,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { AuthService } from '../core/auth/auth.service';
|
||||
@@ -37,11 +37,14 @@ import {
|
||||
import { FindListOptions } from '../core/data/find-list-options.model';
|
||||
import { PaginatedList } from '../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { Suggestion } from '../core/notifications/models/suggestion.model';
|
||||
import { SuggestionTarget } from '../core/notifications/models/suggestion-target.model';
|
||||
import { Suggestion } from '../core/notifications/suggestions/models/suggestion.model';
|
||||
import { SuggestionTarget } from '../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { PaginationService } from '../core/pagination/pagination.service';
|
||||
import { redirectOn4xx } from '../core/shared/authorized.operators';
|
||||
import { getFirstSucceededRemoteDataPayload } from '../core/shared/operators';
|
||||
import {
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
} from '../core/shared/operators';
|
||||
import { WorkspaceItem } from '../core/submission/models/workspaceitem.model';
|
||||
import { WorkspaceitemDataService } from '../core/submission/workspaceitem-data.service';
|
||||
import { SuggestionActionsComponent } from '../notifications/suggestion-actions/suggestion-actions.component';
|
||||
@@ -52,6 +55,7 @@ import {
|
||||
SuggestionBulkResult,
|
||||
SuggestionsService,
|
||||
} from '../notifications/suggestions.service';
|
||||
import { AlertComponent } from '../shared/alert/alert.component';
|
||||
import { ThemedLoadingComponent } from '../shared/loading/themed-loading.component';
|
||||
import { NotificationsService } from '../shared/notifications/notifications.service';
|
||||
import { PaginationComponent } from '../shared/pagination/pagination.component';
|
||||
@@ -74,6 +78,7 @@ import { getWorkspaceItemEditRoute } from '../workflowitems-edit-page/workflowit
|
||||
PaginationComponent,
|
||||
SuggestionListElementComponent,
|
||||
NgForOf,
|
||||
AlertComponent,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
@@ -149,14 +154,15 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
);
|
||||
this.targetRD$.pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
).subscribe((suggestionTarget: SuggestionTarget) => {
|
||||
this.suggestionTarget = suggestionTarget;
|
||||
this.suggestionId = suggestionTarget.id;
|
||||
this.researcherName = suggestionTarget.display;
|
||||
this.suggestionSource = suggestionTarget.source;
|
||||
this.researcherUuid = this.suggestionService.getTargetUuid(suggestionTarget);
|
||||
this.updatePage();
|
||||
});
|
||||
tap((suggestionTarget: SuggestionTarget) => {
|
||||
this.suggestionTarget = suggestionTarget;
|
||||
this.suggestionId = suggestionTarget.id;
|
||||
this.researcherName = suggestionTarget.display;
|
||||
this.suggestionSource = suggestionTarget.source;
|
||||
this.researcherUuid = this.suggestionService.getTargetUuid(suggestionTarget);
|
||||
}),
|
||||
switchMap(() => this.updatePage()),
|
||||
).subscribe();
|
||||
|
||||
this.suggestionTargetsStateService.dispatchMarkUserSuggestionsAsVisitedAction();
|
||||
}
|
||||
@@ -165,13 +171,13 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
* Called when one of the pagination settings is changed
|
||||
*/
|
||||
onPaginationChange() {
|
||||
this.updatePage();
|
||||
this.updatePage().subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the list of suggestions
|
||||
*/
|
||||
updatePage() {
|
||||
updatePage(): Observable<RemoteData<PaginatedList<Suggestion>>> {
|
||||
this.processing$.next(true);
|
||||
const pageConfig$: Observable<FindListOptions> = this.paginationService.getFindListOptions(
|
||||
this.paginationOptions.id,
|
||||
@@ -179,7 +185,8 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
).pipe(
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
combineLatest([this.targetId$, pageConfig$]).pipe(
|
||||
|
||||
return combineLatest([this.targetId$, pageConfig$]).pipe(
|
||||
switchMap(([targetId, config]: [string, FindListOptions]) => {
|
||||
return this.suggestionService.getSuggestions(
|
||||
targetId,
|
||||
@@ -188,12 +195,18 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
config.sort,
|
||||
);
|
||||
}),
|
||||
take(1),
|
||||
).subscribe((results: PaginatedList<Suggestion>) => {
|
||||
this.processing$.next(false);
|
||||
this.suggestionsRD$.next(results);
|
||||
this.suggestionService.clearSuggestionRequests();
|
||||
});
|
||||
getFirstCompletedRemoteData(),
|
||||
tap((resultsRD: RemoteData<PaginatedList<Suggestion>>) => {
|
||||
this.processing$.next(false);
|
||||
if (resultsRD.hasSucceeded) {
|
||||
this.suggestionsRD$.next(resultsRD.payload);
|
||||
} else {
|
||||
this.suggestionsRD$.next(null);
|
||||
}
|
||||
|
||||
this.suggestionService.clearSuggestionRequests();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,11 +214,10 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
* @suggestionId
|
||||
*/
|
||||
ignoreSuggestion(suggestionId) {
|
||||
this.suggestionService.ignoreSuggestion(suggestionId).subscribe(() => {
|
||||
this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction();
|
||||
//We add a little delay in the page refresh so that we ensure the deletion has been propagated
|
||||
setTimeout(() => this.updatePage(), 200);
|
||||
});
|
||||
this.suggestionService.ignoreSuggestion(suggestionId).pipe(
|
||||
tap(() => this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction()),
|
||||
switchMap(() => this.updatePage()),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,11 +225,9 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
*/
|
||||
ignoreSuggestionAllSelected() {
|
||||
this.isBulkOperationPending = true;
|
||||
this.suggestionService
|
||||
.ignoreSuggestionMultiple(Object.values(this.selectedSuggestions))
|
||||
.subscribe((results: SuggestionBulkResult) => {
|
||||
this.suggestionService.ignoreSuggestionMultiple(Object.values(this.selectedSuggestions)).pipe(
|
||||
tap((results: SuggestionBulkResult) => {
|
||||
this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction();
|
||||
this.updatePage();
|
||||
this.isBulkOperationPending = false;
|
||||
this.selectedSuggestions = {};
|
||||
if (results.success > 0) {
|
||||
@@ -230,7 +240,9 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
this.translateService.get('suggestion.ignoreSuggestion.bulk.error',
|
||||
{ count: results.fails }));
|
||||
}
|
||||
});
|
||||
}),
|
||||
switchMap(() => this.updatePage()),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,13 +250,14 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
* @param event contains the suggestion and the target collection
|
||||
*/
|
||||
approveAndImport(event: SuggestionApproveAndImport) {
|
||||
this.suggestionService.approveAndImport(this.workspaceItemService, event.suggestion, event.collectionId)
|
||||
.subscribe((workspaceitem: WorkspaceItem) => {
|
||||
this.suggestionService.approveAndImport(this.workspaceItemService, event.suggestion, event.collectionId).pipe(
|
||||
tap((workspaceitem: WorkspaceItem) => {
|
||||
const content = this.translateService.instant('suggestion.approveAndImport.success', { url: getWorkspaceItemEditRoute(workspaceitem.id) });
|
||||
this.notificationService.success('', content, { timeOut:0 }, true);
|
||||
this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction();
|
||||
this.updatePage();
|
||||
});
|
||||
}),
|
||||
switchMap(() => this.updatePage()),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,11 +266,9 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
*/
|
||||
approveAndImportAllSelected(event: SuggestionApproveAndImport) {
|
||||
this.isBulkOperationPending = true;
|
||||
this.suggestionService
|
||||
.approveAndImportMultiple(this.workspaceItemService, Object.values(this.selectedSuggestions), event.collectionId)
|
||||
.subscribe((results: SuggestionBulkResult) => {
|
||||
this.suggestionService.approveAndImportMultiple(this.workspaceItemService, Object.values(this.selectedSuggestions), event.collectionId).pipe(
|
||||
tap((results: SuggestionBulkResult) => {
|
||||
this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction();
|
||||
this.updatePage();
|
||||
this.isBulkOperationPending = false;
|
||||
this.selectedSuggestions = {};
|
||||
if (results.success > 0) {
|
||||
@@ -270,7 +281,9 @@ export class SuggestionsPageComponent implements OnInit {
|
||||
this.translateService.get('suggestion.approveAndImport.bulk.error',
|
||||
{ count: results.fails }));
|
||||
}
|
||||
});
|
||||
}),
|
||||
switchMap(() => this.updatePage()),
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -5,12 +5,11 @@ import {
|
||||
RouterStateSnapshot,
|
||||
} from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { find } from 'rxjs/operators';
|
||||
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { SuggestionTarget } from '../core/notifications/models/suggestion-target.model';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/target/suggestion-target-data.service';
|
||||
import { hasValue } from '../shared/empty.util';
|
||||
import { SuggestionTarget } from '../core/notifications/suggestions/models/suggestion-target.model';
|
||||
import { SuggestionTargetDataService } from '../core/notifications/suggestions/target/suggestion-target-data.service';
|
||||
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
||||
|
||||
/**
|
||||
* Method for resolving a suggestion target based on the parameters in the current route
|
||||
@@ -26,6 +25,6 @@ export const suggestionsPageResolver: ResolveFn<RemoteData<SuggestionTarget>> =
|
||||
suggestionsDataService: SuggestionTargetDataService = inject(SuggestionTargetDataService),
|
||||
): Observable<RemoteData<SuggestionTarget>> => {
|
||||
return suggestionsDataService.getTargetById(route.params.targetId).pipe(
|
||||
find((RD) => hasValue(RD.hasFailed) || RD.hasSucceeded),
|
||||
getFirstCompletedRemoteData(),
|
||||
);
|
||||
};
|
||||
|
@@ -6218,7 +6218,7 @@
|
||||
"ldn-new-service.form.error.patterns": "At least a pattern is required",
|
||||
"ldn-new-service.form.error.score": "Please enter a valid score (between 0 and 1). Use the “.” as decimal separator",
|
||||
|
||||
"ldn-new-service.form.label.inboundPattern": "Inbound Pattern",
|
||||
"ldn-new-service.form.label.inboundPattern": "Supported Pattern",
|
||||
"ldn-new-service.form.label.addPattern": "+ Add more",
|
||||
"ldn-new-service.form.label.removeItemFilter": "Remove",
|
||||
"ldn-register-new-service.breadcrumbs": "New Service",
|
||||
@@ -6273,8 +6273,12 @@
|
||||
|
||||
"item.page.review": "Review",
|
||||
|
||||
"item.page.dataset": "Dataset",
|
||||
"item.page.referenced": "Referenced By",
|
||||
|
||||
"item.page.supplemented": "Supplemented By",
|
||||
|
||||
"menu.section.icon.ldn_services": "LDN Services overview",
|
||||
|
||||
"menu.section.services": "LDN Services",
|
||||
|
||||
"menu.section.services_new": "LDN Service",
|
||||
@@ -6350,13 +6354,13 @@
|
||||
|
||||
"request-status-alert-box.requested": "The requested {{ offerType }} for <a href='{{serviceUrl}}' target='_blank'> {{ serviceName }} </a> is pending.",
|
||||
|
||||
"ldn-service-button-mark-inbound-deletion": "Mark inbound pattern for deletion",
|
||||
"ldn-service-button-mark-inbound-deletion": "Mark supported pattern for deletion",
|
||||
|
||||
"ldn-service-button-unmark-inbound-deletion": "Unmark inbound pattern for deletion",
|
||||
"ldn-service-button-unmark-inbound-deletion": "Unmark supported pattern for deletion",
|
||||
|
||||
"ldn-service-input-inbound-item-filter-dropdown": "Select Item filter for inbound pattern",
|
||||
"ldn-service-input-inbound-item-filter-dropdown": "Select Item filter for the pattern",
|
||||
|
||||
"ldn-service-input-inbound-pattern-dropdown": "Select inbound pattern for service",
|
||||
"ldn-service-input-inbound-pattern-dropdown": "Select a pattern for service",
|
||||
|
||||
"ldn-service-overview-select-delete": "Select service for deletion",
|
||||
|
||||
|
Reference in New Issue
Block a user