mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge remote-tracking branch 'remotes/origin/master' into submission-miscellaneous-fixes
This commit is contained in:
35
.travis.yml
35
.travis.yml
@@ -1,5 +1,37 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
# Install the latest docker-compose version for ci testing.
|
||||
# The default installation in travis is not compatible with the latest docker-compose file version.
|
||||
COMPOSE_VERSION: 1.24.1
|
||||
# The ci step will test the dspace-angular code against DSpace REST.
|
||||
# Direct that step to utilize a DSpace REST service that has been started in docker.
|
||||
DSPACE_REST_HOST: localhost
|
||||
DSPACE_REST_PORT: 8080
|
||||
DSPACE_REST_NAMESPACE: '/server/api'
|
||||
DSPACE_REST_SSL: false
|
||||
|
||||
before_install:
|
||||
# Docker Compose Install
|
||||
- curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin
|
||||
- git clone https://github.com/DSpace-Labs/DSpace-Docker-Images.git
|
||||
|
||||
install:
|
||||
- docker-compose version
|
||||
- docker-compose -f DSpace-Docker-Images/docker-compose-files/dspace-compose/d7.travis.yml up -d
|
||||
- travis_retry yarn install
|
||||
|
||||
before_script:
|
||||
# The following line could be enabled to verify that the rest server is responding.
|
||||
# Currently, "yarn run build" takes enough time to run to allow the service to be available
|
||||
#- curl http://localhost:8080/
|
||||
|
||||
after_script:
|
||||
- docker-compose -f DSpace-Docker-Images/docker-compose-files/dspace-compose/d7.travis.yml down
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -18,9 +50,6 @@ cache:
|
||||
|
||||
bundler_args: --retry 5
|
||||
|
||||
install:
|
||||
- travis_retry yarn install
|
||||
|
||||
script:
|
||||
# Use Chromium instead of Chrome.
|
||||
- export CHROME_BIN=chromium-browser
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// This configuration is currently only being used for unit tests, end-to-end tests use environment.dev.ts
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
|
@@ -22,10 +22,10 @@
|
||||
"clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json && yarn run clean:bld",
|
||||
"clean": "yarn run clean:prod && yarn run clean:node",
|
||||
"prebuild": "yarn run clean:bld && yarn run clean:dist",
|
||||
"prebuild:aot": "yarn run prebuild",
|
||||
"prebuild:ci": "yarn run prebuild",
|
||||
"prebuild:prod": "yarn run prebuild",
|
||||
"build": "node ./scripts/webpack.js --progress --mode development",
|
||||
"build:aot": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode development && node ./scripts/webpack.js --env.aot --env.client --mode development",
|
||||
"build:ci": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode development && node ./scripts/webpack.js --env.aot --env.client --mode development",
|
||||
"build:prod": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode production && node ./scripts/webpack.js --env.aot --env.client --mode production",
|
||||
"postbuild:prod": "yarn run rollup",
|
||||
"rollup": "rollup -c rollup.config.js",
|
||||
@@ -51,10 +51,13 @@
|
||||
"debug:server": "node-nightly --inspect --debug-brk dist/server.js",
|
||||
"debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --mode development",
|
||||
"debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server --mode production",
|
||||
"ci": "yarn run lint && yarn run build:aot && yarn run test:headless",
|
||||
"ci": "yarn run lint && yarn run build:ci && yarn run test:headless && npm-run-all -p -r server e2e",
|
||||
"protractor": "node node_modules/protractor/bin/protractor",
|
||||
"pree2e": "yarn run webdriver:update",
|
||||
"e2e": "yarn run protractor",
|
||||
"pretest": "yarn run clean:bld",
|
||||
"pretest:headless": "yarn run pretest",
|
||||
"pretest:watch": "yarn run pretest",
|
||||
"test": "karma start --single-run",
|
||||
"test:headless": "karma start --single-run --browsers ChromeHeadless",
|
||||
"test:watch": "karma start --no-single-run --auto-watch",
|
||||
|
@@ -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';
|
||||
|
@@ -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,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
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';
|
||||
|
||||
|
@@ -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 { of as observableOf } from 'rxjs';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
|
@@ -8,7 +8,7 @@ import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-
|
||||
import { RoleService } from '../core/roles/role.service';
|
||||
import { SearchConfigurationOption } from '../+search-page/search-switch-configuration/search-configuration-option.model';
|
||||
import { SearchConfigurationService } from '../+search-page/search-service/search-configuration.service';
|
||||
import { RouteService } from '../shared/services/route.service';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||
import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service';
|
||||
|
@@ -17,7 +17,7 @@ import { HostWindowService } from '../shared/host-window.service';
|
||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from './my-dspace-page.component';
|
||||
import { RouteService } from '../shared/services/route.service';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { routeServiceStub } from '../shared/testing/route-service-stub';
|
||||
import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service-stub';
|
||||
import { SearchService } from '../+search-page/search-service/search.service';
|
||||
|
@@ -4,12 +4,12 @@ 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';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
|
||||
/**
|
||||
* This component renders a search page using a configuration as input.
|
||||
|
@@ -4,12 +4,12 @@ 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';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
|
||||
/**
|
||||
* This component renders a simple item page.
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<ds-input-suggestions [suggestions]="(filterSearchResults | async)"
|
||||
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
|
||||
[action]="getCurrentUrl()"
|
||||
[action]="currentUrl"
|
||||
[name]="filterConfig.paramName"
|
||||
[(ngModel)]="filter"
|
||||
(submitSuggestion)="onSubmit($event)"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<a *ngIf="isVisible | async" class="d-flex flex-row"
|
||||
[routerLink]="[getSearchLink()]"
|
||||
[routerLink]="[searchLink]"
|
||||
[queryParams]="addQueryParams" queryParamsHandling="merge">
|
||||
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
|
||||
<span class="filter-value px-1">{{filterValue.value}}</span>
|
||||
|
@@ -50,6 +50,10 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
addQueryParams;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
/**
|
||||
* Subscription to unsubscribe from on destroy
|
||||
*/
|
||||
@@ -66,6 +70,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
|
||||
* Initializes all observable instance variables and starts listening to them
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.searchLink = this.getSearchLink();
|
||||
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
|
||||
this.sub = observableCombineLatest(this.selectedValues$, this.searchConfigService.searchOptions)
|
||||
.subscribe(([selectedValues, searchOptions]) => {
|
||||
@@ -83,7 +88,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<a *ngIf="isVisible | async" class="d-flex flex-row"
|
||||
[routerLink]="[getSearchLink()]"
|
||||
[routerLink]="[searchLink]"
|
||||
[queryParams]="changeQueryParams" queryParamsHandling="merge">
|
||||
<span class="filter-value px-1">{{filterValue.label}}</span>
|
||||
<span class="float-right filter-value-count ml-auto">
|
||||
|
@@ -56,6 +56,11 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
sub: Subscription;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
constructor(protected searchService: SearchService,
|
||||
protected filterService: SearchFilterService,
|
||||
protected searchConfigService: SearchConfigurationService,
|
||||
@@ -67,6 +72,7 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
|
||||
* Initializes all observable instance variables and starts listening to them
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.searchLink = this.getSearchLink();
|
||||
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
|
||||
this.sub = this.searchConfigService.searchOptions.subscribe(() => {
|
||||
this.updateChangeParams()
|
||||
@@ -83,7 +89,7 @@ export class SearchFacetRangeOptionComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<a class="d-flex flex-row"
|
||||
[routerLink]="[getSearchLink()]"
|
||||
[routerLink]="[searchLink]"
|
||||
[queryParams]="removeQueryParams" queryParamsHandling="merge">
|
||||
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
|
||||
<span class="filter-value pl-1 text-capitalize">{{selectedValue.label}}</span>
|
||||
|
@@ -49,6 +49,11 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
sub: Subscription;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
constructor(protected searchService: SearchService,
|
||||
protected filterService: SearchFilterService,
|
||||
protected searchConfigService: SearchConfigurationService,
|
||||
@@ -64,12 +69,13 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy {
|
||||
.subscribe(([selectedValues, searchOptions]) => {
|
||||
this.updateRemoveParams(selectedValues)
|
||||
});
|
||||
this.searchLink = this.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
|
@@ -80,6 +80,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
searchOptions$: Observable<SearchOptions>;
|
||||
|
||||
/**
|
||||
* The current URL
|
||||
*/
|
||||
currentUrl: string;
|
||||
|
||||
constructor(protected searchService: SearchService,
|
||||
protected filterService: SearchFilterService,
|
||||
protected rdbs: RemoteDataBuildService,
|
||||
@@ -93,6 +98,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
||||
* Initializes all observable instance variables and starts listening to them
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.currentUrl = this.router.url;
|
||||
this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined));
|
||||
this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged());
|
||||
|
||||
@@ -215,13 +221,6 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
||||
return this.filterService.getPage(this.filterConfig.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} the current URL
|
||||
*/
|
||||
getCurrentUrl() {
|
||||
return this.router.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a new active custom value to the filter from the input field
|
||||
* @param data The string from the input field
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
import { mergeMap, map, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { distinctUntilChanged, map, mergeMap } from 'rxjs/operators';
|
||||
import { Injectable, InjectionToken } from '@angular/core';
|
||||
import { SearchFiltersState, SearchFilterState } from './search-filter.reducer';
|
||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
@@ -14,16 +14,12 @@ import {
|
||||
} from './search-filter.actions';
|
||||
import { hasValue, isNotEmpty, } from '../../../shared/empty.util';
|
||||
import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
|
||||
import { RouteService } from '../../../shared/services/route.service';
|
||||
import { RouteService } from '../../../core/services/route.service';
|
||||
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';
|
||||
import { PaginatedSearchOptions } from '../../paginated-search-options.model';
|
||||
import { SearchFixedFilterService } from './search-fixed-filter.service';
|
||||
import { Params } from '@angular/router';
|
||||
import * as postcss from 'postcss';
|
||||
import prefix = postcss.vendor.prefix;
|
||||
// const spy = create();
|
||||
|
||||
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
|
||||
|
||||
export const FILTER_CONFIG: InjectionToken<SearchFilterConfig> = new InjectionToken<SearchFilterConfig>('filterConfig');
|
||||
|
@@ -1,20 +1,19 @@
|
||||
import { SearchFixedFilterService } from './search-fixed-filter.service';
|
||||
import { RouteService } from '../../../shared/services/route.service';
|
||||
import { RequestService } from '../../../core/data/request.service';
|
||||
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RequestEntry } from '../../../core/data/request.reducer';
|
||||
import { FilteredDiscoveryQueryResponse, RestResponse } from '../../../core/cache/response.models';
|
||||
import { FilteredDiscoveryQueryResponse } from '../../../core/cache/response.models';
|
||||
|
||||
describe('SearchFixedFilterService', () => {
|
||||
let service: SearchFixedFilterService;
|
||||
|
||||
const filterQuery = 'filter:query';
|
||||
|
||||
const routeServiceStub = {} as RouteService;
|
||||
const requestServiceStub = Object.assign({
|
||||
/* tslint:disable:no-empty */
|
||||
configure: () => {},
|
||||
configure: () => {
|
||||
},
|
||||
/* tslint:enable:no-empty */
|
||||
generateRequestId: () => 'fake-id',
|
||||
getByHref: () => observableOf(Object.assign(new RequestEntry(), {
|
||||
@@ -26,7 +25,7 @@ describe('SearchFixedFilterService', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
service = new SearchFixedFilterService(routeServiceStub, requestServiceStub, halServiceStub);
|
||||
service = new SearchFixedFilterService(requestServiceStub, halServiceStub);
|
||||
});
|
||||
|
||||
describe('when getQueryByFilterName is called with a filterName', () => {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { flatMap, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { map, switchMap } 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';
|
||||
@@ -9,7 +9,6 @@ import { GenericConstructor } from '../../../core/shared/generic-constructor';
|
||||
import { FilteredDiscoveryPageResponseParsingService } from '../../../core/data/filtered-discovery-page-response-parsing.service';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { configureRequest, getResponseFromEntry } from '../../../core/shared/operators';
|
||||
import { RouteService } from '../../../shared/services/route.service';
|
||||
import { FilteredDiscoveryQueryResponse } from '../../../core/cache/response.models';
|
||||
|
||||
/**
|
||||
@@ -19,8 +18,7 @@ import { FilteredDiscoveryQueryResponse } from '../../../core/cache/response.mod
|
||||
export class SearchFixedFilterService {
|
||||
private queryByFilterPath = 'filtered-discovery-pages';
|
||||
|
||||
constructor(private routeService: RouteService,
|
||||
protected requestService: RequestService,
|
||||
constructor(protected requestService: RequestService,
|
||||
private halService: HALEndpointService) {
|
||||
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<ds-input-suggestions [suggestions]="(filterSearchResults | async)"
|
||||
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
|
||||
[action]="getCurrentUrl()"
|
||||
[action]="currentUrl"
|
||||
[name]="filterConfig.paramName"
|
||||
[(ngModel)]="filter"
|
||||
(submitSuggestion)="onSubmit($event)"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<div>
|
||||
<div class="filters py-2">
|
||||
<form #form="ngForm" (ngSubmit)="onSubmit()" class="add-filter row"
|
||||
[action]="getCurrentUrl()">
|
||||
[action]="currentUrl">
|
||||
<div class="col-6">
|
||||
<input type="text" [(ngModel)]="range[0]" [name]="filterConfig.paramName + '.min'"
|
||||
class="form-control" (blur)="onSubmit()"
|
||||
|
@@ -16,7 +16,7 @@ import { RouterStub } from '../../../../shared/testing/router-stub';
|
||||
import { Router } from '@angular/router';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
import { SearchRangeFilterComponent } from './search-range-filter.component';
|
||||
import { RouteService } from '../../../../shared/services/route.service';
|
||||
import { RouteService } from '../../../../core/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';
|
||||
|
@@ -14,7 +14,7 @@ import { FILTER_CONFIG, IN_PLACE_SEARCH, SearchFilterService } from '../search-f
|
||||
import { SearchService } from '../../../search-service/search.service';
|
||||
import { Router } from '@angular/router';
|
||||
import * as moment from 'moment';
|
||||
import { RouteService } from '../../../../shared/services/route.service';
|
||||
import { RouteService } from '../../../../core/services/route.service';
|
||||
import { hasValue } from '../../../../shared/empty.util';
|
||||
import { SearchConfigurationService } from '../../../search-service/search-configuration.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component';
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<ds-input-suggestions [suggestions]="(filterSearchResults | async)"
|
||||
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
|
||||
[action]="getCurrentUrl()"
|
||||
[action]="currentUrl"
|
||||
[name]="filterConfig.paramName"
|
||||
[(ngModel)]="filter"
|
||||
(submitSuggestion)="onSubmit($event)"
|
||||
|
@@ -4,4 +4,4 @@
|
||||
<ds-search-filter [filter]="filter" [inPlaceSearch]="inPlaceSearch"></ds-search-filter>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-primary" [routerLink]="[getSearchLink()]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a>
|
||||
<a class="btn btn-primary" [routerLink]="[searchLink]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a>
|
||||
|
@@ -58,7 +58,7 @@ describe('SearchFiltersComponent', () => {
|
||||
describe('when the getSearchLink method is called', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(searchService, 'getSearchLink');
|
||||
comp.getSearchLink();
|
||||
(comp as any).getSearchLink();
|
||||
});
|
||||
|
||||
it('should call getSearchLink on the searchService', () => {
|
||||
|
@@ -37,6 +37,11 @@ export class SearchFiltersComponent implements OnInit {
|
||||
*/
|
||||
@Input() inPlaceSearch;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
* @param {SearchService} searchService
|
||||
@@ -60,12 +65,13 @@ export class SearchFiltersComponent implements OnInit {
|
||||
Object.keys(filters).forEach((f) => filters[f] = null);
|
||||
return filters;
|
||||
}));
|
||||
this.searchLink = this.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<a class="badge badge-primary mr-1 mb-1 text-capitalize"
|
||||
[routerLink]="searchLink"
|
||||
[queryParams]="(removeParameters | async)" queryParamsHandling="merge">
|
||||
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(value)}}
|
||||
<span> ×</span>
|
||||
</a>
|
@@ -0,0 +1,87 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Params } from '@angular/router';
|
||||
import { SearchLabelComponent } from './search-label.component';
|
||||
import { ObjectKeysPipe } from '../../../shared/utils/object-keys-pipe';
|
||||
import { SearchService } from '../../search-service/search.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component';
|
||||
import { SearchServiceStub } from '../../../shared/testing/search-service-stub';
|
||||
import { SearchConfigurationServiceStub } from '../../../shared/testing/search-configuration-service-stub';
|
||||
|
||||
describe('SearchLabelComponent', () => {
|
||||
let comp: SearchLabelComponent;
|
||||
let fixture: ComponentFixture<SearchLabelComponent>;
|
||||
|
||||
const searchLink = '/search';
|
||||
let searchService;
|
||||
|
||||
const key1 = 'author';
|
||||
const key2 = 'subject';
|
||||
const value1 = 'Test, Author';
|
||||
const normValue1 = 'Test, Author';
|
||||
const value2 = 'TestSubject';
|
||||
const value3 = 'Test, Authority,authority';
|
||||
const normValue3 = 'Test, Authority';
|
||||
const filter1 = [key1, value1];
|
||||
const filter2 = [key2, value2];
|
||||
const mockFilters = [
|
||||
filter1,
|
||||
filter2
|
||||
];
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), NoopAnimationsModule, FormsModule],
|
||||
declarations: [SearchLabelComponent, ObjectKeysPipe],
|
||||
providers: [
|
||||
{ provide: SearchService, useValue: new SearchServiceStub(searchLink) },
|
||||
{ provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }
|
||||
// { provide: SearchConfigurationService, useValue: {getCurrentFrontendFilters : () => observableOf({})} }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(SearchLabelComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchLabelComponent);
|
||||
comp = fixture.componentInstance;
|
||||
searchService = (comp as any).searchService;
|
||||
comp.key = key1;
|
||||
comp.value = value1;
|
||||
(comp as any).appliedFilters = observableOf(mockFilters);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('when getRemoveParams is called', () => {
|
||||
let obs: Observable<Params>;
|
||||
|
||||
beforeEach(() => {
|
||||
obs = comp.getRemoveParams();
|
||||
});
|
||||
|
||||
it('should return all params but the provided filter', () => {
|
||||
obs.subscribe((params) => {
|
||||
// Should contain only filter2 and page: length == 2
|
||||
expect(Object.keys(params).length).toBe(2);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('when normalizeFilterValue is called', () => {
|
||||
it('should return properly filter value', () => {
|
||||
let result: string;
|
||||
|
||||
result = comp.normalizeFilterValue(value1);
|
||||
expect(result).toBe(normValue1);
|
||||
|
||||
result = comp.normalizeFilterValue(value3);
|
||||
expect(result).toBe(normValue3);
|
||||
})
|
||||
});
|
||||
});
|
@@ -0,0 +1,75 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Params } from '@angular/router';
|
||||
import { SearchService } from '../../search-service/search.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-label',
|
||||
templateUrl: './search-label.component.html',
|
||||
})
|
||||
|
||||
/**
|
||||
* Component that represents the label containing the currently active filters
|
||||
*/
|
||||
export class SearchLabelComponent implements OnInit {
|
||||
@Input() key: string;
|
||||
@Input() value: string;
|
||||
@Input() inPlaceSearch: boolean;
|
||||
@Input() appliedFilters: Observable<Params>;
|
||||
searchLink: string;
|
||||
removeParameters: Observable<Params>;
|
||||
|
||||
/**
|
||||
* Initialize the instance variable
|
||||
*/
|
||||
constructor(
|
||||
private searchService: SearchService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.searchLink = this.getSearchLink();
|
||||
this.removeParameters = this.getRemoveParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the parameters that should change if a given value for the given filter would be removed from the active filters
|
||||
* @returns {Observable<Params>} The changed filter parameters
|
||||
*/
|
||||
getRemoveParams(): Observable<Params> {
|
||||
return this.appliedFilters.pipe(
|
||||
map((filters) => {
|
||||
const field: string = Object.keys(filters).find((f) => f === this.key);
|
||||
const newValues = hasValue(filters[field]) ? filters[field].filter((v) => v !== this.value) : null;
|
||||
return {
|
||||
[field]: isNotEmpty(newValues) ? newValues : null,
|
||||
page: 1
|
||||
};
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
return this.searchService.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved
|
||||
* Strips authority operator from filter value
|
||||
* e.g. 'test ,authority' => 'test'
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
normalizeFilterValue(value: string) {
|
||||
// const pattern = /,[^,]*$/g;
|
||||
const pattern = /,authority*$/g;
|
||||
return value.replace(pattern, '');
|
||||
}
|
||||
}
|
@@ -1,13 +1,7 @@
|
||||
<div class="row mb-3 mb-md-1">
|
||||
<div class="labels col-sm-9 offset-sm-3">
|
||||
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)"><!--Do not remove this to prevent uneven spacing
|
||||
--><a *ngFor="let values of (appliedFilters | async)[key]"
|
||||
class="badge badge-primary mr-1 mb-1 text-capitalize"
|
||||
[routerLink]="getSearchLink()"
|
||||
[queryParams]="(getRemoveParams(key, values) | async)" queryParamsHandling="merge">
|
||||
{{('search.filters.applied.' + key) | translate}}: {{normalizeFilterValue(values)}}
|
||||
<span> ×</span>
|
||||
</a><!--Do not remove this to prevent uneven spacing
|
||||
--></ng-container>
|
||||
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)">
|
||||
<ds-search-label *ngFor="let value of (appliedFilters | async)[key]" [inPlaceSearch]="inPlaceSearch" [key]="key" [value]="value" [appliedFilters]="appliedFilters"></ds-search-label>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -6,11 +6,9 @@ import { SearchService } from '../search-service/search.service';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { SearchServiceStub } from '../../shared/testing/search-service-stub';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Params } from '@angular/router';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ObjectKeysPipe } from '../../shared/utils/object-keys-pipe';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component';
|
||||
import { SearchConfigurationServiceStub } from '../../shared/testing/search-configuration-service-stub';
|
||||
|
||||
describe('SearchLabelsComponent', () => {
|
||||
let comp: SearchLabelsComponent;
|
||||
@@ -22,10 +20,7 @@ describe('SearchLabelsComponent', () => {
|
||||
const field1 = 'author';
|
||||
const field2 = 'subject';
|
||||
const value1 = 'Test, Author';
|
||||
const normValue1 = 'Test, Author';
|
||||
const value2 = 'TestSubject';
|
||||
const value3 = 'Test, Authority,authority';
|
||||
const normValue3 = 'Test, Authority';
|
||||
const filter1 = [field1, value1];
|
||||
const filter2 = [field2, value2];
|
||||
const mockFilters = [
|
||||
@@ -39,8 +34,7 @@ describe('SearchLabelsComponent', () => {
|
||||
declarations: [SearchLabelsComponent, ObjectKeysPipe],
|
||||
providers: [
|
||||
{ provide: SearchService, useValue: new SearchServiceStub(searchLink) },
|
||||
{ provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }
|
||||
// { provide: SearchConfigurationService, useValue: {getCurrentFrontendFilters : () => observableOf({})} }
|
||||
{ provide: SEARCH_CONFIG_SERVICE, useValue: { getCurrentFrontendFilters: () => observableOf(mockFilters) } }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(SearchLabelsComponent, {
|
||||
@@ -56,30 +50,11 @@ describe('SearchLabelsComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('when getRemoveParams is called', () => {
|
||||
let obs: Observable<Params>;
|
||||
|
||||
beforeEach(() => {
|
||||
obs = comp.getRemoveParams(filter1[0], filter1[1]);
|
||||
});
|
||||
|
||||
describe('when the component has been initialized', () => {
|
||||
it('should return all params but the provided filter', () => {
|
||||
obs.subscribe((params) => {
|
||||
// Should contain only filter2 and page: length == 2
|
||||
expect(Object.keys(params).length).toBe(2);
|
||||
comp.appliedFilters.subscribe((filters) => {
|
||||
expect(filters).toBe(mockFilters);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('when normalizeFilterValue is called', () => {
|
||||
it('should return properly filter value', () => {
|
||||
let result: string;
|
||||
|
||||
result = comp.normalizeFilterValue(value1);
|
||||
expect(result).toBe(normValue1);
|
||||
|
||||
result = comp.normalizeFilterValue(value3);
|
||||
expect(result).toBe(normValue3);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Inject, Input } from '@angular/core';
|
||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { SearchService } from '../search-service/search.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Params } from '@angular/router';
|
||||
@@ -31,50 +31,7 @@ export class SearchLabelsComponent {
|
||||
* Initialize the instance variable
|
||||
*/
|
||||
constructor(
|
||||
private searchService: SearchService,
|
||||
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {
|
||||
this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the parameters that should change if a given value for the given filter would be removed from the active filters
|
||||
* @param {string} filterField The filter field parameter name from which the value should be removed
|
||||
* @param {string} filterValue The value that is removed for this given filter field
|
||||
* @returns {Observable<Params>} The changed filter parameters
|
||||
*/
|
||||
getRemoveParams(filterField: string, filterValue: string): Observable<Params> {
|
||||
return this.appliedFilters.pipe(
|
||||
map((filters) => {
|
||||
const field: string = Object.keys(filters).find((f) => f === filterField);
|
||||
const newValues = hasValue(filters[field]) ? filters[field].filter((v) => v !== filterValue) : null;
|
||||
return {
|
||||
[field]: isNotEmpty(newValues) ? newValues : null,
|
||||
page: 1
|
||||
};
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
return this.searchService.getSearchLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved
|
||||
* Strips authority operator from filter value
|
||||
* e.g. 'test ,authority' => 'test'
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
normalizeFilterValue(value: string) {
|
||||
// const pattern = /,[^,]*$/g;
|
||||
const pattern = /,authority*$/g;
|
||||
return value.replace(pattern, '');
|
||||
}
|
||||
}
|
||||
|
@@ -13,4 +13,5 @@ import { ConfigurationSearchPageComponent } from './configuration-search-page.co
|
||||
])
|
||||
]
|
||||
})
|
||||
export class SearchPageRoutingModule { }
|
||||
export class SearchPageRoutingModule {
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<ds-search-form *ngIf="searchEnabled" id="search-form"
|
||||
[query]="(searchOptions$ | async)?.query"
|
||||
[scope]="(searchOptions$ | async)?.scope"
|
||||
[currentUrl]="getSearchLink()"
|
||||
[currentUrl]="searchLink"
|
||||
[scopes]="(scopeListRD$ | async)"
|
||||
[inPlaceSearch]="inPlaceSearch">
|
||||
</ds-search-form>
|
||||
@@ -15,12 +15,12 @@
|
||||
<div class="row">
|
||||
<div id="search-body"
|
||||
class="row-offcanvas row-offcanvas-left"
|
||||
[@pushInOut]="(isSidebarCollapsed() | async) ? 'collapsed' : 'expanded'">
|
||||
[@pushInOut]="(isSidebarCollapsed$ | async) ? 'collapsed' : 'expanded'">
|
||||
<ds-search-sidebar *ngIf="(isXsOrSm$ | async)" class="col-12"
|
||||
id="search-sidebar-sm"
|
||||
[resultCount]="(resultsRD$ | async)?.payload.totalElements"
|
||||
(toggleSidebar)="closeSidebar()"
|
||||
[ngClass]="{'active': !(isSidebarCollapsed() | async)}">
|
||||
[ngClass]="{'active': !(isSidebarCollapsed$ | async)}">
|
||||
</ds-search-sidebar>
|
||||
<div id="search-content" class="col-12">
|
||||
<div class="d-block d-md-none search-controls clearfix">
|
||||
|
@@ -21,7 +21,7 @@ import { SearchFilterService } from './search-filters/search-filter/search-filte
|
||||
import { SearchConfigurationService } from './search-service/search-configuration.service';
|
||||
import { RemoteData } from '../core/data/remote-data';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
|
||||
import { RouteService } from '../shared/services/route.service';
|
||||
import { RouteService } from '../core/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';
|
||||
@@ -201,7 +201,7 @@ describe('SearchPageComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement;
|
||||
comp.isSidebarCollapsed = () => observableOf(true);
|
||||
(comp as any).isSidebarCollapsed$ = observableOf(true);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('SearchPageComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#search-sidebar-sm')).nativeElement;
|
||||
comp.isSidebarCollapsed = () => observableOf(false);
|
||||
(comp as any).isSidebarCollapsed$ = observableOf(false);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@@ -13,7 +13,7 @@ import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
|
||||
import { hasValue, isNotEmpty } from '../shared/empty.util';
|
||||
import { SearchConfigurationService } from './search-service/search-configuration.service';
|
||||
import { getSucceededRemoteData } from '../core/shared/operators';
|
||||
import { RouteService } from '../shared/services/route.service';
|
||||
import { RouteService } from '../core/services/route.service';
|
||||
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
|
||||
|
||||
export const SEARCH_ROUTE = '/search';
|
||||
@@ -91,6 +91,16 @@ export class SearchPageComponent implements OnInit {
|
||||
@Input()
|
||||
configuration$: Observable<string>;
|
||||
|
||||
/**
|
||||
* Link to the search page
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
/**
|
||||
* Observable for whether or not the sidebar is currently collapsed
|
||||
*/
|
||||
isSidebarCollapsed$: Observable<boolean>;
|
||||
|
||||
constructor(protected service: SearchService,
|
||||
protected sidebarService: SearchSidebarService,
|
||||
protected windowService: HostWindowService,
|
||||
@@ -107,6 +117,8 @@ export class SearchPageComponent implements OnInit {
|
||||
* If something changes, update the list of scopes for the dropdown
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.isSidebarCollapsed$ = this.isSidebarCollapsed();
|
||||
this.searchLink = this.getSearchLink();
|
||||
this.searchOptions$ = this.getSearchOptions();
|
||||
this.sub = this.searchOptions$.pipe(
|
||||
switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData(), startWith(undefined))))
|
||||
@@ -147,14 +159,14 @@ export class SearchPageComponent implements OnInit {
|
||||
* Check if the sidebar is collapsed
|
||||
* @returns {Observable<boolean>} emits true if the sidebar is currently collapsed, false if it is expanded
|
||||
*/
|
||||
public isSidebarCollapsed(): Observable<boolean> {
|
||||
private isSidebarCollapsed(): Observable<boolean> {
|
||||
return this.sidebarService.isCollapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||
*/
|
||||
public getSearchLink(): string {
|
||||
private getSearchLink(): string {
|
||||
if (this.inPlaceSearch) {
|
||||
return './';
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ 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 { SearchLabelComponent } from './search-labels/search-label/search-label.component';
|
||||
import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
|
||||
import { ConfigurationSearchPageGuard } from './configuration-search-page.guard';
|
||||
import { FilteredSearchPageComponent } from './filtered-search-page.component';
|
||||
@@ -50,6 +51,7 @@ const components = [
|
||||
SearchFilterComponent,
|
||||
SearchFacetFilterComponent,
|
||||
SearchLabelsComponent,
|
||||
SearchLabelComponent,
|
||||
SearchFacetFilterComponent,
|
||||
SearchFacetFilterWrapperComponent,
|
||||
SearchRangeFilterComponent,
|
||||
|
@@ -14,7 +14,7 @@ import { SortDirection, SortOptions } from '../../core/cache/models/sort-options
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { SearchOptions } from '../search-options.model';
|
||||
import { PaginatedSearchOptions } from '../paginated-search-options.model';
|
||||
import { RouteService } from '../../shared/services/route.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { hasNoValue, hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { getSucceededRemoteData } from '../../core/shared/operators';
|
||||
|
@@ -26,7 +26,7 @@ import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { RouteService } from '../../shared/services/route.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
import { routeServiceStub } from '../../shared/testing/route-service-stub';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
|
||||
|
||||
|
@@ -41,7 +41,7 @@ import { Community } from '../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { RouteService } from '../../shared/services/route.service';
|
||||
import { RouteService } from '../../core/services/route.service';
|
||||
|
||||
/**
|
||||
* Service that performs all general actions that have to do with the search page
|
||||
|
@@ -26,7 +26,7 @@ import { HostWindowResizeAction } from './shared/host-window.actions';
|
||||
import { MetadataService } from './core/metadata/metadata.service';
|
||||
|
||||
import { GLOBAL_CONFIG, ENV_CONFIG } from '../config';
|
||||
import { NativeWindowRef, NativeWindowService } from './shared/services/window.service';
|
||||
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
||||
|
||||
import { MockTranslateLoader } from './shared/mocks/mock-translate-loader';
|
||||
import { MockMetadataService } from './shared/mocks/mock-metadata-service';
|
||||
@@ -41,9 +41,11 @@ import { MenuServiceStub } from './shared/testing/menu-service-stub';
|
||||
import { HostWindowService } from './shared/host-window.service';
|
||||
import { HostWindowServiceStub } from './shared/testing/host-window-service-stub';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouteService } from './shared/services/route.service';
|
||||
import { RouteService } from './core/services/route.service';
|
||||
import { MockActivatedRoute } from './shared/mocks/mock-active-router';
|
||||
import { MockRouter } from './shared/mocks/mock-router';
|
||||
import { MockCookieService } from './shared/mocks/mock-cookie.service';
|
||||
import { CookieService } from './core/services/cookie.service';
|
||||
|
||||
let comp: AppComponent;
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
@@ -78,6 +80,7 @@ describe('App component', () => {
|
||||
{ provide: MenuService, useValue: menuService },
|
||||
{ provide: CSSVariableService, useClass: CSSVariableServiceStub },
|
||||
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
|
||||
{ provide: CookieService, useValue: new MockCookieService()},
|
||||
AppComponent,
|
||||
RouteService
|
||||
],
|
||||
|
@@ -19,11 +19,11 @@ import { GLOBAL_CONFIG, GlobalConfig } from '../config';
|
||||
import { MetadataService } from './core/metadata/metadata.service';
|
||||
import { HostWindowResizeAction } from './shared/host-window.actions';
|
||||
import { HostWindowState } from './shared/host-window.reducer';
|
||||
import { NativeWindowRef, NativeWindowService } from './shared/services/window.service';
|
||||
import { NativeWindowRef, NativeWindowService } from './core/services/window.service';
|
||||
import { isAuthenticated } from './core/auth/selectors';
|
||||
import { AuthService } from './core/auth/auth.service';
|
||||
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
|
||||
import { RouteService } from './shared/services/route.service';
|
||||
import { RouteService } from './core/services/route.service';
|
||||
import variables from '../styles/_exposed_variables.scss';
|
||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
||||
import { MenuService } from './shared/menu/menu.service';
|
||||
@@ -32,6 +32,10 @@ import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs';
|
||||
import { slideSidebarPadding } from './shared/animations/slide';
|
||||
import { HostWindowService } from './shared/host-window.service';
|
||||
import { Theme } from '../config/theme.inferface';
|
||||
import { isNotEmpty } from './shared/empty.util';
|
||||
import { CookieService } from './core/services/cookie.service';
|
||||
|
||||
export const LANG_COOKIE = 'language_cookie';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-app',
|
||||
@@ -61,6 +65,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||
private cssService: CSSVariableService,
|
||||
private menuService: MenuService,
|
||||
private windowService: HostWindowService,
|
||||
private cookie: CookieService
|
||||
) {
|
||||
// Load all the languages that are defined as active from the config file
|
||||
translate.addLangs(config.languages.filter((LangConfig) => LangConfig.active === true).map((a) => a.code));
|
||||
@@ -68,11 +73,20 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||
// Load the default language from the config file
|
||||
translate.setDefaultLang(config.defaultLanguage);
|
||||
|
||||
// Attempt to get the browser language from the user
|
||||
if (translate.getLangs().includes(translate.getBrowserLang())) {
|
||||
translate.use(translate.getBrowserLang());
|
||||
// Attempt to get the language from a cookie
|
||||
const lang = cookie.get(LANG_COOKIE);
|
||||
if (isNotEmpty(lang)) {
|
||||
// Cookie found
|
||||
// Use the language from the cookie
|
||||
translate.use(lang);
|
||||
} else {
|
||||
translate.use(config.defaultLanguage);
|
||||
// Cookie not found
|
||||
// Attempt to get the browser language from the user
|
||||
if (translate.getLangs().includes(translate.getBrowserLang())) {
|
||||
translate.use(translate.getBrowserLang());
|
||||
} else {
|
||||
translate.use(config.defaultLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
metadata.listenForRouteChange();
|
||||
|
@@ -39,6 +39,7 @@ import { ExpandableAdminSidebarSectionComponent } from './+admin/admin-sidebar/e
|
||||
import { NavbarModule } from './navbar/navbar.module';
|
||||
import { JournalEntitiesModule } from './entity-groups/journal-entities/journal-entities.module';
|
||||
import { ResearchEntitiesModule } from './entity-groups/research-entities/research-entities.module';
|
||||
import { ClientCookieService } from './core/services/client-cookie.service';
|
||||
|
||||
export function getConfig() {
|
||||
return ENV_CONFIG;
|
||||
@@ -97,7 +98,8 @@ const PROVIDERS = [
|
||||
{
|
||||
provide: RouterStateSerializer,
|
||||
useClass: DSpaceRouterStateSerializer
|
||||
}
|
||||
},
|
||||
ClientCookieService
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
@@ -7,12 +7,12 @@ import { REQUEST } from '@nguniversal/express-engine/tokens';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { authReducer, AuthState } from './auth.reducer';
|
||||
import { NativeWindowRef, NativeWindowService } from '../../shared/services/window.service';
|
||||
import { NativeWindowRef, NativeWindowService } from '../services/window.service';
|
||||
import { AuthService } from './auth.service';
|
||||
import { RouterStub } from '../../shared/testing/router-stub';
|
||||
import { ActivatedRouteStub } from '../../shared/testing/active-router-stub';
|
||||
|
||||
import { CookieService } from '../../shared/services/cookie.service';
|
||||
import { CookieService } from '../services/cookie.service';
|
||||
import { AuthRequestServiceStub } from '../../shared/testing/auth-request-service-stub';
|
||||
import { AuthRequestService } from './auth-request.service';
|
||||
import { AuthStatus } from './models/auth-status.model';
|
||||
@@ -20,7 +20,7 @@ import { AuthTokenInfo } from './models/auth-token-info.model';
|
||||
import { EPerson } from '../eperson/models/eperson.model';
|
||||
import { EPersonMock } from '../../shared/testing/eperson-mock';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { ClientCookieService } from '../../shared/services/client-cookie.service';
|
||||
import { ClientCookieService } from '../services/client-cookie.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service';
|
||||
|
||||
|
@@ -15,11 +15,11 @@ import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||
import { AuthStatus } from './models/auth-status.model';
|
||||
import { AuthTokenInfo, TOKENITEM } from './models/auth-token-info.model';
|
||||
import { isEmpty, isNotEmpty, isNotNull, isNotUndefined } from '../../shared/empty.util';
|
||||
import { CookieService } from '../../shared/services/cookie.service';
|
||||
import { CookieService } from '../services/cookie.service';
|
||||
import { getAuthenticationToken, getRedirectUrl, isAuthenticated, isTokenRefreshing } from './selectors';
|
||||
import { AppState, routerStateSelector } from '../../app.reducer';
|
||||
import { ResetAuthenticationMessagesAction, SetRedirectUrlAction } from './auth.actions';
|
||||
import { NativeWindowRef, NativeWindowService } from '../../shared/services/window.service';
|
||||
import { NativeWindowRef, NativeWindowService } from '../services/window.service';
|
||||
import { Base64EncodeUrl } from '../../shared/utils/encode-decode.util';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import { AuthEffects } from './auth/auth.effects';
|
||||
import { JsonPatchOperationsEffects } from './json-patch/json-patch-operations.effects';
|
||||
import { ServerSyncBufferEffects } from './cache/server-sync-buffer.effects';
|
||||
import { ObjectUpdatesEffects } from './data/object-updates/object-updates.effects';
|
||||
import { RouteEffects } from '../shared/services/route.effects';
|
||||
import { RouteEffects } from './services/route.effects';
|
||||
|
||||
export const coreEffects = [
|
||||
RequestEffects,
|
||||
|
@@ -14,7 +14,7 @@ import { coreReducers } from './core.reducers';
|
||||
|
||||
import { isNotEmpty } from '../shared/empty.util';
|
||||
|
||||
import { ApiService } from '../shared/services/api.service';
|
||||
import { ApiService } from './services/api.service';
|
||||
import { BrowseEntriesResponseParsingService } from './data/browse-entries-response-parsing.service';
|
||||
import { CollectionDataService } from './data/collection-data.service';
|
||||
import { CommunityDataService } from './data/community-data.service';
|
||||
@@ -34,12 +34,12 @@ import { PaginationComponentOptions } from '../shared/pagination/pagination-comp
|
||||
import { RemoteDataBuildService } from './cache/builders/remote-data-build.service';
|
||||
import { RequestService } from './data/request.service';
|
||||
import { EndpointMapResponseParsingService } from './data/endpoint-map-response-parsing.service';
|
||||
import { ServerResponseService } from '../shared/services/server-response.service';
|
||||
import { NativeWindowFactory, NativeWindowService } from '../shared/services/window.service';
|
||||
import { ServerResponseService } from './services/server-response.service';
|
||||
import { NativeWindowFactory, NativeWindowService } from './services/window.service';
|
||||
import { BrowseService } from './browse/browse.service';
|
||||
import { BrowseResponseParsingService } from './data/browse-response-parsing.service';
|
||||
import { ConfigResponseParsingService } from './config/config-response-parsing.service';
|
||||
import { RouteService } from '../shared/services/route.service';
|
||||
import { RouteService } from './services/route.service';
|
||||
import { SubmissionDefinitionsConfigService } from './config/submission-definitions-config.service';
|
||||
import { SubmissionFormsConfigService } from './config/submission-forms-config.service';
|
||||
import { SubmissionSectionsConfigService } from './config/submission-sections-config.service';
|
||||
|
@@ -13,7 +13,7 @@ import {
|
||||
objectUpdatesReducer,
|
||||
ObjectUpdatesState
|
||||
} from './data/object-updates/object-updates.reducer';
|
||||
import { routeReducer, RouteState } from '../shared/services/route.reducer';
|
||||
import { routeReducer, RouteState } from './services/route.reducer';
|
||||
|
||||
export interface CoreState {
|
||||
'cache/object': ObjectCacheState,
|
||||
|
@@ -6,9 +6,9 @@ import { Store } from '@ngrx/store';
|
||||
import { getTestScheduler, hot } from 'jasmine-marbles';
|
||||
|
||||
import { RouteService } from './route.service';
|
||||
import { MockRouter } from '../mocks/mock-router';
|
||||
import { MockRouter } from '../../shared/mocks/mock-router';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { AddUrlToHistoryAction } from '../history/history.actions';
|
||||
import { AddUrlToHistoryAction } from '../../shared/history/history.actions';
|
||||
|
||||
describe('RouteService', () => {
|
||||
let scheduler: TestScheduler;
|
@@ -12,12 +12,12 @@ import { combineLatest, Observable } from 'rxjs';
|
||||
import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import { AddUrlToHistoryAction } from '../history/history.actions';
|
||||
import { historySelector } from '../history/selectors';
|
||||
import { AddUrlToHistoryAction } from '../../shared/history/history.actions';
|
||||
import { historySelector } from '../../shared/history/selectors';
|
||||
import { SetParametersAction, SetQueryParametersAction } from './route.actions';
|
||||
import { CoreState } from '../../core/core.reducers';
|
||||
import { hasValue } from '../empty.util';
|
||||
import { coreSelector } from '../../core/core.selectors';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { coreSelector } from '../core.selectors';
|
||||
|
||||
/**
|
||||
* Selector to select all route parameters from the store
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { JournalIssueGridElementComponent } from './journal-issue-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -33,7 +36,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { JournalVolumeGridElementComponent } from './journal-volume-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -33,7 +36,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { JournalGridElementComponent } from './journal-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -39,7 +42,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { OrgunitGridElementComponent } from './orgunit-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -39,7 +42,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { PersonGridElementComponent } from './person-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -33,7 +36,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -3,11 +3,14 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec';
|
||||
import { ProjectGridElementComponent } from './project-grid-element.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -27,7 +30,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { ServerResponseService } from '../shared/services/server-response.service';
|
||||
import { ServerResponseService } from '../core/services/server-response.service';
|
||||
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
|
||||
import { AuthService } from '../core/auth/auth.service';
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { RouteService } from '../../services/route.service';
|
||||
import { RouteService } from '../../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
@@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
import { CommunityDataService } from '../../../core/data/community-data.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RouteService } from '../../services/route.service';
|
||||
import { RouteService } from '../../../core/services/route.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { isNotEmpty, isNotUndefined } from '../../empty.util';
|
||||
|
@@ -29,7 +29,7 @@ export class DropdownFieldParser extends FieldParser {
|
||||
const dropdownModel = new DynamicScrollableDropdownModel(dropdownModelConfig, layout);
|
||||
return dropdownModel;
|
||||
} else {
|
||||
throw Error(`Authority name is not available. Please checks form configuration file.`);
|
||||
throw Error(`Authority name is not available. Please check the form configuration file.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
<ng-container *ngComponentOutlet="getComponent(); injector: objectInjector;"></ng-container>
|
||||
<ng-container *ngComponentOutlet="component; injector: objectInjector;"></ng-container>
|
||||
|
@@ -1,16 +1,14 @@
|
||||
import { ItemTypeSwitcherComponent } from './item-type-switcher.component';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import * as decorator from '../item-type-decorator';
|
||||
import { getComponentByItemType, ItemViewMode } from '../item-type-decorator';
|
||||
import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model';
|
||||
import createSpy = jasmine.createSpy;
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../testing/utils';
|
||||
import createSpy = jasmine.createSpy;
|
||||
|
||||
const relationType = 'type';
|
||||
const mockItem: Item = Object.assign(new Item(), {
|
||||
@@ -61,7 +59,7 @@ describe('ItemTypeSwitcherComponent', () => {
|
||||
|
||||
describe('when calling getComponent', () => {
|
||||
beforeEach(() => {
|
||||
comp.getComponent();
|
||||
(comp as any).getComponent();
|
||||
});
|
||||
|
||||
it('should call getComponentByItemType with parameters type and viewMode', () => {
|
||||
@@ -79,7 +77,7 @@ describe('ItemTypeSwitcherComponent', () => {
|
||||
|
||||
describe('when calling getComponent', () => {
|
||||
beforeEach(() => {
|
||||
comp.getComponent();
|
||||
(comp as any).getComponent();
|
||||
});
|
||||
|
||||
it('should call getComponentByItemType with parameters type, viewMode and representationType', () => {
|
||||
|
@@ -32,6 +32,8 @@ export class ItemTypeSwitcherComponent implements OnInit {
|
||||
*/
|
||||
objectInjector: Injector;
|
||||
|
||||
component: any;
|
||||
|
||||
constructor(private injector: Injector) {
|
||||
}
|
||||
|
||||
@@ -40,14 +42,14 @@ export class ItemTypeSwitcherComponent implements OnInit {
|
||||
providers: [{ provide: ITEM, useFactory: () => this.object, deps:[] }],
|
||||
parent: this.injector
|
||||
});
|
||||
|
||||
this.component = this.getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the component depending on the item's relationship type
|
||||
* @returns {string}
|
||||
*/
|
||||
getComponent(): string {
|
||||
private getComponent(): string {
|
||||
if (hasValue((this.object as any).representationType)) {
|
||||
const metadataRepresentation = this.object as MetadataRepresentation;
|
||||
return getComponentByItemType(metadataRepresentation.itemType, this.viewMode, metadataRepresentation.representationType);
|
||||
|
@@ -4,7 +4,7 @@
|
||||
</a>
|
||||
<ul ngbDropdownMenu class="dropdown-menu" aria-labelledby="dropdownLang">
|
||||
<li class="dropdown-item" #langSelect *ngFor="let lang of translate.getLangs()"
|
||||
(click)="translate.use(lang)"
|
||||
(click)="useLang(lang)"
|
||||
[class.active]="lang === translate.currentLang">
|
||||
{{ langLabel(lang) }}
|
||||
</li>
|
||||
|
@@ -6,6 +6,9 @@ import {HttpClientTestingModule, HttpTestingController} from '@angular/common/ht
|
||||
import { GLOBAL_CONFIG } from '../../../config';
|
||||
import {LangConfig} from '../../../config/lang-config.interface';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { MockCookieService } from '../mocks/mock-cookie.service';
|
||||
import { CookieService } from '../../core/services/cookie.service';
|
||||
|
||||
// This test is completely independent from any message catalogs or keys in the codebase
|
||||
// The translation module is instantiated with these bogus messages that we aren't using anyway.
|
||||
@@ -28,8 +31,14 @@ class CustomLoader implements TranslateLoader {
|
||||
/* tslint:enable:quotemark */
|
||||
/* tslint:enable:object-literal-key-quotes */
|
||||
|
||||
let cookie: CookieService;
|
||||
|
||||
describe('LangSwitchComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
cookie = Object.assign(new MockCookieService());
|
||||
});
|
||||
|
||||
describe('with English and Deutsch activated, English as default', () => {
|
||||
let component: LangSwitchComponent;
|
||||
let fixture: ComponentFixture<LangSwitchComponent>;
|
||||
@@ -61,7 +70,11 @@ describe('LangSwitchComponent', () => {
|
||||
)],
|
||||
declarations: [LangSwitchComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [TranslateService, {provide: GLOBAL_CONFIG, useValue: mockConfig}]
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: GLOBAL_CONFIG, useValue: mockConfig },
|
||||
{ provide: CookieService, useValue: cookie }
|
||||
]
|
||||
}).compileComponents()
|
||||
.then(() => {
|
||||
translate = TestBed.get(TranslateService);
|
||||
@@ -73,6 +86,7 @@ describe('LangSwitchComponent', () => {
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
langSwitchElement = de.nativeElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -93,6 +107,24 @@ describe('LangSwitchComponent', () => {
|
||||
it('should define the main A HREF in the UI', (() => {
|
||||
expect(langSwitchElement.querySelector('a')).toBeDefined();
|
||||
}));
|
||||
|
||||
describe('when selecting a language', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(translate, 'use');
|
||||
spyOn(cookie, 'set');
|
||||
const langItem = fixture.debugElement.query(By.css('.dropdown-item')).nativeElement;
|
||||
langItem.click();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should translate the app', () => {
|
||||
expect(translate.use).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set the client\'s language cookie', () => {
|
||||
expect(cookie.set).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with English as the only active and also default language', () => {
|
||||
@@ -127,7 +159,11 @@ describe('LangSwitchComponent', () => {
|
||||
)],
|
||||
declarations: [LangSwitchComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [TranslateService, {provide: GLOBAL_CONFIG, useValue: mockConfig}]
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: GLOBAL_CONFIG, useValue: mockConfig },
|
||||
{ provide: CookieService, useValue: cookie }
|
||||
]
|
||||
}).compileComponents();
|
||||
translate = TestBed.get(TranslateService);
|
||||
translate.addLangs(mockConfig.languages.filter((MyLangConfig) => MyLangConfig.active === true).map((a) => a.code));
|
||||
|
@@ -2,6 +2,8 @@ import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {LangConfig} from '../../../config/lang-config.interface';
|
||||
import { LANG_COOKIE } from '../../app.component';
|
||||
import { CookieService } from '../../core/services/cookie.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-lang-switch',
|
||||
@@ -23,7 +25,8 @@ export class LangSwitchComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
|
||||
public translate: TranslateService
|
||||
public translate: TranslateService,
|
||||
public cookie: CookieService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -46,4 +49,13 @@ export class LangSwitchComponent implements OnInit {
|
||||
return this.activeLangs.find((MyLangConfig) => MyLangConfig.code === langcode).label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a language and store it in a cookie
|
||||
* @param lang The language to switch to
|
||||
*/
|
||||
useLang(lang: string) {
|
||||
this.translate.use(lang);
|
||||
this.cookie.set(LANG_COOKIE, lang);
|
||||
}
|
||||
|
||||
}
|
||||
|
26
src/app/shared/mocks/mock-cookie.service.ts
Normal file
26
src/app/shared/mocks/mock-cookie.service.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Mock for [[CookieService]]
|
||||
*/
|
||||
export class MockCookieService {
|
||||
cookies: Map<string, string>;
|
||||
|
||||
constructor(cookies: Map<string, string> = new Map()) {
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
set(name, value) {
|
||||
this.cookies.set(name, value);
|
||||
}
|
||||
|
||||
get(name) {
|
||||
return this.cookies.get(name);
|
||||
}
|
||||
|
||||
remove() {
|
||||
return jasmine.createSpy('remove');
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return jasmine.createSpy('getAll');
|
||||
}
|
||||
}
|
@@ -8,7 +8,7 @@
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||
(sortFieldChange)="onSortFieldChange($event)"
|
||||
*ngIf="getViewMode()===viewModeEnum.List">
|
||||
*ngIf="(currentMode$ | async) === viewModeEnum.List">
|
||||
</ds-object-list>
|
||||
|
||||
<ds-object-grid [config]="config"
|
||||
@@ -20,14 +20,14 @@
|
||||
(pageSizeChange)="onPageSizeChange($event)"
|
||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||
(sortFieldChange)="onSortFieldChange($event)"
|
||||
*ngIf="getViewMode()===viewModeEnum.Grid">
|
||||
*ngIf="(currentMode$ | async) === viewModeEnum.Grid">
|
||||
</ds-object-grid>
|
||||
|
||||
<ds-object-detail [config]="config"
|
||||
[sortConfig]="sortConfig"
|
||||
[objects]="objects"
|
||||
[hideGear]="hideGear"
|
||||
*ngIf="getViewMode()===viewModeEnum.Detail">
|
||||
*ngIf="(currentMode$ | async) === viewModeEnum.Detail">
|
||||
</ds-object-detail>
|
||||
|
||||
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import { ObjectCollectionComponent } from './object-collection.component';
|
||||
import { SetViewMode } from '../view-mode';
|
||||
import { element } from 'protractor';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Config } from '../../../config/config.interface';
|
||||
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RouterStub } from '../testing/router-stub';
|
||||
@@ -38,14 +36,14 @@ describe('ObjectCollectionComponent', () => {
|
||||
|
||||
}));
|
||||
it('should only show the grid component when the viewmode is set to grid', () => {
|
||||
objectCollectionComponent.currentMode = SetViewMode.Grid;
|
||||
objectCollectionComponent.currentMode$ = observableOf(SetViewMode.Grid);
|
||||
|
||||
expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeDefined();
|
||||
expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeNull();
|
||||
});
|
||||
|
||||
it('should only show the list component when the viewmode is set to list', () => {
|
||||
objectCollectionComponent.currentMode = SetViewMode.List;
|
||||
objectCollectionComponent.currentMode$ = observableOf(SetViewMode.List);
|
||||
|
||||
expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeDefined();
|
||||
expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeNull();
|
||||
|
@@ -11,7 +11,7 @@ import {
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { filter, map, startWith } from 'rxjs/operators';
|
||||
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PageInfo } from '../../core/shared/page-info.model';
|
||||
@@ -19,14 +19,14 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o
|
||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||
import { ListableObject } from './shared/listable-object.model';
|
||||
import { SetViewMode } from '../view-mode';
|
||||
import { hasValue, isNotEmpty } from '../empty.util';
|
||||
import { hasValue, isEmpty, isNotEmpty } from '../empty.util';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-viewable-collection',
|
||||
styleUrls: ['./object-collection.component.scss'],
|
||||
templateUrl: './object-collection.component.html',
|
||||
})
|
||||
export class ObjectCollectionComponent implements OnChanges, OnInit {
|
||||
export class ObjectCollectionComponent implements OnInit {
|
||||
|
||||
@Input() objects: RemoteData<ListableObject[]>;
|
||||
@Input() config?: PaginationComponentOptions;
|
||||
@@ -34,7 +34,6 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
|
||||
@Input() hasBorder = false;
|
||||
@Input() hideGear = false;
|
||||
pageInfo: Observable<PageInfo>;
|
||||
private sub;
|
||||
/**
|
||||
* An event fired when the page is changed.
|
||||
* Event's payload equals to the newly selected page.
|
||||
@@ -61,25 +60,17 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
|
||||
*/
|
||||
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
data: any = {};
|
||||
currentMode: SetViewMode = SetViewMode.List;
|
||||
currentMode$: Observable<SetViewMode>;
|
||||
viewModeEnum = SetViewMode;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.objects && !changes.objects.isFirstChange()) {
|
||||
// this.pageInfo = this.objects.pageInfo;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// this.pageInfo = this.objects.pageInfo;
|
||||
|
||||
this.sub = this.route
|
||||
this.currentMode$ = this.route
|
||||
.queryParams
|
||||
.subscribe((params) => {
|
||||
if (isNotEmpty(params.view)) {
|
||||
this.currentMode = params.view;
|
||||
}
|
||||
});
|
||||
.pipe(
|
||||
filter((params) => isNotEmpty(params.view)),
|
||||
map((params) => params.view),
|
||||
startWith(SetViewMode.List)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,15 +87,6 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
|
||||
private router: Router) {
|
||||
}
|
||||
|
||||
getViewMode(): SetViewMode {
|
||||
this.route.queryParams.pipe(map((params) => {
|
||||
if (isNotEmpty(params.view) && hasValue(params.view)) {
|
||||
this.currentMode = params.view;
|
||||
}
|
||||
}));
|
||||
return this.currentMode;
|
||||
}
|
||||
|
||||
onPageChange(event) {
|
||||
this.pageChange.emit(event);
|
||||
}
|
||||
|
@@ -1 +1 @@
|
||||
<ng-container *ngComponentOutlet="getDetailElement(); injector: objectInjector;"></ng-container>
|
||||
<ng-container *ngComponentOutlet="detailElement; injector: objectInjector;"></ng-container>
|
||||
|
@@ -26,6 +26,8 @@ export class WrapperDetailElementComponent implements OnInit {
|
||||
*/
|
||||
objectInjector: Injector;
|
||||
|
||||
detailElement: any;
|
||||
|
||||
/**
|
||||
* Initialize instance variables
|
||||
*
|
||||
@@ -42,13 +44,13 @@ export class WrapperDetailElementComponent implements OnInit {
|
||||
providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }],
|
||||
parent: this.injector
|
||||
});
|
||||
|
||||
this.detailElement = this.getDetailElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return class name for the object to inject
|
||||
*/
|
||||
getDetailElement(): string {
|
||||
private getDetailElement(): string {
|
||||
const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>;
|
||||
return rendersDSOType(f, SetViewMode.Detail);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<div class="card" [@focusShadow]="(isCollapsed() | async)?'blur':'focus'">
|
||||
<div class="card" [@focusShadow]="(isCollapsed$ | async)?'blur':'focus'">
|
||||
<a [routerLink]="['/items/' + dso.id]" class="card-img-top full-width">
|
||||
<div>
|
||||
<ds-grid-thumbnail [thumbnail]="this.item.getThumbnail() | async">
|
||||
|
@@ -9,11 +9,14 @@ import { of as observableOf } from 'rxjs/internal/observable/of';
|
||||
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { ITEM } from '../../../../items/switcher/item-type-switcher.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils';
|
||||
import { PaginatedList } from '../../../../../core/data/paginated-list';
|
||||
import { PageInfo } from '../../../../../core/shared/page-info.model';
|
||||
|
||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithMetadata.hitHighlights = {};
|
||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
@@ -45,7 +48,7 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||
mockItemWithoutMetadata.hitHighlights = {};
|
||||
mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), {
|
||||
bitstreams: observableOf({}),
|
||||
bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
|
||||
metadata: {
|
||||
'dc.title': [
|
||||
{
|
||||
|
@@ -16,11 +16,13 @@ import { hasValue } from '../../empty.util';
|
||||
|
||||
export class SearchResultGridElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> {
|
||||
dso: K;
|
||||
isCollapsed$: Observable<boolean>;
|
||||
|
||||
public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, protected truncatableService: TruncatableService) {
|
||||
super(listableObject);
|
||||
if (hasValue(this.object)) {
|
||||
this.dso = this.object.indexableObject;
|
||||
this.isCollapsed$ = this.isCollapsed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +46,7 @@ export class SearchResultGridElementComponent<T extends SearchResult<K>, K exten
|
||||
return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys);
|
||||
}
|
||||
|
||||
isCollapsed(): Observable<boolean> {
|
||||
private isCollapsed(): Observable<boolean> {
|
||||
return this.truncatableService.isCollapsed(this.dso.id);
|
||||
}
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
<ng-container *ngComponentOutlet="getGridElement(); injector: objectInjector;"></ng-container>
|
||||
<ng-container *ngComponentOutlet="gridElement; injector: objectInjector;"></ng-container>
|
||||
|
@@ -12,6 +12,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m
|
||||
export class WrapperGridElementComponent implements OnInit {
|
||||
@Input() object: ListableObject;
|
||||
objectInjector: Injector;
|
||||
gridElement: any;
|
||||
|
||||
constructor(private injector: Injector) {
|
||||
}
|
||||
@@ -21,7 +22,7 @@ export class WrapperGridElementComponent implements OnInit {
|
||||
providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }],
|
||||
parent: this.injector
|
||||
});
|
||||
|
||||
this.gridElement = this.getGridElement();
|
||||
}
|
||||
|
||||
getGridElement(): string {
|
||||
|
@@ -8,6 +8,7 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m
|
||||
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
|
||||
import { TruncatableService } from '../../truncatable/truncatable.service';
|
||||
import { Metadata } from '../../../core/shared/metadata.utils';
|
||||
import { MetadataMap } from '../../../core/shared/metadata.models';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-result-list-element',
|
||||
@@ -16,6 +17,7 @@ import { Metadata } from '../../../core/shared/metadata.utils';
|
||||
|
||||
export class SearchResultListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends AbstractListableElementComponent<T> {
|
||||
dso: K;
|
||||
metadata: MetadataMap;
|
||||
|
||||
public constructor(@Inject('objectElementProvider') public listable: ListableObject, protected truncatableService: TruncatableService) {
|
||||
super(listable);
|
||||
|
@@ -1 +1 @@
|
||||
<ng-container *ngComponentOutlet="getListElement(); injector: objectInjector;"></ng-container>
|
||||
<ng-container *ngComponentOutlet="listElement; injector: objectInjector;"></ng-container>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user