diff --git a/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts b/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
index 00ea9b9f62..30f326bec4 100644
--- a/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-status/item-status.component.spec.ts
@@ -11,7 +11,7 @@ import { Item } from '../../../core/shared/item.model';
import { By } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../core/data/remote-data';
+import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
describe('ItemStatusComponent', () => {
let comp: ItemStatusComponent;
@@ -27,7 +27,7 @@ describe('ItemStatusComponent', () => {
const routeStub = {
parent: {
- data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) })
+ data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
}
};
diff --git a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
index ac49eee7e7..4c23a1d1e5 100644
--- a/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-withdraw/item-withdraw.component.spec.ts
@@ -16,6 +16,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ItemWithdrawComponent } from './item-withdraw.component';
import { By } from '@angular/platform-browser';
import { RestResponse } from '../../../core/cache/response.models';
+import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemWithdrawComponent;
let fixture: ComponentFixture;
@@ -50,7 +51,7 @@ describe('ItemWithdrawComponent', () => {
routeStub = {
data: observableOf({
- item: new RemoteData(false, false, true, null, {
+ item: createSuccessfulRemoteDataObject({
id: 'fake-id'
})
})
diff --git a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
index 32acdef467..e4413e47c6 100644
--- a/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec.ts
@@ -17,6 +17,10 @@ import { By } from '@angular/platform-browser';
import { of as observableOf } from 'rxjs';
import { getItemEditPath } from '../../item-page-routing.module';
import { RestResponse } from '../../../core/cache/response.models';
+import {
+ createSuccessfulRemoteDataObject,
+ createSuccessfulRemoteDataObject$
+} from '../../../shared/testing/utils';
/**
* Test component that implements the AbstractSimpleItemActionComponent used to test the
@@ -65,12 +69,12 @@ describe('AbstractSimpleItemActionComponent', () => {
});
mockItemDataService = jasmine.createSpyObj({
- findById: observableOf(new RemoteData(false, false, true, undefined, mockItem))
+ findById: createSuccessfulRemoteDataObject$(mockItem)
});
routeStub = {
data: observableOf({
- item: new RemoteData(false, false, true, null, {
+ item: createSuccessfulRemoteDataObject({
id: 'fake-id'
})
})
diff --git a/src/app/+item-page/field-components/collections/collections.component.spec.ts b/src/app/+item-page/field-components/collections/collections.component.spec.ts
index 53fcded9e3..b53f499881 100644
--- a/src/app/+item-page/field-components/collections/collections.component.spec.ts
+++ b/src/app/+item-page/field-components/collections/collections.component.spec.ts
@@ -9,6 +9,10 @@ import { Item } from '../../../core/shared/item.model';
import { of as observableOf } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { TranslateModule } from '@ngx-translate/core';
+import {
+ createFailedRemoteDataObject$,
+ createSuccessfulRemoteDataObject$
+} from '../../../shared/testing/utils';
let collectionsComponent: CollectionsComponent;
let fixture: ComponentFixture;
@@ -24,8 +28,8 @@ const mockCollection1: Collection = Object.assign(new Collection(), {
}
});
-const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: observableOf(new RemoteData(false, false, true, null, mockCollection1))});
-const failedMockItem: Item = Object.assign(new Item(), {owningCollection: observableOf(new RemoteData(false, false, false, null, mockCollection1))});
+const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: createSuccessfulRemoteDataObject$(mockCollection1)});
+const failedMockItem: Item = Object.assign(new Item(), {owningCollection: createFailedRemoteDataObject$(mockCollection1)});
describe('CollectionsComponent', () => {
beforeEach(async(() => {
diff --git a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss
index dff97a6eb2..75dfd09d0d 100644
--- a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss
+++ b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../styles/variables.scss';
-
:host {
.simple-view-element {
margin-bottom: 15px;
diff --git a/src/app/+item-page/field-components/metadata-uri-values/metadata-uri-values.component.scss b/src/app/+item-page/field-components/metadata-uri-values/metadata-uri-values.component.scss
index 96ce861942..e69de29bb2 100644
--- a/src/app/+item-page/field-components/metadata-uri-values/metadata-uri-values.component.scss
+++ b/src/app/+item-page/field-components/metadata-uri-values/metadata-uri-values.component.scss
@@ -1 +0,0 @@
-@import '../../../../styles/variables.scss';
diff --git a/src/app/+item-page/field-components/metadata-values/metadata-values.component.scss b/src/app/+item-page/field-components/metadata-values/metadata-values.component.scss
index 96ce861942..e69de29bb2 100644
--- a/src/app/+item-page/field-components/metadata-values/metadata-values.component.scss
+++ b/src/app/+item-page/field-components/metadata-values/metadata-values.component.scss
@@ -1 +0,0 @@
-@import '../../../../styles/variables.scss';
diff --git a/src/app/+item-page/full/field-components/file-section/full-file-section.component.scss b/src/app/+item-page/full/field-components/file-section/full-file-section.component.scss
index 77db5d97cf..5bb04cac2f 100644
--- a/src/app/+item-page/full/field-components/file-section/full-file-section.component.scss
+++ b/src/app/+item-page/full/field-components/file-section/full-file-section.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../styles/variables';
-@import '../../../../../styles/mixins';
@media screen and (min-width: map-get($grid-breakpoints, md)) {
dt {
text-align: right;
diff --git a/src/app/+item-page/full/full-item-page.component.scss b/src/app/+item-page/full/full-item-page.component.scss
index 4fe93bbb7a..458c4992c7 100644
--- a/src/app/+item-page/full/full-item-page.component.scss
+++ b/src/app/+item-page/full/full-item-page.component.scss
@@ -1,5 +1,3 @@
-@import '../../../styles/variables.scss';
-
:host {
div.simple-view-link {
text-align: center;
diff --git a/src/app/+item-page/full/full-item-page.component.spec.ts b/src/app/+item-page/full/full-item-page.component.spec.ts
index 15dd001964..2f151b4997 100644
--- a/src/app/+item-page/full/full-item-page.component.spec.ts
+++ b/src/app/+item-page/full/full-item-page.component.spec.ts
@@ -17,9 +17,13 @@ import { RemoteData } from '../../core/data/remote-data';
import { of as observableOf } from 'rxjs';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { By } from '@angular/platform-browser';
+import {
+ createSuccessfulRemoteDataObject,
+ createSuccessfulRemoteDataObject$
+} from '../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), {
- bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))),
+ bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
@@ -30,7 +34,7 @@ const mockItem: Item = Object.assign(new Item(), {
}
});
const routeStub = Object.assign(new ActivatedRouteStub(), {
- data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) })
+ data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
});
const metadataServiceStub = {
/* tslint:disable:no-empty */
diff --git a/src/app/+item-page/item-page.module.ts b/src/app/+item-page/item-page.module.ts
index 123e3ea143..6743028b6c 100644
--- a/src/app/+item-page/item-page.module.ts
+++ b/src/app/+item-page/item-page.module.ts
@@ -20,16 +20,12 @@ import { FullFileSectionComponent } from './full/field-components/file-section/f
import { RelatedItemsComponent } from './simple/related-items/related-items-component';
import { SearchPageModule } from '../+search-page/search-page.module';
import { PublicationComponent } from './simple/item-types/publication/publication.component';
-import { PersonComponent } from './simple/item-types/person/person.component';
-import { OrgunitComponent } from './simple/item-types/orgunit/orgunit.component';
-import { ProjectComponent } from './simple/item-types/project/project.component';
-import { JournalComponent } from './simple/item-types/journal/journal.component';
-import { JournalVolumeComponent } from './simple/item-types/journal-volume/journal-volume.component';
-import { JournalIssueComponent } from './simple/item-types/journal-issue/journal-issue.component';
import { ItemComponent } from './simple/item-types/shared/item.component';
import { EditItemPageModule } from './edit-item-page/edit-item-page.module';
import { MetadataRepresentationListComponent } from './simple/metadata-representation-list/metadata-representation-list.component';
import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component';
+import { MetadataValuesComponent } from './field-components/metadata-values/metadata-values.component';
+import { MetadataFieldWrapperComponent } from './field-components/metadata-field-wrapper/metadata-field-wrapper.component';
@NgModule({
imports: [
@@ -53,26 +49,23 @@ import { RelatedEntitiesSearchComponent } from './simple/related-entities/relate
CollectionsComponent,
FullFileSectionComponent,
PublicationComponent,
- ProjectComponent,
- OrgunitComponent,
- PersonComponent,
RelatedItemsComponent,
ItemComponent,
GenericItemPageFieldComponent,
- JournalComponent,
- JournalIssueComponent,
- JournalVolumeComponent,
MetadataRepresentationListComponent,
RelatedEntitiesSearchComponent
],
+ exports: [
+ ItemComponent,
+ MetadataValuesComponent,
+ MetadataFieldWrapperComponent,
+ GenericItemPageFieldComponent,
+ RelatedEntitiesSearchComponent,
+ RelatedItemsComponent,
+ MetadataRepresentationListComponent
+ ],
entryComponents: [
- PublicationComponent,
- ProjectComponent,
- OrgunitComponent,
- PersonComponent,
- JournalComponent,
- JournalIssueComponent,
- JournalVolumeComponent
+ PublicationComponent
]
})
export class ItemPageModule {
diff --git a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts
index ea6e722c66..1b7acb2e3b 100644
--- a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts
+++ b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts
@@ -11,6 +11,7 @@ import { ItemPageFieldComponent } from './item-page-field.component';
import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component';
import { of as observableOf } from 'rxjs';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
let comp: ItemPageFieldComponent;
let fixture: ComponentFixture;
@@ -52,7 +53,7 @@ describe('ItemPageFieldComponent', () => {
export function mockItemWithMetadataFieldAndValue(field: string, value: string): Item {
const item = Object.assign(new Item(), {
- bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))),
+ bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: new MetadataMap()
});
item.metadata[field] = [{
diff --git a/src/app/+item-page/simple/item-page.component.spec.ts b/src/app/+item-page/simple/item-page.component.spec.ts
index e1202ab725..cd5c385671 100644
--- a/src/app/+item-page/simple/item-page.component.spec.ts
+++ b/src/app/+item-page/simple/item-page.component.spec.ts
@@ -16,9 +16,13 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { By } from '@angular/platform-browser';
import { createRelationshipsObservable } from './item-types/shared/item.component.spec';
import { of as observableOf } from 'rxjs';
+import {
+ createFailedRemoteDataObject$, createPendingRemoteDataObject$, createSuccessfulRemoteDataObject,
+ createSuccessfulRemoteDataObject$
+} from '../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), {
- bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))),
+ bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
@@ -33,7 +37,7 @@ describe('ItemPageComponent', () => {
/* tslint:enable:no-empty */
};
const mockRoute = Object.assign(new ActivatedRouteStub(), {
- data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) })
+ data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
});
beforeEach(async(() => {
@@ -66,7 +70,8 @@ describe('ItemPageComponent', () => {
describe('when the item is loading', () => {
beforeEach(() => {
- comp.itemRD$ = observableOf(new RemoteData(true, true, true, null, undefined));
+ comp.itemRD$ = createPendingRemoteDataObject$(undefined);
+ // comp.itemRD$ = observableOf(new RemoteData(true, true, true, null, undefined));
fixture.detectChanges();
});
@@ -78,7 +83,7 @@ describe('ItemPageComponent', () => {
describe('when the item failed loading', () => {
beforeEach(() => {
- comp.itemRD$ = observableOf(new RemoteData(false, false, false, null, undefined));
+ comp.itemRD$ = createFailedRemoteDataObject$(undefined);
fixture.detectChanges();
});
diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.html b/src/app/+item-page/simple/item-types/publication/publication.component.html
index 37135c6036..abf5225c27 100644
--- a/src/app/+item-page/simple/item-types/publication/publication.component.html
+++ b/src/app/+item-page/simple/item-types/publication/publication.component.html
@@ -21,6 +21,10 @@
[fields]="['journalvolume.identifier.name']"
[label]="'publication.page.volume-title'">
+
+
+
+
+
;
- constructor(
- @Inject(ITEM) public item: Item,
- private ids: ItemDataService
- ) {
- super(item);
- }
-
ngOnInit(): void {
super.ngOnInit();
if (this.resolvedRelsAndTypes$) {
- this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author', this.ids);
+ this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author');
this.projects$ = this.resolvedRelsAndTypes$.pipe(
- filterRelationsByTypeLabel('isProjectOfPublication'),
- relationsToItems(this.item.id, this.ids)
+ getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPublication')
);
this.orgUnits$ = this.resolvedRelsAndTypes$.pipe(
- filterRelationsByTypeLabel('isOrgUnitOfPublication'),
- relationsToItems(this.item.id, this.ids)
+ getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPublication')
);
this.journalIssues$ = this.resolvedRelsAndTypes$.pipe(
- filterRelationsByTypeLabel('isJournalIssueOfPublication'),
- relationsToItems(this.item.id, this.ids)
+ getRelatedItemsByTypeLabel(this.item.id, 'isJournalIssueOfPublication')
);
}
diff --git a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
index 7c632a9365..65ad743245 100644
--- a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
+++ b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts
@@ -2,16 +2,15 @@ import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-rep
import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
import { MetadataValue } from '../../../../core/shared/metadata.models';
-import { getSucceededRemoteData } from '../../../../core/shared/operators';
-import { hasValue } from '../../../../shared/empty.util';
+import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
+import { hasNoValue, hasValue } from '../../../../shared/empty.util';
import { Observable } from 'rxjs/internal/Observable';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
-import { distinctUntilChanged, flatMap, map } from 'rxjs/operators';
-import { of as observableOf, zip as observableZip } from 'rxjs';
+import { distinctUntilChanged, flatMap, map, switchMap } from 'rxjs/operators';
+import { of as observableOf, zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs';
import { ItemDataService } from '../../../../core/data/item-data.service';
import { Item } from '../../../../core/shared/item.model';
-import { RemoteData } from '../../../../core/data/remote-data';
/**
* Operator for comparing arrays using a mapping function
@@ -43,47 +42,74 @@ export const compareArraysUsingIds = () =>
/**
* Fetch the relationships which match the type label given
* @param {string} label Type label
+ * @param thisId The item's id of which the relations belong to
* @returns {(source: Observable<[Relationship[] , RelationshipType[]]>) => Observable}
*/
-export const filterRelationsByTypeLabel = (label: string) =>
+export const filterRelationsByTypeLabel = (label: string, thisId?: string) =>
(source: Observable<[Relationship[], RelationshipType[]]>): Observable =>
source.pipe(
- map(([relsCurrentPage, relTypesCurrentPage]) =>
- relsCurrentPage.filter((rel: Relationship, idx: number) =>
- hasValue(relTypesCurrentPage[idx]) && (relTypesCurrentPage[idx].leftLabel === label ||
- relTypesCurrentPage[idx].rightLabel === label)
- )
- ),
+ switchMap(([relsCurrentPage, relTypesCurrentPage]) => {
+ const relatedItems$ = observableZip(...relsCurrentPage.map((rel: Relationship) =>
+ observableCombineLatest(
+ rel.leftItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()),
+ rel.rightItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()))
+ )
+ );
+ return relatedItems$.pipe(
+ map((arr) => relsCurrentPage.filter((rel: Relationship, idx: number) =>
+ hasValue(relTypesCurrentPage[idx]) && (
+ (hasNoValue(thisId) && (relTypesCurrentPage[idx].leftLabel === label ||
+ relTypesCurrentPage[idx].rightLabel === label)) ||
+ (thisId === arr[idx][0].id && relTypesCurrentPage[idx].leftLabel === label) ||
+ (thisId === arr[idx][1].id && relTypesCurrentPage[idx].rightLabel === label)
+ )
+ ))
+ );
+ }),
distinctUntilChanged(compareArraysUsingIds())
);
/**
* Operator for turning a list of relationships into a list of the relevant items
- * @param {string} thisId The item's id of which the relations belong to
- * @param {ItemDataService} ids The ItemDataService to fetch items from the REST API
+ * @param {string} thisId The item's id of which the relations belong to
* @returns {(source: Observable) => Observable- }
*/
-export const relationsToItems = (thisId: string, ids: ItemDataService) =>
+export const relationsToItems = (thisId: string) =>
(source: Observable): Observable
- =>
source.pipe(
flatMap((rels: Relationship[]) =>
observableZip(
- ...rels.map((rel: Relationship) => {
- let queryId = rel.leftId;
- if (rel.leftId === thisId) {
- queryId = rel.rightId;
- }
- return ids.findById(queryId);
- })
+ ...rels.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem))
)
),
- map((arr: Array>) =>
+ map((arr) =>
arr
- .filter((d: RemoteData
- ) => d.hasSucceeded)
- .map((d: RemoteData
- ) => d.payload)),
+ .filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded)
+ .map(([leftItem, rightItem]) => {
+ if (leftItem.payload.id === thisId) {
+ return rightItem.payload;
+ } else if (rightItem.payload.id === thisId) {
+ return leftItem.payload;
+ }
+ })
+ .filter((item: Item) => hasValue(item))
+ ),
distinctUntilChanged(compareArraysUsingIds()),
);
+/**
+ * Operator for turning a list of relationships and their relationship-types into a list of relevant items by relationship label
+ * @param thisId The item's id of which the relations belong to
+ * @param label The label of the relationship-type to filter on
+ * @param side Filter only on one side of the relationship (for example: child-parent relationships)
+ */
+export const getRelatedItemsByTypeLabel = (thisId: string, label: string) =>
+ (source: Observable<[Relationship[], RelationshipType[]]>): Observable
- =>
+ source.pipe(
+ filterRelationsByTypeLabel(label, thisId),
+ relationsToItems(thisId)
+ );
+
/**
* Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata
* @param parentId The id of the parent item
@@ -103,13 +129,15 @@ export const relationsToRepresentations = (parentId: string, itemType: string, m
const matchingRels = rels.filter((rel: Relationship) => ('' + rel.id) === metadatum.virtualValue);
if (matchingRels.length > 0) {
const matchingRel = matchingRels[0];
- let queryId = matchingRel.leftId;
- if (matchingRel.leftId === parentId) {
- queryId = matchingRel.rightId;
- }
- return ids.findById(queryId).pipe(
- getSucceededRemoteData(),
- map((d: RemoteData
- ) => Object.assign(new ItemMetadataRepresentation(), d.payload))
+ return observableCombineLatest(matchingRel.leftItem, matchingRel.rightItem).pipe(
+ map(([leftItem, rightItem]) => {
+ if (leftItem.payload.id === parentId) {
+ return rightItem.payload;
+ } else if (rightItem.payload.id === parentId) {
+ return leftItem.payload;
+ }
+ }),
+ map((item: Item) => Object.assign(new ItemMetadataRepresentation(), item))
);
}
} else {
diff --git a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
index a6b4dd801d..3f525e6a25 100644
--- a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
+++ b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts
@@ -26,6 +26,7 @@ import { MetadatumRepresentation } from '../../../../core/shared/metadata-repres
import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
/**
* Create a generic test for an item-page-fields component using a mockItem and the type of component
@@ -102,11 +103,13 @@ export function containsFieldInput(fields: DebugElement[], metadataKey: string):
}
export function createRelationshipsObservable() {
- return observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [
+ return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
Object.assign(new Relationship(), {
- relationshipType: observableOf(new RemoteData(false, false, true, null, new RelationshipType()))
+ relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType()),
+ leftItem: createSuccessfulRemoteDataObject$(new Item()),
+ rightItem: createSuccessfulRemoteDataObject$(new Item())
})
- ])));
+ ]));
}
describe('ItemComponent', () => {
const arr1 = [
@@ -319,20 +322,31 @@ describe('ItemComponent', () => {
let fixture: ComponentFixture;
const metadataField = 'dc.contributor.author';
+ const relatedItem = Object.assign(new Item(), {
+ id: '2',
+ metadata: Object.assign(new MetadataMap(), {
+ 'dc.title': [
+ {
+ language: 'en_US',
+ value: 'related item'
+ }
+ ]
+ })
+ });
const mockItem = Object.assign(new Item(), {
id: '1',
uuid: '1',
- metadata: new MetadataMap(),
- relationships: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [
- Object.assign(new Relationship(), {
- uuid: '123',
- id: '123',
- leftId: '1',
- rightId: '2',
- relationshipType: observableOf(new RemoteData(false, false, true, null, new RelationshipType()))
- })
- ])))
+ metadata: new MetadataMap()
});
+ mockItem.relationships = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
+ Object.assign(new Relationship(), {
+ uuid: '123',
+ id: '123',
+ leftItem: createSuccessfulRemoteDataObject$(mockItem),
+ rightItem: createSuccessfulRemoteDataObject$(relatedItem),
+ relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType())
+ })
+ ]));
mockItem.metadata[metadataField] = [
{
value: 'Second value',
@@ -353,21 +367,10 @@ describe('ItemComponent', () => {
authority: '123'
}
] as MetadataValue[];
- const relatedItem = Object.assign(new Item(), {
- id: '2',
- metadata: Object.assign(new MetadataMap(), {
- 'dc.title': [
- {
- language: 'en_US',
- value: 'related item'
- }
- ]
- })
- });
const mockItemDataService = Object.assign({
findById: (id) => {
if (id === relatedItem.id) {
- return observableOf(new RemoteData(false, false, true, null, relatedItem))
+ return createSuccessfulRemoteDataObject$(relatedItem)
}
}
}) as ItemDataService;
@@ -397,7 +400,7 @@ describe('ItemComponent', () => {
fixture = TestBed.createComponent(ItemComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
- representations = comp.buildRepresentations('bogus', metadataField, mockItemDataService);
+ representations = comp.buildRepresentations('bogus', metadataField);
}));
it('should contain exactly 4 metadata-representations', () => {
diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts
index c6d43aa6b3..556496fe49 100644
--- a/src/app/+item-page/simple/item-types/shared/item.component.ts
+++ b/src/app/+item-page/simple/item-types/shared/item.component.ts
@@ -1,5 +1,5 @@
import { Component, Inject, OnInit } from '@angular/core';
-import { combineLatest as observableCombineLatest, Observable, zip as observableZip } from 'rxjs';
+import { Observable , zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs';
import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators';
import { ItemDataService } from '../../../../core/data/item-data.service';
import { PaginatedList } from '../../../../core/data/paginated-list';
@@ -7,10 +7,52 @@ import { RemoteData } from '../../../../core/data/remote-data';
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { Item } from '../../../../core/shared/item.model';
-import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
-import { compareArraysUsingIds, relationsToRepresentations } from './item-relationships-utils';
+import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
+import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
+import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
+import { of } from 'rxjs/internal/observable/of';
+import { MetadataValue } from '../../../../core/shared/metadata.models';
+import { compareArraysUsingIds } from './item-relationships-utils';
+
+/**
+ * Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata
+ * @param thisId The id of the parent item
+ * @param itemType The type of relation this list resembles (for creating representations)
+ * @param metadata The list of original Metadatum objects
+ */
+export const relationsToRepresentations = (thisId: string, itemType: string, metadata: MetadataValue[]) =>
+ (source: Observable): Observable =>
+ source.pipe(
+ flatMap((rels: Relationship[]) =>
+ observableZip(
+ ...metadata
+ .map((metadatum: any) => Object.assign(new MetadataValue(), metadatum))
+ .map((metadatum: MetadataValue) => {
+ if (metadatum.isVirtual) {
+ const matchingRels = rels.filter((rel: Relationship) => ('' + rel.id) === metadatum.virtualValue);
+ if (matchingRels.length > 0) {
+ const matchingRel = matchingRels[0];
+ return observableCombineLatest(matchingRel.leftItem, matchingRel.rightItem).pipe(
+ filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded),
+ map(([leftItem, rightItem]) => {
+ if (leftItem.payload.id === thisId) {
+ return rightItem.payload;
+ } else if (rightItem.payload.id === thisId) {
+ return leftItem.payload;
+ }
+ }),
+ map((item: Item) => Object.assign(new ItemMetadataRepresentation(), item))
+ );
+ }
+ } else {
+ return of(Object.assign(new MetadatumRepresentation(itemType), metadatum));
+ }
+ })
+ )
+ )
+ );
@Component({
selector: 'ds-item',
@@ -60,9 +102,8 @@ export class ItemComponent implements OnInit {
* certain type.
* @param itemType The type of item we're building representations of. Used for matching templates.
* @param metadataField The metadata field that resembles the item type.
- * @param itemDataService ItemDataService to turn relations into items.
*/
- buildRepresentations(itemType: string, metadataField: string, itemDataService: ItemDataService): Observable {
+ buildRepresentations(itemType: string, metadataField: string): Observable {
const metadata = this.item.findMetadataSortedByPlace(metadataField);
const relsCurrentPage$ = this.item.relationships.pipe(
getSucceededRemoteData(),
@@ -72,7 +113,7 @@ export class ItemComponent implements OnInit {
);
return relsCurrentPage$.pipe(
- relationsToRepresentations(this.item.id, itemType, metadata, itemDataService)
+ relationsToRepresentations(this.item.id, itemType, metadata)
);
}
diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html
index 9ec082db73..c7e1f77264 100644
--- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html
+++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.html
@@ -1,6 +1,6 @@
diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts
index e76a9cf3d0..711e1b9d3d 100644
--- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts
+++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts
@@ -47,9 +47,9 @@ describe('RelatedEntitiesSearchComponent', () => {
expect(comp.fixedFilter).toEqual(mockFilter);
});
- it('should create a fixedFilter$', () => {
- comp.fixedFilter$.subscribe((fixedFilter) => {
- expect(fixedFilter).toEqual(mockRelationEntityType);
+ it('should create a configuration$', () => {
+ comp.configuration$.subscribe((configuration) => {
+ expect(configuration).toEqual(mockRelationEntityType);
})
});
diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts
index 672655a8b8..4c0b127925 100644
--- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts
+++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.ts
@@ -47,7 +47,7 @@ export class RelatedEntitiesSearchComponent implements OnInit {
@Input() sideBarWidth = 4;
fixedFilter: string;
- fixedFilter$: Observable;
+ configuration$: Observable;
constructor(private fixedFilterService: SearchFixedFilterService) {
}
@@ -57,7 +57,7 @@ export class RelatedEntitiesSearchComponent implements OnInit {
this.fixedFilter = this.fixedFilterService.getFilterByRelation(this.relationType, this.item.id);
}
if (isNotEmpty(this.relationEntityType)) {
- this.fixedFilter$ = of(this.relationEntityType);
+ this.configuration$ = of(this.relationEntityType);
}
}
diff --git a/src/app/+item-page/simple/related-items/related-items.component.spec.ts b/src/app/+item-page/simple/related-items/related-items.component.spec.ts
index ef42ab1098..1896f46015 100644
--- a/src/app/+item-page/simple/related-items/related-items.component.spec.ts
+++ b/src/app/+item-page/simple/related-items/related-items.component.spec.ts
@@ -8,14 +8,15 @@ import { PageInfo } from '../../../core/shared/page-info.model';
import { By } from '@angular/platform-browser';
import { createRelationshipsObservable } from '../item-types/shared/item.component.spec';
import { of as observableOf } from 'rxjs';
+import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
const mockItem1: Item = Object.assign(new Item(), {
- bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))),
+ bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
const mockItem2: Item = Object.assign(new Item(), {
- bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))),
+ bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [],
relationships: createRelationshipsObservable()
});
diff --git a/src/app/+login-page/login-page.component.scss b/src/app/+login-page/login-page.component.scss
index 38adf24671..58e7272e5f 100644
--- a/src/app/+login-page/login-page.component.scss
+++ b/src/app/+login-page/login-page.component.scss
@@ -1,5 +1,3 @@
-@import '../../styles/variables.scss';
-
.login-logo {
height: $login-logo-height;
width: $login-logo-width;
diff --git a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
index 9658814a6a..34af21073f 100644
--- a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
+++ b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts
@@ -29,6 +29,7 @@ import { RoleDirective } from '../shared/roles/role.directive';
import { RoleService } from '../core/roles/role.service';
import { MockRoleService } from '../shared/mocks/mock-role-service';
import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service';
+import { createSuccessfulRemoteDataObject$ } from '../shared/testing/utils';
describe('MyDSpacePageComponent', () => {
let comp: MyDSpacePageComponent;
@@ -46,7 +47,7 @@ describe('MyDSpacePageComponent', () => {
pagination.currentPage = 1;
pagination.pageSize = 10;
const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
- const mockResults = observableOf(new RemoteData(false, false, true, null, ['test', 'data']));
+ const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
const searchServiceStub = jasmine.createSpyObj('SearchService', {
search: mockResults,
getSearchLink: '/mydspace',
diff --git a/src/app/+search-page/configuration-search-page.component.spec.ts b/src/app/+search-page/configuration-search-page.component.spec.ts
new file mode 100644
index 0000000000..a18dd38f78
--- /dev/null
+++ b/src/app/+search-page/configuration-search-page.component.spec.ts
@@ -0,0 +1,21 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { configureSearchComponentTestingModule } from './search-page.component.spec';
+import { SearchConfigurationService } from './search-service/search-configuration.service';
+import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
+
+describe('ConfigurationSearchPageComponent', () => {
+ let comp: ConfigurationSearchPageComponent;
+ let fixture: ComponentFixture;
+ let searchConfigService: SearchConfigurationService;
+
+ beforeEach(async(() => {
+ configureSearchComponentTestingModule(ConfigurationSearchPageComponent);
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfigurationSearchPageComponent);
+ comp = fixture.componentInstance;
+ searchConfigService = (comp as any).searchConfigService;
+ fixture.detectChanges();
+ });
+});
diff --git a/src/app/+search-page/configuration-search-page.component.ts b/src/app/+search-page/configuration-search-page.component.ts
new file mode 100644
index 0000000000..85619e8f04
--- /dev/null
+++ b/src/app/+search-page/configuration-search-page.component.ts
@@ -0,0 +1,71 @@
+import { HostWindowService } from '../shared/host-window.service';
+import { SearchService } from './search-service/search.service';
+import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
+import { SearchPageComponent } from './search-page.component';
+import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
+import { pushInOut } from '../shared/animations/push';
+import { RouteService } from '../shared/services/route.service';
+import { SearchConfigurationService } from './search-service/search-configuration.service';
+import { Observable } from 'rxjs';
+import { PaginatedSearchOptions } from './paginated-search-options.model';
+import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
+import { map } from 'rxjs/operators';
+
+/**
+ * This component renders a search page using a configuration as input.
+ */
+@Component({
+ selector: 'ds-configuration-search-page',
+ styleUrls: ['./search-page.component.scss'],
+ templateUrl: './search-page.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ animations: [pushInOut],
+ providers: [
+ {
+ provide: SEARCH_CONFIG_SERVICE,
+ useClass: SearchConfigurationService
+ }
+ ]
+})
+
+export class ConfigurationSearchPageComponent extends SearchPageComponent implements OnInit {
+ /**
+ * The configuration to use for the search options
+ * If empty, the configuration will be determined by the route parameter called 'configuration'
+ */
+ @Input() configuration: string;
+
+ constructor(protected service: SearchService,
+ protected sidebarService: SearchSidebarService,
+ protected windowService: HostWindowService,
+ @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService,
+ protected routeService: RouteService) {
+ super(service, sidebarService, windowService, searchConfigService, routeService);
+ }
+
+ /**
+ * Listening to changes in the paginated search options
+ * If something changes, update the search results
+ *
+ * Listen to changes in the scope
+ * If something changes, update the list of scopes for the dropdown
+ */
+ ngOnInit(): void {
+ super.ngOnInit();
+ }
+
+ /**
+ * Get the current paginated search options after updating the configuration using the configuration input
+ * This is to make sure the configuration is included in the paginated search options, as it is not part of any
+ * query or route parameters
+ * @returns {Observable}
+ */
+ protected getSearchOptions(): Observable {
+ return this.searchConfigService.paginatedSearchOptions.pipe(
+ map((options: PaginatedSearchOptions) => {
+ const config = this.configuration || options.configuration;
+ return Object.assign(options, { configuration: config });
+ })
+ );
+ }
+}
diff --git a/src/app/+search-page/configuration-search-page.guard.ts b/src/app/+search-page/configuration-search-page.guard.ts
new file mode 100644
index 0000000000..c52a0a6d8e
--- /dev/null
+++ b/src/app/+search-page/configuration-search-page.guard.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { Observable } from 'rxjs';
+
+@Injectable()
+/**
+ * Assemble the correct i18n key for the configuration search page's title depending on the current route's configuration parameter.
+ * The format of the key will be "{configuration}.search.title" with:
+ * - configuration: The current configuration stored in route.params
+ */
+export class ConfigurationSearchPageGuard implements CanActivate {
+ canActivate(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot): Observable | Promise | boolean {
+ const configuration = route.params.configuration;
+
+ const newTitle = configuration + '.search.title';
+
+ route.data = { title: newTitle };
+ return true;
+ }
+}
diff --git a/src/app/+search-page/filtered-search-page.component.spec.ts b/src/app/+search-page/filtered-search-page.component.spec.ts
index 5c49767ed2..59ab9d7b0d 100644
--- a/src/app/+search-page/filtered-search-page.component.spec.ts
+++ b/src/app/+search-page/filtered-search-page.component.spec.ts
@@ -18,20 +18,4 @@ describe('FilteredSearchPageComponent', () => {
searchConfigService = (comp as any).searchConfigService;
fixture.detectChanges();
});
-
- describe('when fixedFilterQuery is defined', () => {
- const fixedFilterQuery = 'fixedFilterQuery';
-
- beforeEach(() => {
- spyOn(searchConfigService, 'updateFixedFilter').and.callThrough();
- comp.fixedFilterQuery = fixedFilterQuery;
- comp.ngOnInit();
- fixture.detectChanges();
- });
-
- it('should update the paginated search options', () => {
- expect(searchConfigService.updateFixedFilter).toHaveBeenCalledWith(fixedFilterQuery);
- });
- });
-
});
diff --git a/src/app/+search-page/filtered-search-page.component.ts b/src/app/+search-page/filtered-search-page.component.ts
index d577c2c44c..66c619b823 100644
--- a/src/app/+search-page/filtered-search-page.component.ts
+++ b/src/app/+search-page/filtered-search-page.component.ts
@@ -2,20 +2,22 @@ import { HostWindowService } from '../shared/host-window.service';
import { SearchService } from './search-service/search.service';
import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
import { SearchPageComponent } from './search-page.component';
-import { ChangeDetectionStrategy, Component, Inject, Input } from '@angular/core';
+import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
import { pushInOut } from '../shared/animations/push';
import { RouteService } from '../shared/services/route.service';
import { SearchConfigurationService } from './search-service/search-configuration.service';
import { Observable } from 'rxjs';
import { PaginatedSearchOptions } from './paginated-search-options.model';
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
+import { map } from 'rxjs/operators';
/**
* This component renders a simple item page.
* The route parameter 'id' is used to request the item it represents.
* All fields of the item that should be displayed, are defined in its template.
*/
-@Component({selector: 'ds-filtered-search-page',
+@Component({
+ selector: 'ds-filtered-search-page',
styleUrls: ['./search-page.component.scss'],
templateUrl: './search-page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -28,8 +30,7 @@ import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.compone
]
})
-export class FilteredSearchPageComponent extends SearchPageComponent {
-
+export class FilteredSearchPageComponent extends SearchPageComponent implements OnInit {
/**
* The actual query for the fixed filter.
* If empty, the query will be determined by the route parameter called 'filter'
@@ -44,6 +45,17 @@ export class FilteredSearchPageComponent extends SearchPageComponent {
super(service, sidebarService, windowService, searchConfigService, routeService);
}
+ /**
+ * Listening to changes in the paginated search options
+ * If something changes, update the search results
+ *
+ * Listen to changes in the scope
+ * If something changes, update the list of scopes for the dropdown
+ */
+ ngOnInit(): void {
+ super.ngOnInit();
+ }
+
/**
* Get the current paginated search options after updating the fixed filter using the fixedFilterQuery input
* This is to make sure the fixed filter is included in the paginated search options, as it is not part of any
@@ -51,8 +63,11 @@ export class FilteredSearchPageComponent extends SearchPageComponent {
* @returns {Observable}
*/
protected getSearchOptions(): Observable {
- this.searchConfigService.updateFixedFilter(this.fixedFilterQuery);
- return this.searchConfigService.paginatedSearchOptions;
+ return this.searchConfigService.paginatedSearchOptions.pipe(
+ map((options: PaginatedSearchOptions) => {
+ const filter = this.fixedFilterQuery || options.fixedFilter;
+ return Object.assign(options, { fixedFilter: filter });
+ })
+ );
}
-
}
diff --git a/src/app/+search-page/filtered-search-page.guard.ts b/src/app/+search-page/filtered-search-page.guard.ts
deleted file mode 100644
index 39fbb48c67..0000000000
--- a/src/app/+search-page/filtered-search-page.guard.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Injectable } from '@angular/core';
-import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
-import { Observable } from 'rxjs';
-
-@Injectable()
-/**
- * Assemble the correct i18n key for the filtered search page's title depending on the current route's filter parameter
- * and title data.
- * The format of the key will be "{title}{filter}.title" with:
- * - title: The prefix of the key stored in route.data
- * - filter: The current filter stored in route.params
- */
-export class FilteredSearchPageGuard implements CanActivate {
- canActivate(
- route: ActivatedRouteSnapshot,
- state: RouterStateSnapshot): Observable | Promise | boolean {
- const filter = route.params.filter;
-
- const newTitle = route.data.title + filter + '.title';
-
- route.data = { title: newTitle };
- return true;
- }
-}
diff --git a/src/app/+search-page/normalized-search-result.model.ts b/src/app/+search-page/normalized-search-result.model.ts
index 32f3217b54..abb5f21250 100644
--- a/src/app/+search-page/normalized-search-result.model.ts
+++ b/src/app/+search-page/normalized-search-result.model.ts
@@ -1,10 +1,12 @@
-import { autoserialize, autoserializeAs } from 'cerialize';
+import { autoserialize, inheritSerialization } from 'cerialize';
import { MetadataMap } from '../core/shared/metadata.models';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
+import { NormalizedObject } from '../core/cache/models/normalized-object.model';
/**
* Represents a normalized version of a search result object of a certain DSpaceObject
*/
+@inheritSerialization(NormalizedObject)
export class NormalizedSearchResult implements ListableObject {
/**
* The UUID of the DSpaceObject that was found
diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss
index a28db359b5..20f1bf2952 100644
--- a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../styles/variables.scss';
-@import '../../../../../styles/mixins.scss';
.filters {
.toggle-more-filters a {
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
index 7ab7ffd0ca..b853346fa5 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
@@ -1,9 +1,9 @@
-
- {{filterValue.value}}
-
+ [routerLink]="[getSearchLink()]"
+ [queryParams]="addQueryParams" queryParamsHandling="merge">
+
+ {{filterValue.value}}
+
{{filterValue.count}}
-
\ No newline at end of file
+
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.scss b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.scss
index 6452f2469b..c5a38f24a7 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../../styles/variables.scss';
-
a {
color: $body-color;
&:hover, &focus {
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
index 8e8ad9b4e3..4efee3e7b5 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
@@ -1,8 +1,8 @@
- {{filterValue.label}}
-
+ {{filterValue.label}}
+
{{filterValue.count}}
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.scss b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.scss
index 7b5448b980..93d85fcba8 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../../styles/variables.scss';
-
a {
color: $link-color;
&:hover {
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
index 54d5d535df..77f240a899 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
@@ -18,6 +18,7 @@ const rangeDelimiter = '-';
@Component({
selector: 'ds-search-facet-range-option',
styleUrls: ['./search-facet-range-option.component.scss'],
+ // templateUrl: './search-facet-range-option.component.html',
templateUrl: './search-facet-range-option.component.html',
})
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.scss b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.scss
index 6452f2469b..c5a38f24a7 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../../styles/variables.scss';
-
a {
color: $body-color;
&:hover, &focus {
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
index 5d8b51de96..af5ca68de1 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts
@@ -20,6 +20,7 @@ import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-d
import { SearchConfigurationServiceStub } from '../../../../shared/testing/search-configuration-service-stub';
import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component';
import { tap } from 'rxjs/operators';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
describe('SearchFacetFilterComponent', () => {
let comp: SearchFacetFilterComponent;
@@ -61,7 +62,7 @@ describe('SearchFacetFilterComponent', () => {
let router;
const page = observableOf(0);
- const mockValues = observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values)));
+ const mockValues = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), values));
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule],
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
index 6402d07f9b..5ce76fbf2c 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
@@ -1,12 +1,12 @@
import {
- combineLatest as observableCombineLatest,
- of as observableOf,
BehaviorSubject,
+ combineLatest as observableCombineLatest,
Observable,
+ of as observableOf,
Subject,
Subscription
} from 'rxjs';
-import { switchMap, distinctUntilChanged, map, take, flatMap, tap } from 'rxjs/operators';
+import { distinctUntilChanged, map, switchMap, take, tap } from 'rxjs/operators';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@@ -137,7 +137,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig).pipe(
map((selectedValues) => {
return selectedValues.map((value: string) => {
- const fValue = [].concat(...rd.payload.map((page) => page.page)).find((facetValue: FacetValue) => facetValue.value === value);
+ const fValue = [].concat(...rd.payload.map((page) => page.page)).find((facetValue: FacetValue) => this.getFacetValue(facetValue) === value);
if (hasValue(fValue)) {
return fValue;
}
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss
index 1db5e9a1b2..c94edb01bb 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.scss
@@ -1,13 +1,10 @@
-@import '../../../../styles/variables.scss';
-@import '../../../../styles/mixins.scss';
-
:host .facet-filter {
- border: 1px solid map-get($theme-colors, light);
- cursor: pointer;
- .search-filter-wrapper.closed {
- overflow: hidden;
- }
- .filter-toggle {
- line-height: $line-height-base;
- }
+ border: 1px solid map-get($theme-colors, light);
+ cursor: pointer;
+ .search-filter-wrapper.closed {
+ overflow: hidden;
+ }
+ .filter-toggle {
+ line-height: $line-height-base;
+ }
}
diff --git a/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.spec.ts b/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.spec.ts
index 3207345564..3f6c2ef133 100644
--- a/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.spec.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.spec.ts
@@ -17,7 +17,7 @@ describe('SearchFixedFilterService', () => {
configure: () => {},
/* tslint:enable:no-empty */
generateRequestId: () => 'fake-id',
- getByUUID: () => observableOf(Object.assign(new RequestEntry(), {
+ getByHref: () => observableOf(Object.assign(new RequestEntry(), {
response: new FilteredDiscoveryQueryResponse(filterQuery, 200, 'OK')
}))
}) as RequestService;
@@ -56,5 +56,4 @@ describe('SearchFixedFilterService', () => {
expect(query).toContain(itemUUID);
});
});
-
});
diff --git a/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.ts
index 7d59e5a446..0f17b508c9 100644
--- a/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-fixed-filter.service.ts
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
-import { flatMap, map } from 'rxjs/operators';
-import { Observable , of as observableOf } from 'rxjs';
+import { flatMap, map, switchMap, tap } from 'rxjs/operators';
+import { Observable, of as observableOf } from 'rxjs';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { GetRequest, RestRequest } from '../../../core/data/request.models';
import { RequestService } from '../../../core/data/request.service';
@@ -33,7 +33,7 @@ export class SearchFixedFilterService {
getQueryByFilterName(filterName: string): Observable {
if (hasValue(filterName)) {
const requestUuid = this.requestService.generateRequestId();
- this.halService.getEndpoint(this.queryByFilterPath).pipe(
+ const requestObs = this.halService.getEndpoint(this.queryByFilterPath).pipe(
map((url: string) => {
url += ('/' + filterName);
const request = new GetRequest(requestUuid, url);
@@ -44,10 +44,12 @@ export class SearchFixedFilterService {
});
}),
configureRequest(this.requestService)
- ).subscribe();
+ );
- // get search results from response cache
- const filterQuery: Observable = this.requestService.getByUUID(requestUuid).pipe(
+ const requestEntryObs = requestObs.pipe(
+ switchMap((request: RestRequest) => this.requestService.getByHref(request.href)),
+ );
+ const filterQuery = requestEntryObs.pipe(
getResponseFromEntry(),
map((response: FilteredDiscoveryQueryResponse) =>
response.filterQuery
@@ -75,5 +77,4 @@ export class SearchFixedFilterService {
getFilterByRelation(relationType: string, itemUUID: string): string {
return `f.${relationType}=${itemUUID}`;
}
-
}
diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss
index d8bb1ff1b3..489b7bab63 100644
--- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.scss
@@ -1,6 +1,3 @@
-@import '../../../../../styles/variables.scss';
-@import '../../../../../styles/mixins.scss';
-
.filters {
.toggle-more-filters a {
color: $link-color;
diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss
index caaef5985e..9e536626b0 100644
--- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.scss
@@ -1,14 +1,10 @@
-@import '../../../../../styles/variables.scss';
-@import '../../../../../styles/mixins.scss';
-
-
.filters {
- .toggle-more-filters a {
- color: $link-color;
- text-decoration: underline;
- cursor: pointer;
- }
- }
+ .toggle-more-filters a {
+ color: $link-color;
+ text-decoration: underline;
+ cursor: pointer;
+ }
+}
$slider-handle-width: 18px;
::ng-deep
diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
index 119f3f92a9..da86e3a759 100644
--- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts
@@ -20,6 +20,7 @@ import { RouteService } from '../../../../shared/services/route.service';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationServiceStub } from '../../../../shared/testing/search-configuration-service-stub';
+import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
describe('SearchRangeFilterComponent', () => {
let comp: SearchRangeFilterComponent;
@@ -66,7 +67,7 @@ describe('SearchRangeFilterComponent', () => {
let router;
const page = observableOf(0);
- const mockValues = observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), values)));
+ const mockValues = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), values));
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule],
diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss
index d8bb1ff1b3..1d062960c7 100644
--- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss
+++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.scss
@@ -1,5 +1,3 @@
-@import '../../../../../styles/variables.scss';
-@import '../../../../../styles/mixins.scss';
.filters {
.toggle-more-filters a {
diff --git a/src/app/+search-page/search-filters/search-filters.component.scss b/src/app/+search-page/search-filters/search-filters.component.scss
index 628c8ed46f..e69de29bb2 100644
--- a/src/app/+search-page/search-filters/search-filters.component.scss
+++ b/src/app/+search-page/search-filters/search-filters.component.scss
@@ -1,2 +0,0 @@
-@import '../../../styles/variables.scss';
-@import '../../../styles/mixins.scss';
\ No newline at end of file
diff --git a/src/app/+search-page/search-page-routing.module.ts b/src/app/+search-page/search-page-routing.module.ts
index 8c138c0d52..d1ab02945e 100644
--- a/src/app/+search-page/search-page-routing.module.ts
+++ b/src/app/+search-page/search-page-routing.module.ts
@@ -2,14 +2,14 @@ import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { SearchPageComponent } from './search-page.component';
-import { FilteredSearchPageComponent } from './filtered-search-page.component';
-import { FilteredSearchPageGuard } from './filtered-search-page.guard';
+import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
+import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
@NgModule({
imports: [
RouterModule.forChild([
{ path: '', component: SearchPageComponent, data: { title: 'search.title' } },
- { path: ':filter', component: FilteredSearchPageComponent, canActivate: [FilteredSearchPageGuard], data: { title: 'search.' }}
+ { path: ':configuration', component: ConfigurationSearchPageComponent, canActivate: [ConfigurationSearchPageGuard]}
])
]
})
diff --git a/src/app/+search-page/search-page.component.html b/src/app/+search-page/search-page.component.html
index c11e863429..ea04a2b04e 100644
--- a/src/app/+search-page/search-page.component.html
+++ b/src/app/+search-page/search-page.component.html
@@ -2,7 +2,7 @@
+ [resultCount]="(resultsRD$ | async)?.payload?.totalElements" [inPlaceSearch]="inPlaceSearch">
diff --git a/src/app/+search-page/search-page.component.scss b/src/app/+search-page/search-page.component.scss
index 26011dd57e..05abf74f05 100644
--- a/src/app/+search-page/search-page.component.scss
+++ b/src/app/+search-page/search-page.component.scss
@@ -1,5 +1,3 @@
-@import '../../styles/variables.scss';
-@import '../../styles/mixins.scss';
@include media-breakpoint-down(md) {
.container {
diff --git a/src/app/+search-page/search-page.component.spec.ts b/src/app/+search-page/search-page.component.spec.ts
index 88c7c693d3..fe4c301bd5 100644
--- a/src/app/+search-page/search-page.component.spec.ts
+++ b/src/app/+search-page/search-page.component.spec.ts
@@ -25,6 +25,7 @@ import { RouteService } from '../shared/services/route.service';
import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service-stub';
import { PaginatedSearchOptions } from './paginated-search-options.model';
import { SearchFixedFilterService } from './search-filters/search-filter/search-fixed-filter.service';
+import { createSuccessfulRemoteDataObject$ } from '../shared/testing/utils';
let comp: SearchPageComponent;
let fixture: ComponentFixture;
@@ -41,7 +42,7 @@ pagination.id = 'search-results-pagination';
pagination.currentPage = 1;
pagination.pageSize = 10;
const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
-const mockResults = observableOf(new RemoteData(false, false, true, null, ['test', 'data']));
+const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
const searchServiceStub = jasmine.createSpyObj('SearchService', {
search: mockResults,
getSearchLink: '/search',
diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts
index 2b343ac584..03433d1da1 100644
--- a/src/app/+search-page/search-page.component.ts
+++ b/src/app/+search-page/search-page.component.ts
@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
-import { Observable , Subscription , BehaviorSubject } from 'rxjs';
-import { switchMap, } from 'rxjs/operators';
+import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs';
+import { startWith, switchMap, } from 'rxjs/operators';
import { PaginatedList } from '../core/data/paginated-list';
import { RemoteData } from '../core/data/remote-data';
import { DSpaceObject } from '../core/shared/dspace-object.model';
@@ -43,7 +43,6 @@ export const SEARCH_ROUTE = '/search';
* It renders search results depending on the current search options
*/
export class SearchPageComponent implements OnInit {
-
/**
* The current search results
*/
@@ -87,10 +86,10 @@ export class SearchPageComponent implements OnInit {
sideBarWidth = 3;
/**
- * The currently applied filter (determines title of search)
+ * The currently applied configuration (determines title of search)
*/
@Input()
- fixedFilter$: Observable;
+ configuration$: Observable;
constructor(protected service: SearchService,
protected sidebarService: SearchSidebarService,
@@ -110,15 +109,15 @@ export class SearchPageComponent implements OnInit {
ngOnInit(): void {
this.searchOptions$ = this.getSearchOptions();
this.sub = this.searchOptions$.pipe(
- switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData())))
+ switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData(), startWith(observableOf(undefined)))))
.subscribe((results) => {
this.resultsRD$.next(results);
});
this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe(
switchMap((scopeId) => this.service.getScopes(scopeId))
);
- if (!isNotEmpty(this.fixedFilter$)) {
- this.fixedFilter$ = this.routeService.getRouteParameterValue('filter');
+ if (!isNotEmpty(this.configuration$)) {
+ this.configuration$ = this.routeService.getRouteParameterValue('configuration');
}
}
diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts
index 65558eae17..d7d66d854c 100644
--- a/src/app/+search-page/search-page.module.ts
+++ b/src/app/+search-page/search-page.module.ts
@@ -17,9 +17,7 @@ import { SearchFiltersComponent } from './search-filters/search-filters.componen
import { SearchFilterComponent } from './search-filters/search-filter/search-filter.component';
import { SearchFacetFilterComponent } from './search-filters/search-filter/search-facet-filter/search-facet-filter.component';
import { SearchFilterService } from './search-filters/search-filter/search-filter.service';
-import { FilteredSearchPageComponent } from './filtered-search-page.component';
import { SearchFixedFilterService } from './search-filters/search-filter/search-fixed-filter.service';
-import { FilteredSearchPageGuard } from './filtered-search-page.guard';
import { SearchLabelsComponent } from './search-labels/search-labels.component';
import { SearchRangeFilterComponent } from './search-filters/search-filter/search-range-filter/search-range-filter.component';
import { SearchTextFilterComponent } from './search-filters/search-filter/search-text-filter/search-text-filter.component';
@@ -32,6 +30,9 @@ import { SearchFacetSelectedOptionComponent } from './search-filters/search-filt
import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component';
import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component';
import { SearchAuthorityFilterComponent } from './search-filters/search-filter/search-authority-filter/search-authority-filter.component';
+import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
+import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
+import { FilteredSearchPageComponent } from './filtered-search-page.component';
const effects = [
SearchSidebarEffects
@@ -60,7 +61,8 @@ const components = [
SearchFacetRangeOptionComponent,
SearchSwitchConfigurationComponent,
SearchAuthorityFilterComponent,
- FilteredSearchPageComponent
+ FilteredSearchPageComponent,
+ ConfigurationSearchPageComponent
];
@NgModule({
@@ -76,7 +78,7 @@ const components = [
SearchSidebarService,
SearchFilterService,
SearchFixedFilterService,
- FilteredSearchPageGuard,
+ ConfigurationSearchPageGuard,
SearchFilterService,
SearchConfigurationService
],
diff --git a/src/app/+search-page/search-results/search-results.component.html b/src/app/+search-page/search-results/search-results.component.html
index d7ecb0357e..5a1e89858b 100644
--- a/src/app/+search-page/search-results/search-results.component.html
+++ b/src/app/+search-page/search-results/search-results.component.html
@@ -1,4 +1,4 @@
-{{ getTitleKey() | translate }}
+{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}
0" @fadeIn>
-
+
{{ 'search.results.no-results' | translate }}
diff --git a/src/app/+search-page/search-results/search-results.component.spec.ts b/src/app/+search-page/search-results/search-results.component.spec.ts
index 518829e69f..6eb48bb037 100644
--- a/src/app/+search-page/search-results/search-results.component.spec.ts
+++ b/src/app/+search-page/search-results/search-results.component.spec.ts
@@ -114,7 +114,7 @@ export const objects = [
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
- type: ResourceType.Community,
+ type: Community.type,
metadata: {
'dc.description': [
{
@@ -168,7 +168,7 @@ export const objects = [
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
id: '9076bd16-e69a-48d6-9e41-0238cb40d863',
uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863',
- type: ResourceType.Community,
+ type: Community.type,
metadata: {
'dc.description': [
{
diff --git a/src/app/+search-page/search-results/search-results.component.ts b/src/app/+search-page/search-results/search-results.component.ts
index 9656ba9574..0ad1fd46bf 100644
--- a/src/app/+search-page/search-results/search-results.component.ts
+++ b/src/app/+search-page/search-results/search-results.component.ts
@@ -6,7 +6,7 @@ import { SetViewMode } from '../../shared/view-mode';
import { SearchOptions } from '../search-options.model';
import { SearchResult } from '../search-result.model';
import { PaginatedList } from '../../core/data/paginated-list';
-import { isNotEmpty } from '../../shared/empty.util';
+import { hasNoValue, isNotEmpty } from '../../shared/empty.util';
import { SortOptions } from '../../core/cache/models/sort-options.model';
@Component({
@@ -22,6 +22,8 @@ import { SortOptions } from '../../core/cache/models/sort-options.model';
* Component that represents all results from a search
*/
export class SearchResultsComponent {
+ hasNoValue = hasNoValue;
+
/**
* The actual search result objects
*/
@@ -43,9 +45,9 @@ export class SearchResultsComponent {
@Input() viewMode: SetViewMode;
/**
- * An optional fixed filter to filter the result on one type
+ * An optional configuration to filter the result on one type
*/
- @Input() fixedFilter: string;
+ @Input() configuration: string;
/**
* Whether or not to hide the header of the results
@@ -53,19 +55,6 @@ export class SearchResultsComponent {
*/
@Input() disableHeader = false;
- /**
- * Get the i18n key for the title depending on the fixed filter
- * Defaults to 'search.results.head' if there's no fixed filter found
- * @returns {string}
- */
- getTitleKey() {
- if (isNotEmpty(this.fixedFilter)) {
- return 'search.' + this.fixedFilter + '.results.head'
- } else {
- return 'search.results.head';
- }
- }
-
/**
* Method to change the given string by surrounding it by quotes if not already present.
*/
diff --git a/src/app/+search-page/search-service/search-configuration.service.spec.ts b/src/app/+search-page/search-service/search-configuration.service.spec.ts
index 79932805c1..fb95ab8d04 100644
--- a/src/app/+search-page/search-service/search-configuration.service.spec.ts
+++ b/src/app/+search-page/search-service/search-configuration.service.spec.ts
@@ -171,20 +171,4 @@ describe('SearchConfigurationService', () => {
expect((service as any).routeService.getRouteParameterValue).toHaveBeenCalledWith('filter');
});
});
-
- describe('when updateFixedFilter is called', () => {
- const filter = 'filter';
-
- beforeEach(() => {
- service.updateFixedFilter(filter);
- });
-
- it('should update the paginated search options with the correct fixed filter', () => {
- expect(service.paginatedSearchOptions.getValue().fixedFilter).toEqual(filter);
- });
-
- it('should update the search options with the correct fixed filter', () => {
- expect(service.searchOptions.getValue().fixedFilter).toEqual(filter);
- });
- });
});
diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts
index 39acd19ccd..06efc16be2 100644
--- a/src/app/+search-page/search-service/search-configuration.service.ts
+++ b/src/app/+search-page/search-service/search-configuration.service.ts
@@ -9,7 +9,7 @@ import {
of as observableOf,
Subscription
} from 'rxjs';
-import { filter, flatMap, map } from 'rxjs/operators';
+import { filter, flatMap, map, startWith, switchMap, tap } from 'rxjs/operators';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { SearchOptions } from '../search-options.model';
@@ -21,6 +21,7 @@ import { getSucceededRemoteData } from '../../core/shared/operators';
import { SearchFilter } from '../search-filter.model';
import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model';
import { SearchFixedFilterService } from '../search-filters/search-filter/search-fixed-filter.service';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
/**
* Service that performs all actions that have to do with the current search configuration
@@ -44,7 +45,7 @@ export class SearchConfigurationService implements OnDestroy {
/**
* Default configuration parameter setting
*/
- protected defaultConfiguration = 'default';
+ protected defaultConfiguration;
/**
* Default scope setting
@@ -99,10 +100,8 @@ export class SearchConfigurationService implements OnDestroy {
const defs = defRD.payload;
this.paginatedSearchOptions = new BehaviorSubject
(defs);
this.searchOptions = new BehaviorSubject(defs);
-
this.subs.push(this.subscribeToSearchOptions(defs));
this.subs.push(this.subscribeToPaginatedSearchOptions(defs));
-
}
)
}
@@ -111,9 +110,14 @@ export class SearchConfigurationService implements OnDestroy {
* @returns {Observable} Emits the current configuration string
*/
getCurrentConfiguration(defaultConfiguration: string) {
- return this.routeService.getQueryParameterValue('configuration').pipe(map((configuration) => {
- return configuration || defaultConfiguration;
- }));
+ return observableCombineLatest(
+ this.routeService.getQueryParameterValue('configuration').pipe(startWith(undefined)),
+ this.routeService.getRouteParameterValue('configuration').pipe(startWith(undefined))
+ ).pipe(
+ map(([queryConfig, routeConfig]) => {
+ return queryConfig || routeConfig || defaultConfiguration;
+ })
+ );
}
/**
@@ -206,7 +210,7 @@ export class SearchConfigurationService implements OnDestroy {
*/
getCurrentFixedFilter(): Observable {
return this.routeService.getRouteParameterValue('filter').pipe(
- flatMap((f) => this.fixedFilterService.getQueryByFilterName(f))
+ switchMap((f) => this.fixedFilterService.getQueryByFilterName(f))
);
}
@@ -271,7 +275,7 @@ export class SearchConfigurationService implements OnDestroy {
scope: this.defaultScope,
query: this.defaultQuery
});
- this._defaults = observableOf(new RemoteData(false, false, true, null, options));
+ this._defaults = createSuccessfulRemoteDataObject$(options);
}
return this._defaults;
}
@@ -357,21 +361,7 @@ export class SearchConfigurationService implements OnDestroy {
isNotEmptyOperator(),
map((fixedFilter) => {
return { fixedFilter }
- })
+ }),
);
}
-
- /**
- * Update the fixed filter in paginated and non-paginated search options with a given value
- * @param {string} fixedFilter
- */
- public updateFixedFilter(fixedFilter: string) {
- const currentPaginatedValue: PaginatedSearchOptions = this.paginatedSearchOptions.getValue();
- const updatedPaginatedValue: PaginatedSearchOptions = Object.assign(currentPaginatedValue, { fixedFilter: fixedFilter });
- this.paginatedSearchOptions.next(updatedPaginatedValue);
-
- const currentValue: SearchOptions = this.searchOptions.getValue();
- const updatedValue: SearchOptions = Object.assign(currentValue, { fixedFilter: fixedFilter });
- this.searchOptions.next(updatedValue);
- }
}
diff --git a/src/app/+search-page/search-service/search-result-element-decorator.ts b/src/app/+search-page/search-service/search-result-element-decorator.ts
index 59446480a3..e804a5d8ee 100644
--- a/src/app/+search-page/search-service/search-result-element-decorator.ts
+++ b/src/app/+search-page/search-service/search-result-element-decorator.ts
@@ -1,6 +1,6 @@
import { GenericConstructor } from '../../core/shared/generic-constructor';
import { ListableObject } from '../../shared/object-collection/shared/listable-object.model';
-import { isNull } from '../../shared/empty.util';
+import { hasNoValue, isNull } from '../../shared/empty.util';
/**
* Contains the mapping between a search result component and a DSpaceObject
@@ -34,7 +34,7 @@ export function searchResultFor(domainConstructor: GenericConstructor, configuration: string = null) {
- if (isNull(configuration) || configuration === 'default') {
+ if (isNull(configuration) || configuration === 'default' || hasNoValue(searchResultMap.get(configuration))) {
return searchResultMap.get(domainConstructor);
} else {
return searchResultMap.get(configuration).get(domainConstructor);
diff --git a/src/app/+search-page/search-service/search.service.spec.ts b/src/app/+search-page/search-service/search.service.spec.ts
index 9ec5bc35f2..4ae9876159 100644
--- a/src/app/+search-page/search-service/search.service.spec.ts
+++ b/src/app/+search-page/search-service/search.service.spec.ts
@@ -28,6 +28,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
import { map } from 'rxjs/operators';
import { RouteService } from '../../shared/services/route.service';
import { routeServiceStub } from '../../shared/testing/route-service-stub';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
@Component({ template: '' })
class DummyComponent {
@@ -91,7 +92,7 @@ describe('SearchService', () => {
);
},
aggregate: (input: Array>>): Observable> => {
- return observableOf(new RemoteData(false, false, true, null, []));
+ return createSuccessfulRemoteDataObject$([]);
}
};
diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts
index 598657a1b2..86611cc87b 100644
--- a/src/app/+search-page/search-service/search.service.ts
+++ b/src/app/+search-page/search-service/search.service.ts
@@ -1,6 +1,6 @@
import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs';
import { Injectable, OnDestroy } from '@angular/core';
-import { NavigationExtras, PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router';
+import { NavigationExtras, Router } from '@angular/router';
import { first, map, switchMap } from 'rxjs/operators';
import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
import {
@@ -40,7 +40,6 @@ import { PaginatedSearchOptions } from '../paginated-search-options.model';
import { Community } from '../../core/shared/community.model';
import { CommunityDataService } from '../../core/data/community-data.service';
import { ViewMode } from '../../core/shared/view-mode.model';
-import { ResourceType } from '../../core/shared/resource-type';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { RouteService } from '../../shared/services/route.service';
@@ -296,7 +295,7 @@ export class SearchService implements OnDestroy {
const scopeObject: Observable> = this.dspaceObjectService.findById(scopeId).pipe(getSucceededRemoteData());
const scopeList: Observable = scopeObject.pipe(
switchMap((dsoRD: RemoteData) => {
- if (dsoRD.payload.type === ResourceType.Community) {
+ if ((dsoRD.payload as any).type === Community.type.value) {
const community: Community = dsoRD.payload as Community;
return observableCombineLatest(community.subcommunities, community.collections).pipe(
map(([subCommunities, collections]) => {
diff --git a/src/app/+search-page/search-settings/search-settings.component.scss b/src/app/+search-page/search-settings/search-settings.component.scss
index 0a3824f815..cd18456888 100644
--- a/src/app/+search-page/search-settings/search-settings.component.scss
+++ b/src/app/+search-page/search-settings/search-settings.component.scss
@@ -1,5 +1,3 @@
-@import '../../../styles/variables.scss';
-
.setting-option {
- border: 1px solid map-get($theme-colors, light);
+ border: 1px solid map-get($theme-colors, light);
}
diff --git a/src/app/+search-page/search-sidebar/search-sidebar.component.html b/src/app/+search-page/search-sidebar/search-sidebar.component.html
index 50877052ec..7a5857fcff 100644
--- a/src/app/+search-page/search-sidebar/search-sidebar.component.html
+++ b/src/app/+search-page/search-sidebar/search-sidebar.component.html
@@ -10,7 +10,7 @@