mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-17 15:03:07 +00:00
Merge branch 'w2p-65195_dynamic-component-refactoring' into clean-relationships-in-submission
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2>{{'collection.edit.item-mapper.head' | translate}}</h2>
|
||||
<p [innerHTML]="'collection.edit.item-mapper.collection' | translate:{ name: (collectionRD$ | async)?.payload?.name }" id="collection-name"></p>
|
||||
<p>{{'collection.edit.item-mapper.description' | translate}}</p>
|
||||
|
||||
<ngb-tabset (tabChange)="tabChange($event)" [destroyOnHide]="true" #tabs="ngbTabset">
|
||||
<ngb-tab title="{{'collection.edit.item-mapper.tabs.browse' | translate}}" id="browseTab">
|
||||
<ng-template ngbTabContent>
|
||||
<div class="mt-2">
|
||||
<ds-item-select class="mt-2"
|
||||
[key]="'browse'"
|
||||
[dsoRD$]="collectionItemsRD$"
|
||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||
[confirmButton]="'collection.edit.item-mapper.remove'"
|
||||
[cancelButton]="'collection.edit.item-mapper.cancel'"
|
||||
[dangerConfirm]="true"
|
||||
[hideCollection]="true"
|
||||
(confirm)="mapItems($event, true)"
|
||||
(cancel)="onCancel()"></ds-item-select>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngb-tab>
|
||||
<ngb-tab title="{{'collection.edit.item-mapper.tabs.map' | translate}}" id="mapTab">
|
||||
<ng-template ngbTabContent>
|
||||
<div class="row mt-2">
|
||||
<div class="col-12 col-lg-6">
|
||||
<ds-search-form id="search-form"
|
||||
[query]="(searchOptions$ | async)?.query"
|
||||
[scope]="(searchOptions$ | async)?.scope"
|
||||
[currentUrl]="'./'"
|
||||
[inPlaceSearch]="true"
|
||||
(submitSearch)="performedSearch = true">
|
||||
</ds-search-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="performedSearch">
|
||||
<ds-item-select class="mt-2"
|
||||
[key]="'map'"
|
||||
[dsoRD$]="mappedItemsRD$"
|
||||
[paginationOptions]="(searchOptions$ | async)?.pagination"
|
||||
[confirmButton]="'collection.edit.item-mapper.confirm'"
|
||||
[cancelButton]="'collection.edit.item-mapper.cancel'"
|
||||
(confirm)="mapItems($event)"
|
||||
(cancel)="onCancel()"></ds-item-select>
|
||||
</div>
|
||||
<div *ngIf="!performedSearch" class="alert alert-info w-100" role="alert">
|
||||
{{'collection.edit.item-mapper.no-search' | translate}}
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngb-tab>
|
||||
</ngb-tabset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1 @@
|
||||
@import '../../../styles/variables.scss';
|
@@ -0,0 +1,214 @@
|
||||
import { CollectionItemMapperComponent } from './collection-item-mapper.component';
|
||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { SearchFormComponent } from '../../shared/search-form/search-form.component';
|
||||
import { SearchPageModule } from '../../+search-page/search-page.module';
|
||||
import { ObjectCollectionComponent } from '../../shared/object-collection/object-collection.component';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
|
||||
import { RouterStub } from '../../shared/testing/router-stub';
|
||||
import { SearchConfigurationService } from '../../+search-page/search-service/search-configuration.service';
|
||||
import { SearchService } from '../../+search-page/search-service/search.service';
|
||||
import { SearchServiceStub } from '../../shared/testing/search-service-stub';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub';
|
||||
import { ItemDataService } from '../../core/data/item-data.service';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedSearchOptions } from '../../+search-page/paginated-search-options.model';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||
import { EventEmitter, NgModule } from '@angular/core';
|
||||
import { HostWindowService } from '../../shared/host-window.service';
|
||||
import { HostWindowServiceStub } from '../../shared/testing/host-window-service-stub';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../core/shared/page-info.model';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { PaginationComponent } from '../../shared/pagination/pagination.component';
|
||||
import { EnumKeysPipe } from '../../shared/utils/enum-keys-pipe';
|
||||
import { ItemSelectComponent } from '../../shared/object-select/item-select/item-select.component';
|
||||
import { ObjectSelectService } from '../../shared/object-select/object-select.service';
|
||||
import { ObjectSelectServiceStub } from '../../shared/testing/object-select-service-stub';
|
||||
import { VarDirective } from '../../shared/utils/var.directive';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { of as observableOf, of } from 'rxjs/internal/observable/of';
|
||||
import { RestResponse } from '../../core/cache/response.models';
|
||||
import { SearchFixedFilterService } from '../../+search-page/search-filters/search-filter/search-fixed-filter.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { ErrorComponent } from '../../shared/error/error.component';
|
||||
import { LoadingComponent } from '../../shared/loading/loading.component';
|
||||
|
||||
describe('CollectionItemMapperComponent', () => {
|
||||
let comp: CollectionItemMapperComponent;
|
||||
let fixture: ComponentFixture<CollectionItemMapperComponent>;
|
||||
|
||||
let route: ActivatedRoute;
|
||||
let router: Router;
|
||||
let searchConfigService: SearchConfigurationService;
|
||||
let searchService: SearchService;
|
||||
let notificationsService: NotificationsService;
|
||||
let itemDataService: ItemDataService;
|
||||
|
||||
const mockCollection: Collection = Object.assign(new Collection(), {
|
||||
id: 'ce41d451-97ed-4a9c-94a1-7de34f16a9f4',
|
||||
name: 'test-collection'
|
||||
});
|
||||
const mockCollectionRD: RemoteData<Collection> = new RemoteData<Collection>(false, false, true, null, mockCollection);
|
||||
const mockSearchOptions = of(new PaginatedSearchOptions({
|
||||
pagination: Object.assign(new PaginationComponentOptions(), {
|
||||
id: 'search-page-configuration',
|
||||
pageSize: 10,
|
||||
currentPage: 1
|
||||
}),
|
||||
sort: new SortOptions('dc.title', SortDirection.ASC),
|
||||
scope: mockCollection.id
|
||||
}));
|
||||
const url = 'http://test.url';
|
||||
const urlWithParam = url + '?param=value';
|
||||
const routerStub = Object.assign(new RouterStub(), {
|
||||
url: urlWithParam,
|
||||
navigateByUrl: {},
|
||||
navigate: {}
|
||||
});
|
||||
const searchConfigServiceStub = {
|
||||
paginatedSearchOptions: mockSearchOptions
|
||||
};
|
||||
const itemDataServiceStub = {
|
||||
mapToCollection: () => of(new RestResponse(true, 200, 'OK'))
|
||||
};
|
||||
const activatedRouteStub = new ActivatedRouteStub({}, { collection: mockCollectionRD });
|
||||
const translateServiceStub = {
|
||||
get: () => of('test-message of collection ' + mockCollection.name),
|
||||
onLangChange: new EventEmitter(),
|
||||
onTranslationChange: new EventEmitter(),
|
||||
onDefaultLangChange: new EventEmitter()
|
||||
};
|
||||
const emptyList = new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []));
|
||||
const searchServiceStub = Object.assign(new SearchServiceStub(), {
|
||||
search: () => of(emptyList),
|
||||
/* tslint:disable:no-empty */
|
||||
clearDiscoveryRequests: () => {}
|
||||
/* tslint:enable:no-empty */
|
||||
});
|
||||
const collectionDataServiceStub = {
|
||||
getMappedItems: () => of(emptyList),
|
||||
/* tslint:disable:no-empty */
|
||||
clearMappedItemsRequests: () => {}
|
||||
/* tslint:enable:no-empty */
|
||||
};
|
||||
const routeServiceStub = {
|
||||
getRouteParameterValue: () => {
|
||||
return observableOf('');
|
||||
},
|
||||
getQueryParameterValue: () => {
|
||||
return observableOf('')
|
||||
},
|
||||
getQueryParamsWithPrefix: () => {
|
||||
return observableOf('')
|
||||
}
|
||||
};
|
||||
const fixedFilterServiceStub = {
|
||||
getQueryByFilterName: () => {
|
||||
return observableOf('')
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
|
||||
declarations: [CollectionItemMapperComponent, ItemSelectComponent, SearchFormComponent, PaginationComponent, EnumKeysPipe, VarDirective, ErrorComponent, LoadingComponent],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
||||
{ provide: Router, useValue: routerStub },
|
||||
{ provide: SearchConfigurationService, useValue: searchConfigServiceStub },
|
||||
{ provide: SearchService, useValue: searchServiceStub },
|
||||
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
|
||||
{ provide: ItemDataService, useValue: itemDataServiceStub },
|
||||
{ provide: CollectionDataService, useValue: collectionDataServiceStub },
|
||||
{ provide: TranslateService, useValue: translateServiceStub },
|
||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
|
||||
{ provide: ObjectSelectService, useValue: new ObjectSelectServiceStub() },
|
||||
{ provide: RouteService, useValue: routeServiceStub },
|
||||
{ provide: SearchFixedFilterService, useValue: fixedFilterServiceStub }
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CollectionItemMapperComponent);
|
||||
comp = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
route = (comp as any).route;
|
||||
router = (comp as any).router;
|
||||
searchConfigService = (comp as any).searchConfigService;
|
||||
searchService = (comp as any).searchService;
|
||||
notificationsService = (comp as any).notificationsService;
|
||||
itemDataService = (comp as any).itemDataService;
|
||||
});
|
||||
|
||||
it('should display the correct collection name', () => {
|
||||
const name: HTMLElement = fixture.debugElement.query(By.css('#collection-name')).nativeElement;
|
||||
expect(name.innerHTML).toContain(mockCollection.name);
|
||||
});
|
||||
|
||||
describe('mapItems', () => {
|
||||
const ids = ['id1', 'id2', 'id3', 'id4'];
|
||||
|
||||
it('should display a success message if at least one mapping was successful', () => {
|
||||
comp.mapItems(ids);
|
||||
expect(notificationsService.success).toHaveBeenCalled();
|
||||
expect(notificationsService.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display an error message if at least one mapping was unsuccessful', () => {
|
||||
spyOn(itemDataService, 'mapToCollection').and.returnValue(of(new RestResponse(false, 404, 'Not Found')));
|
||||
comp.mapItems(ids);
|
||||
expect(notificationsService.success).not.toHaveBeenCalled();
|
||||
expect(notificationsService.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('tabChange', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(routerStub, 'navigateByUrl');
|
||||
comp.tabChange({});
|
||||
});
|
||||
|
||||
it('should navigate to the same page to remove parameters', () => {
|
||||
expect(router.navigateByUrl).toHaveBeenCalledWith(url);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildQuery', () => {
|
||||
const query = 'query';
|
||||
const expected = `-location.coll:\"${mockCollection.id}\" AND ${query}`;
|
||||
|
||||
let result;
|
||||
|
||||
beforeEach(() => {
|
||||
result = comp.buildQuery(mockCollection.id, query);
|
||||
});
|
||||
|
||||
it('should build a solr query to exclude the provided collection', () => {
|
||||
expect(result).toEqual(expected);
|
||||
})
|
||||
});
|
||||
|
||||
describe('onCancel', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(routerStub, 'navigate');
|
||||
comp.onCancel();
|
||||
});
|
||||
|
||||
it('should navigate to the collection page', () => {
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/collections/', mockCollection.id]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -0,0 +1,256 @@
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
|
||||
import { ChangeDetectionStrategy, Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { fadeIn, fadeInOut } from '../../shared/animations/fade';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { SearchConfigurationService } from '../../+search-page/search-service/search-configuration.service';
|
||||
import { PaginatedSearchOptions } from '../../+search-page/paginated-search-options.model';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { map, startWith, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData, toDSpaceObjectListRD } from '../../core/shared/operators';
|
||||
import { SearchService } from '../../+search-page/search-service/search.service';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model';
|
||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { ItemDataService } from '../../core/data/item-data.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { RestResponse } from '../../core/cache/response.models';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-collection-item-mapper',
|
||||
styleUrls: ['./collection-item-mapper.component.scss'],
|
||||
templateUrl: './collection-item-mapper.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [
|
||||
fadeIn,
|
||||
fadeInOut
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: SEARCH_CONFIG_SERVICE,
|
||||
useClass: SearchConfigurationService
|
||||
}
|
||||
]
|
||||
})
|
||||
/**
|
||||
* Component used to map items to a collection
|
||||
*/
|
||||
export class CollectionItemMapperComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* A view on the tabset element
|
||||
* Used to switch tabs programmatically
|
||||
*/
|
||||
@ViewChild('tabs') tabs;
|
||||
|
||||
/**
|
||||
* The collection to map items to
|
||||
*/
|
||||
collectionRD$: Observable<RemoteData<Collection>>;
|
||||
|
||||
/**
|
||||
* Search options
|
||||
*/
|
||||
searchOptions$: Observable<PaginatedSearchOptions>;
|
||||
|
||||
/**
|
||||
* List of items to show under the "Browse" tab
|
||||
* Items inside the collection
|
||||
*/
|
||||
collectionItemsRD$: Observable<RemoteData<PaginatedList<DSpaceObject>>>;
|
||||
|
||||
/**
|
||||
* List of items to show under the "Map" tab
|
||||
* Items outside the collection
|
||||
*/
|
||||
mappedItemsRD$: Observable<RemoteData<PaginatedList<DSpaceObject>>>;
|
||||
|
||||
/**
|
||||
* Sort on title ASC by default
|
||||
* @type {SortOptions}
|
||||
*/
|
||||
defaultSortOptions: SortOptions = new SortOptions('dc.title', SortDirection.ASC);
|
||||
|
||||
/**
|
||||
* Firing this observable (shouldUpdate$.next(true)) forces the two lists to reload themselves
|
||||
* Usually fired after the lists their cache is cleared (to force a new request to the REST API)
|
||||
*/
|
||||
shouldUpdate$: BehaviorSubject<boolean>;
|
||||
|
||||
/**
|
||||
* Track whether at least one search has been performed or not
|
||||
* As soon as at least one search has been performed, we display the search results
|
||||
*/
|
||||
performedSearch = false;
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService,
|
||||
private searchService: SearchService,
|
||||
private notificationsService: NotificationsService,
|
||||
private itemDataService: ItemDataService,
|
||||
private collectionDataService: CollectionDataService,
|
||||
private translateService: TranslateService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.collectionRD$ = this.route.data.pipe(map((data) => data.collection)).pipe(getSucceededRemoteData()) as Observable<RemoteData<Collection>>;
|
||||
this.searchOptions$ = this.searchConfigService.paginatedSearchOptions;
|
||||
this.loadItemLists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load collectionItemsRD$ with a fixed scope to only obtain the items this collection owns
|
||||
* Load mappedItemsRD$ to only obtain items this collection doesn't own
|
||||
*/
|
||||
loadItemLists() {
|
||||
this.shouldUpdate$ = new BehaviorSubject<boolean>(true);
|
||||
const collectionAndOptions$ = observableCombineLatest(
|
||||
this.collectionRD$,
|
||||
this.searchOptions$,
|
||||
this.shouldUpdate$
|
||||
);
|
||||
this.collectionItemsRD$ = collectionAndOptions$.pipe(
|
||||
switchMap(([collectionRD, options, shouldUpdate]) => {
|
||||
if (shouldUpdate) {
|
||||
return this.collectionDataService.getMappedItems(collectionRD.payload.id, Object.assign(options, {
|
||||
sort: this.defaultSortOptions
|
||||
}))
|
||||
}
|
||||
})
|
||||
);
|
||||
this.mappedItemsRD$ = collectionAndOptions$.pipe(
|
||||
switchMap(([collectionRD, options, shouldUpdate]) => {
|
||||
if (shouldUpdate) {
|
||||
return this.searchService.search(Object.assign(new PaginatedSearchOptions(options), {
|
||||
query: this.buildQuery(collectionRD.payload.id, options.query),
|
||||
scope: undefined,
|
||||
dsoType: DSpaceObjectType.ITEM,
|
||||
sort: this.defaultSortOptions
|
||||
}), 10000).pipe(
|
||||
toDSpaceObjectListRD(),
|
||||
startWith(undefined)
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map/Unmap the selected items to the collection and display notifications
|
||||
* @param ids The list of item UUID's to map/unmap to the collection
|
||||
* @param remove Whether or not it's supposed to remove mappings
|
||||
*/
|
||||
mapItems(ids: string[], remove?: boolean) {
|
||||
const responses$ = this.collectionRD$.pipe(
|
||||
getSucceededRemoteData(),
|
||||
map((collectionRD: RemoteData<Collection>) => collectionRD.payload),
|
||||
switchMap((collection: Collection) =>
|
||||
observableCombineLatest(ids.map((id: string) =>
|
||||
remove ? this.itemDataService.removeMappingFromCollection(id, collection.id) : this.itemDataService.mapToCollection(id, collection.self)
|
||||
))
|
||||
)
|
||||
);
|
||||
|
||||
this.showNotifications(responses$, remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display notifications
|
||||
* @param {Observable<RestResponse[]>} responses$ The responses after adding/removing a mapping
|
||||
* @param {boolean} remove Whether or not the goal was to remove mappings
|
||||
*/
|
||||
private showNotifications(responses$: Observable<RestResponse[]>, remove?: boolean) {
|
||||
const messageInsertion = remove ? 'unmap' : 'map';
|
||||
|
||||
responses$.subscribe((responses: RestResponse[]) => {
|
||||
const successful = responses.filter((response: RestResponse) => response.isSuccessful);
|
||||
const unsuccessful = responses.filter((response: RestResponse) => !response.isSuccessful);
|
||||
if (successful.length > 0) {
|
||||
const successMessages = observableCombineLatest(
|
||||
this.translateService.get(`collection.edit.item-mapper.notifications.${messageInsertion}.success.head`),
|
||||
this.translateService.get(`collection.edit.item-mapper.notifications.${messageInsertion}.success.content`, { amount: successful.length })
|
||||
);
|
||||
|
||||
successMessages.subscribe(([head, content]) => {
|
||||
this.notificationsService.success(head, content);
|
||||
});
|
||||
}
|
||||
if (unsuccessful.length > 0) {
|
||||
const unsuccessMessages = observableCombineLatest(
|
||||
this.translateService.get(`collection.edit.item-mapper.notifications.${messageInsertion}.error.head`),
|
||||
this.translateService.get(`collection.edit.item-mapper.notifications.${messageInsertion}.error.content`, { amount: unsuccessful.length })
|
||||
);
|
||||
|
||||
unsuccessMessages.subscribe(([head, content]) => {
|
||||
this.notificationsService.error(head, content);
|
||||
});
|
||||
}
|
||||
// Force an update on all lists and switch back to the first tab
|
||||
this.shouldUpdate$.next(true);
|
||||
this.switchToFirstTab();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear url parameters on tab change (temporary fix until pagination is improved)
|
||||
* @param event
|
||||
*/
|
||||
tabChange(event) {
|
||||
this.performedSearch = false;
|
||||
this.router.navigateByUrl(this.getCurrentUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current url without parameters
|
||||
* @returns {string}
|
||||
*/
|
||||
getCurrentUrl(): string {
|
||||
if (this.router.url.indexOf('?') > -1) {
|
||||
return this.router.url.substring(0, this.router.url.indexOf('?'));
|
||||
}
|
||||
return this.router.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a query where items that are already mapped to a collection are excluded from
|
||||
* @param collectionId The collection's UUID
|
||||
* @param query The query to add to it
|
||||
*/
|
||||
buildQuery(collectionId: string, query: string): string {
|
||||
const excludeColQuery = `-location.coll:\"${collectionId}\"`;
|
||||
if (isNotEmpty(query)) {
|
||||
return `${excludeColQuery} AND ${query}`;
|
||||
} else {
|
||||
return excludeColQuery;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the view to focus on the first tab
|
||||
*/
|
||||
switchToFirstTab() {
|
||||
this.tabs.select('browseTab');
|
||||
}
|
||||
|
||||
/**
|
||||
* When a cancel event is fired, return to the collection page
|
||||
*/
|
||||
onCancel() {
|
||||
this.collectionRD$.pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
take(1)
|
||||
).subscribe((collection: Collection) => {
|
||||
this.router.navigate(['/collections/', collection.id])
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -10,6 +10,7 @@ import { CreateCollectionPageGuard } from './create-collection-page/create-colle
|
||||
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
|
||||
import { URLCombiner } from '../core/url-combiner/url-combiner';
|
||||
import { getCollectionModulePath } from '../app-routing.module';
|
||||
import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
|
||||
|
||||
export const COLLECTION_PARENT_PARAMETER = 'parent';
|
||||
|
||||
@@ -61,6 +62,15 @@ const COLLECTION_EDIT_PATH = ':id/edit';
|
||||
resolve: {
|
||||
collection: CollectionPageResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':id/edit/mapper',
|
||||
component: CollectionItemMapperComponent,
|
||||
pathMatch: 'full',
|
||||
resolve: {
|
||||
collection: CollectionPageResolver
|
||||
},
|
||||
canActivate: [AuthenticatedGuard]
|
||||
}
|
||||
])
|
||||
],
|
||||
|
@@ -52,6 +52,9 @@
|
||||
message="{{'error.recent-submissions' | translate}}"></ds-error>
|
||||
<ds-loading *ngIf="!itemRD || itemRD.isLoading"
|
||||
message="{{'loading.recent-submissions' | translate}}"></ds-loading>
|
||||
<div *ngIf="!itemRD?.isLoading && itemRD?.payload?.page.length === 0" class="alert alert-info w-100" role="alert">
|
||||
{{'collection.page.browse.recent.empty' | translate}}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ds-error *ngIf="collectionRD?.hasFailed"
|
||||
|
@@ -9,6 +9,8 @@ import { CreateCollectionPageComponent } from './create-collection-page/create-c
|
||||
import { CollectionFormComponent } from './collection-form/collection-form.component';
|
||||
import { EditCollectionPageComponent } from './edit-collection-page/edit-collection-page.component';
|
||||
import { DeleteCollectionPageComponent } from './delete-collection-page/delete-collection-page.component';
|
||||
import { CollectionItemMapperComponent } from './collection-item-mapper/collection-item-mapper.component';
|
||||
import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service';
|
||||
import { SearchService } from '../core/shared/search/search.service';
|
||||
|
||||
@NgModule({
|
||||
@@ -22,10 +24,12 @@ import { SearchService } from '../core/shared/search/search.service';
|
||||
CreateCollectionPageComponent,
|
||||
EditCollectionPageComponent,
|
||||
DeleteCollectionPageComponent,
|
||||
CollectionFormComponent
|
||||
CollectionFormComponent,
|
||||
CollectionItemMapperComponent
|
||||
],
|
||||
providers: [
|
||||
SearchService
|
||||
SearchService,
|
||||
SearchFixedFilterService
|
||||
]
|
||||
})
|
||||
export class CollectionPageModule {
|
||||
|
@@ -4,7 +4,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { RouteService } from '../../shared/services/route.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { RouteService } from '../../shared/services/route.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { CreateComColPageComponent } from '../../shared/comcol-forms/create-comcol-page/create-comcol-page.component';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
|
Reference in New Issue
Block a user