From e7f5372f8dd5a0f530c219becd35d4307fb3d1c7 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Feb 2019 11:42:31 +0100 Subject: [PATCH 01/70] Fixed an issue with license in collection page --- src/app/+collection-page/collection-page.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html index 6e411cb29d..6265b223d8 100644 --- a/src/app/+collection-page/collection-page.component.html +++ b/src/app/+collection-page/collection-page.component.html @@ -32,7 +32,7 @@ From f35b1ca62078abdfb63b962007b7a9716bb49292 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Feb 2019 11:41:51 +0100 Subject: [PATCH 02/70] restored name property to NormalizedEPerson class --- src/app/core/eperson/models/normalized-eperson.model.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/core/eperson/models/normalized-eperson.model.ts b/src/app/core/eperson/models/normalized-eperson.model.ts index eb4fa4abe0..4f2a5edcd4 100644 --- a/src/app/core/eperson/models/normalized-eperson.model.ts +++ b/src/app/core/eperson/models/normalized-eperson.model.ts @@ -14,6 +14,9 @@ export class NormalizedEPerson extends NormalizedDSpaceObject implements Cacheab @autoserialize public handle: string; + @autoserialize + public name: string; + @autoserializeAs(NormalizedGroup) groups: Group[]; From 22ebbd5ca388073afb350342e06015fbd9338407 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Feb 2019 15:51:45 +0100 Subject: [PATCH 03/70] Fixed an issue with save of repeatable scrollable-dropdown fields --- ...dynamic-scrollable-dropdown.component.html | 3 +- .../dynamic-scrollable-dropdown.component.ts | 8 ++++++ .../sections/form/section-form.component.ts | 28 ++++++++++--------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index 1b4e9d2cd3..cfe50def98 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -15,7 +15,8 @@ class="ds-form-input-btn btn btn-outline-primary" id="scrollableDropdownMenuButton_{{model.id}}" ngbDropdownToggle - [disabled]="model.readOnly"> + [disabled]="model.readOnly" + (click)="onToggle(sdRef); $event.stopPropagation();"> \ No newline at end of file + diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts index dcc01f2b46..385f83eae2 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts @@ -1,9 +1,10 @@ - -import { take } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { take } from 'rxjs/operators'; + import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { SearchFilterService } from './search-filter.service'; -import { Observable } from 'rxjs'; import { slide } from '../../../shared/animations/slide'; import { isNotEmpty } from '../../../shared/empty.util'; diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts index 6cb04c6c1f..af0676ffe2 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts @@ -22,6 +22,7 @@ import * as moment from 'moment'; import { RouteService } from '../../../../shared/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'; /** * This component renders a simple item page. @@ -67,13 +68,13 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple constructor(protected searchService: SearchService, protected filterService: SearchFilterService, - protected searchConfigService: SearchConfigurationService, protected router: Router, protected rdbs: RemoteDataBuildService, + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @Inject(PLATFORM_ID) private platformId: any, private route: RouteService) { - super(searchService, filterService, searchConfigService, rdbs, router, filterConfig); + super(searchService, filterService, rdbs, router, searchConfigService, filterConfig); } diff --git a/src/app/+search-page/search-filters/search-filters.component.html b/src/app/+search-page/search-filters/search-filters.component.html index 0522c1fba0..310d6502c7 100644 --- a/src/app/+search-page/search-filters/search-filters.component.html +++ b/src/app/+search-page/search-filters/search-filters.component.html @@ -1,7 +1,7 @@

{{"search.filters.head" | translate}}

-
-
- +
+
+
-{{"search.filters.reset" | translate}} \ No newline at end of file +{{"search.filters.reset" | translate}} diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index f16faff1f3..d6116843be 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -1,14 +1,17 @@ -import { Observable, of as observableOf } from 'rxjs'; +import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core'; + +import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; +import { filter, first, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators'; -import { filter, map, mergeMap, startWith, switchMap } from 'rxjs/operators'; -import { Component } from '@angular/core'; import { SearchService } from '../search-service/search.service'; import { RemoteData } from '../../core/data/remote-data'; import { SearchFilterConfig } from '../search-service/search-filter-config.model'; import { SearchConfigurationService } from '../search-service/search-configuration.service'; -import { isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { SearchFilterService } from './search-filter/search-filter.service'; import { getSucceededRemoteData } from '../../core/shared/operators'; +import { PaginatedSearchOptions } from '../paginated-search-options.model'; +import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; @Component({ selector: 'ds-search-filters', @@ -19,11 +22,12 @@ import { getSucceededRemoteData } from '../../core/shared/operators'; /** * This component represents the part of the search sidebar that contains filters. */ -export class SearchFiltersComponent { +export class SearchFiltersComponent implements OnDestroy, OnInit { + /** - * An observable containing configuration about which filters are shown and how they are shown + * An Array containing configuration about which filters are shown and how they are shown */ - filters: Observable>; + filters: SearchFilterConfig[] = []; /** * List of all filters that are currently active with their value set to null. @@ -31,15 +35,44 @@ export class SearchFiltersComponent { */ clearParams; + /** + * A boolean representing load state of filters configuration + */ + isLoadingFilters$: BehaviorSubject = new BehaviorSubject(true); + + /** + * The current paginated search options + */ + searchOptions$: Observable; + + private sub: Subscription; + /** * Initialize instance variables + * @param {ChangeDetectorRef} cdr * @param {SearchService} searchService * @param {SearchConfigurationService} searchConfigService * @param {SearchFilterService} filterService */ - constructor(private searchService: SearchService, private searchConfigService: SearchConfigurationService, private filterService: SearchFilterService) { - this.filters = searchService.getConfig().pipe(getSucceededRemoteData()); - this.clearParams = searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { + constructor( + private cdr: ChangeDetectorRef, + private searchService: SearchService, + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, + private filterService: SearchFilterService) { + } + + ngOnInit(): void { + this.searchOptions$ = this.searchConfigService.searchOptions; + + this.sub = this.searchOptions$.pipe( + tap(() => this.setLoading()), + switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getSucceededRemoteData()))) + .subscribe((filtersRD: RemoteData) => { + this.filters = filtersRD.payload; + this.isLoadingFilters$.next(false); + }); + + this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { Object.keys(filters).forEach((f) => filters[f] = null); return filters; })); @@ -58,12 +91,13 @@ export class SearchFiltersComponent { * @returns {Observable} Emits true whenever a given filter config should be shown */ isActive(filterConfig: SearchFilterConfig): Observable { + console.log('isActive', filterConfig); return this.filterService.getSelectedValuesForFilter(filterConfig).pipe( mergeMap((isActive) => { if (isNotEmpty(isActive)) { return observableOf(true); } else { - return this.searchConfigService.searchOptions.pipe( + return this.searchOptions$.pipe( switchMap((options) => { return this.searchService.getFacetValuesFor(filterConfig, 1, options).pipe( filter((RD) => !RD.isLoading), @@ -73,6 +107,20 @@ export class SearchFiltersComponent { } )) } - }),startWith(true),); + }), + first(), + startWith(true),); } + + private setLoading() { + this.isLoadingFilters$.next(true); + this.cdr.detectChanges(); + } + + ngOnDestroy(): void { + if (hasValue(this.sub)) { + this.sub.unsubscribe(); + } + } + } diff --git a/src/app/+search-page/search-labels/search-labels.component.ts b/src/app/+search-page/search-labels/search-labels.component.ts index 08e07cce3d..fd82de326c 100644 --- a/src/app/+search-page/search-labels/search-labels.component.ts +++ b/src/app/+search-page/search-labels/search-labels.component.ts @@ -1,10 +1,11 @@ -import { Component } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { SearchService } from '../search-service/search.service'; import { Observable } from 'rxjs'; import { Params } from '@angular/router'; import { map } from 'rxjs/operators'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { SearchConfigurationService } from '../search-service/search-configuration.service'; +import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; @Component({ selector: 'ds-search-labels', @@ -24,7 +25,9 @@ export class SearchLabelsComponent { /** * Initialize the instance variable */ - constructor(private searchService: SearchService, private searchConfigService: SearchConfigurationService) { + constructor( + private searchService: SearchService, + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) { this.appliedFilters = this.searchConfigService.getCurrentFrontendFilters(); } diff --git a/src/app/+search-page/search-options.model.ts b/src/app/+search-page/search-options.model.ts index 123cf950f8..e56cec1724 100644 --- a/src/app/+search-page/search-options.model.ts +++ b/src/app/+search-page/search-options.model.ts @@ -8,12 +8,14 @@ import { DSpaceObjectType } from '../core/shared/dspace-object-type.model'; * This model class represents all parameters needed to request information about a certain search request */ export class SearchOptions { + configuration?: string; scope?: string; query?: string; dsoType?: DSpaceObjectType; filters?: SearchFilter[]; - constructor(options: {scope?: string, query?: string, dsoType?: DSpaceObjectType, filters?: SearchFilter[]}) { + constructor(options: {configuration?: string, scope?: string, query?: string, dsoType?: DSpaceObjectType, filters?: SearchFilter[]}) { + this.configuration = options.configuration; this.scope = options.scope; this.query = options.query; this.dsoType = options.dsoType; @@ -28,6 +30,9 @@ export class SearchOptions { */ toRestUrl(url: string, args: string[] = []): string { + if (isNotEmpty(this.configuration)) { + args.push(`configuration=${this.configuration}`); + } if (isNotEmpty(this.query)) { args.push(`query=${this.query}`); } diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 816e3d67bf..333faacc47 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { switchMap, } from 'rxjs/operators'; import { PaginatedList } from '../core/data/paginated-list'; @@ -7,13 +7,13 @@ import { DSpaceObject } from '../core/shared/dspace-object.model'; import { pushInOut } from '../shared/animations/push'; import { HostWindowService } from '../shared/host-window.service'; import { PaginatedSearchOptions } from './paginated-search-options.model'; -import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; import { SearchResult } from './search-result.model'; import { SearchService } from './search-service/search.service'; import { SearchSidebarService } from './search-sidebar/search-sidebar.service'; import { hasValue } from '../shared/empty.util'; import { SearchConfigurationService } from './search-service/search-configuration.service'; import { getSucceededRemoteData } from '../core/shared/operators'; +import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component'; /** * This component renders a simple item page. @@ -26,7 +26,13 @@ import { getSucceededRemoteData } from '../core/shared/operators'; styleUrls: ['./search-page.component.scss'], templateUrl: './search-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, - animations: [pushInOut] + animations: [pushInOut], + providers: [ + { + provide: SEARCH_CONFIG_SERVICE, + useClass: SearchConfigurationService + } + ] }) /** @@ -62,8 +68,7 @@ export class SearchPageComponent implements OnInit { constructor(private service: SearchService, private sidebarService: SearchSidebarService, private windowService: HostWindowService, - private filterService: SearchFilterService, - private searchConfigService: SearchConfigurationService) { + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) { this.isXsOrSm$ = this.windowService.isXsOrSm(); } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 0c8a4ee306..ff23f92b2c 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -28,11 +28,37 @@ import { SearchFacetFilterWrapperComponent } from './search-filters/search-filte import { SearchBooleanFilterComponent } from './search-filters/search-filter/search-boolean-filter/search-boolean-filter.component'; import { SearchHierarchyFilterComponent } from './search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component'; import { SearchConfigurationService } from './search-service/search-configuration.service'; +import { SearchSwitchConfigurationComponent } from './search-switch-configuration/search-switch-configuration.component'; const effects = [ SearchSidebarEffects ]; +const components = [ + SearchPageComponent, + SearchResultsComponent, + SearchSidebarComponent, + SearchSettingsComponent, + ItemSearchResultListElementComponent, + CollectionSearchResultListElementComponent, + CommunitySearchResultListElementComponent, + ItemSearchResultGridElementComponent, + CollectionSearchResultGridElementComponent, + CommunitySearchResultGridElementComponent, + CommunitySearchResultListElementComponent, + SearchFiltersComponent, + SearchFilterComponent, + SearchFacetFilterComponent, + SearchLabelsComponent, + SearchFacetFilterComponent, + SearchFacetFilterWrapperComponent, + SearchRangeFilterComponent, + SearchTextFilterComponent, + SearchHierarchyFilterComponent, + SearchBooleanFilterComponent, + SearchSwitchConfigurationComponent +]; + @NgModule({ imports: [ SearchPageRoutingModule, @@ -41,29 +67,7 @@ const effects = [ EffectsModule.forFeature(effects), CoreModule.forRoot() ], - declarations: [ - SearchPageComponent, - SearchResultsComponent, - SearchSidebarComponent, - SearchSettingsComponent, - ItemSearchResultListElementComponent, - CollectionSearchResultListElementComponent, - CommunitySearchResultListElementComponent, - ItemSearchResultGridElementComponent, - CollectionSearchResultGridElementComponent, - CommunitySearchResultGridElementComponent, - CommunitySearchResultListElementComponent, - SearchFiltersComponent, - SearchFilterComponent, - SearchFacetFilterComponent, - SearchLabelsComponent, - SearchFacetFilterComponent, - SearchFacetFilterWrapperComponent, - SearchRangeFilterComponent, - SearchTextFilterComponent, - SearchHierarchyFilterComponent, - SearchBooleanFilterComponent, - ], + declarations: components, providers: [ SearchService, SearchSidebarService, @@ -82,7 +86,8 @@ const effects = [ SearchTextFilterComponent, SearchHierarchyFilterComponent, SearchBooleanFilterComponent, - ] + ], + exports: components }) /** diff --git a/src/app/+search-page/search-service/facet-value.model.ts b/src/app/+search-page/search-service/facet-value.model.ts index a597528d50..d5102ec68d 100644 --- a/src/app/+search-page/search-service/facet-value.model.ts +++ b/src/app/+search-page/search-service/facet-value.model.ts @@ -6,7 +6,13 @@ import { autoserialize, autoserializeAs } from 'cerialize'; */ export class FacetValue { /** - * The display value of the facet value + * The display label of the facet value + */ + @autoserialize + label: string; + + /** + * The value of the facet value */ @autoserializeAs(String, 'label') value: string; diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts index 292f26724d..31ba839eb5 100644 --- a/src/app/+search-page/search-service/search-configuration.service.ts +++ b/src/app/+search-page/search-service/search-configuration.service.ts @@ -1,3 +1,6 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; + import { BehaviorSubject, combineLatest as observableCombineLatest, @@ -7,12 +10,11 @@ import { Subscription } from 'rxjs'; import { filter, map } from 'rxjs/operators'; + import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; import { SearchOptions } from '../search-options.model'; -import { ActivatedRoute, Params } from '@angular/router'; import { PaginatedSearchOptions } from '../paginated-search-options.model'; -import { Injectable, OnDestroy } from '@angular/core'; import { RouteService } from '../../shared/services/route.service'; import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util'; import { RemoteData } from '../../core/data/remote-data'; @@ -28,7 +30,7 @@ export class SearchConfigurationService implements OnDestroy { /** * Default pagination settings */ - private defaultPagination = Object.assign(new PaginationComponentOptions(), { + protected defaultPagination = Object.assign(new PaginationComponentOptions(), { id: 'search-page-configuration', pageSize: 10, currentPage: 1 @@ -37,17 +39,22 @@ export class SearchConfigurationService implements OnDestroy { /** * Default sort settings */ - private defaultSort = new SortOptions('score', SortDirection.DESC); + protected defaultSort = new SortOptions('score', SortDirection.DESC); + + /** + * Default configuration parameter setting + */ + protected defaultConfiguration = 'default'; /** * Default scope setting */ - private defaultScope = ''; + protected defaultScope = ''; /** * Default query setting */ - private defaultQuery = ''; + protected defaultQuery = ''; /** * Emits the current default values @@ -74,8 +81,8 @@ export class SearchConfigurationService implements OnDestroy { * @param {RouteService} routeService * @param {ActivatedRoute} route */ - constructor(private routeService: RouteService, - private route: ActivatedRoute) { + constructor(protected routeService: RouteService, + protected route: ActivatedRoute) { this.defaults .pipe(getSucceededRemoteData()) .subscribe((defRD) => { @@ -85,10 +92,20 @@ export class SearchConfigurationService implements OnDestroy { this.subs.push(this.subscribeToSearchOptions(defs)); this.subs.push(this.subscribeToPaginatedSearchOptions(defs)); + } ) } + /** + * @returns {Observable} Emits the current configuration string + */ + getCurrentConfiguration(defaultConfiguration: string) { + return this.routeService.getQueryParameterValue('configuration').pipe(map((configuration) => { + return configuration || defaultConfiguration; + })); + } + /** * @returns {Observable} Emits the current scope's identifier */ @@ -188,6 +205,7 @@ export class SearchConfigurationService implements OnDestroy { */ subscribeToSearchOptions(defaults: SearchOptions): Subscription { return observableMerge( + this.getConfigurationPart(defaults.configuration), this.getScopePart(defaults.scope), this.getQueryPart(defaults.query), this.getDSOTypePart(), @@ -208,6 +226,7 @@ export class SearchConfigurationService implements OnDestroy { return observableMerge( this.getPaginationPart(defaults.pagination), this.getSortPart(defaults.sort), + this.getConfigurationPart(defaults.configuration), this.getScopePart(defaults.scope), this.getQueryPart(defaults.query), this.getDSOTypePart(), @@ -226,6 +245,7 @@ export class SearchConfigurationService implements OnDestroy { if (hasNoValue(this._defaults)) { const options = new PaginatedSearchOptions({ pagination: this.defaultPagination, + configuration: this.defaultConfiguration, sort: this.defaultSort, scope: this.defaultScope, query: this.defaultQuery @@ -242,6 +262,16 @@ export class SearchConfigurationService implements OnDestroy { this.subs.forEach((sub) => { sub.unsubscribe(); }); + this.subs = []; + } + + /** + * @returns {Observable} Emits the current configuration settings as a partial SearchOptions object + */ + private getConfigurationPart(defaultConfiguration: string): Observable { + return this.getCurrentConfiguration(defaultConfiguration).pipe(map((configuration) => { + return { configuration } + })); } /** diff --git a/src/app/+search-page/search-service/search-query-response.model.ts b/src/app/+search-page/search-service/search-query-response.model.ts index ac1d8b7df3..bca6e644fc 100644 --- a/src/app/+search-page/search-service/search-query-response.model.ts +++ b/src/app/+search-page/search-service/search-query-response.model.ts @@ -34,7 +34,7 @@ export class SearchQueryResponse { * The sort parameters used in the search request */ @autoserialize - configurationName: string; + configuration: string; /** * The sort parameters used in the search request diff --git a/src/app/+search-page/search-service/search-result-element-decorator.ts b/src/app/+search-page/search-service/search-result-element-decorator.ts index 348cf7f592..59446480a3 100644 --- a/src/app/+search-page/search-service/search-result-element-decorator.ts +++ b/src/app/+search-page/search-service/search-result-element-decorator.ts @@ -1,5 +1,6 @@ import { GenericConstructor } from '../../core/shared/generic-constructor'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { isNull } from '../../shared/empty.util'; /** * Contains the mapping between a search result component and a DSpaceObject @@ -11,12 +12,19 @@ const searchResultMap = new Map(); * @param {GenericConstructor} domainConstructor The constructor of the DSpaceObject * @returns Decorator function that performs the actual mapping on initialization of the component */ -export function searchResultFor(domainConstructor: GenericConstructor) { +export function searchResultFor(domainConstructor: GenericConstructor, configuration: string = null) { return function decorator(searchResult: any) { if (!searchResult) { return; } - searchResultMap.set(domainConstructor, searchResult); + if (isNull(configuration)) { + searchResultMap.set(domainConstructor, searchResult); + } else { + if (!searchResultMap.get(configuration)) { + searchResultMap.set(configuration, new Map()); + } + searchResultMap.get(configuration).set(domainConstructor, searchResult); + } }; } @@ -25,6 +33,10 @@ export function searchResultFor(domainConstructor: GenericConstructor} domainConstructor The DSpaceObject's constructor for which the search result component is requested * @returns The component's constructor that matches the given DSpaceObject */ -export function getSearchResultFor(domainConstructor: GenericConstructor) { - return searchResultMap.get(domainConstructor); +export function getSearchResultFor(domainConstructor: GenericConstructor, configuration: string = null) { + if (isNull(configuration) || configuration === 'default') { + return searchResultMap.get(domainConstructor); + } else { + return searchResultMap.get(configuration).get(domainConstructor); + } } diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 275b0b3340..1d5ff06193 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -7,7 +7,7 @@ import { Router, UrlSegmentGroup } from '@angular/router'; -import { map, switchMap, tap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, first, map, switchMap, take, tap } from 'rxjs/operators'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { FacetConfigSuccessResponse, @@ -23,12 +23,12 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { GenericConstructor } from '../../core/shared/generic-constructor'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { - configureRequest, + configureRequest, filterSuccessfulResponses, getResponseFromEntry, getSucceededRemoteData } from '../../core/shared/operators'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; -import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; import { NormalizedSearchResult } from '../normalized-search-result.model'; import { SearchOptions } from '../search-options.model'; import { SearchResult } from '../search-result.model'; @@ -63,6 +63,16 @@ export class SearchService implements OnDestroy { */ private facetLinkPathPrefix = 'discover/facets/'; + /** + * When true, a new search request is always dispatched + */ + private forceBypassCache = false; + + /** + * The ResponseParsingService constructor name + */ + private parser: GenericConstructor = SearchResponseParsingService; + /** * Subscription to unsubscribe from */ @@ -78,6 +88,19 @@ export class SearchService implements OnDestroy { ) { } + /** + * Method to set service options + * @param {GenericConstructor} parser The configuration necessary to perform this search + * @param {boolean} forceBypassCache When true, a new search request is always dispatched + * @returns {Observable>>>} Emits a paginated list with all search results found + */ + setServiceOptions(parser: GenericConstructor, forceBypassCache: boolean) { + if (parser) { + this.parser = parser; + } + this.forceBypassCache = forceBypassCache; + } + /** * Method to retrieve a paginated list of search results from the server * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search @@ -90,13 +113,15 @@ export class SearchService implements OnDestroy { url = (searchOptions as PaginatedSearchOptions).toRestUrl(url); } const request = new GetRequest(this.requestService.generateRequestId(), url); + const getResponseParserFn: () => GenericConstructor = () => { + return this.parser; + }; + return Object.assign(request, { - getResponseParser(): GenericConstructor { - return SearchResponseParsingService; - } + getResponseParser: getResponseParserFn }); }), - configureRequest(this.requestService) + configureRequest(this.requestService, this.forceBypassCache), ); const requestEntryObs = requestObs.pipe( switchMap((request: RestRequest) => this.requestService.getByHref(request.href)) @@ -111,8 +136,11 @@ export class SearchService implements OnDestroy { // turn dspace href from search results to effective list of DSpaceObjects // Turn list of observable remote data DSO's into observable remote data object with list of DSO const dsoObs: Observable> = sqrObs.pipe( + // filter((sqr: SearchQueryResponse) => isNotUndefined(sqr)), map((sqr: SearchQueryResponse) => { - return sqr.objects.map((nsr: NormalizedSearchResult) => { + return sqr.objects + .filter((nsr: NormalizedSearchResult) => isNotUndefined(nsr.dspaceObject)) + .map((nsr: NormalizedSearchResult) => { return this.rdb.buildSingle(nsr.dspaceObject); }) }), @@ -126,7 +154,7 @@ export class SearchService implements OnDestroy { let co = DSpaceObject; if (dsos.payload[index]) { const constructor: GenericConstructor = dsos.payload[index].constructor as GenericConstructor; - co = getSearchResultFor(constructor); + co = getSearchResultFor(constructor, searchOptions.configuration); return Object.assign(new co(), object, { dspaceObject: dsos.payload[index] }); @@ -134,6 +162,7 @@ export class SearchService implements OnDestroy { return undefined; } }); + // .filter((object) => isNotUndefined(object)); }) ); @@ -156,7 +185,7 @@ export class SearchService implements OnDestroy { * @param {string} scope UUID of the object for which config the filter config is requested, when no scope is provided the configuration for the whole repository is loaded * @returns {Observable>} The found filter configuration */ - getConfig(scope?: string): Observable> { + getConfig(scope?: string, configuration?: string): Observable> { const requestObs = this.halService.getEndpoint(this.facetLinkPathPrefix).pipe( map((url: string) => { const args: string[] = []; @@ -165,6 +194,10 @@ export class SearchService implements OnDestroy { args.push(`scope=${scope}`); } + if (isNotEmpty(configuration)) { + args.push(`configuration=${configuration}`); + } + if (isNotEmpty(args)) { url = new URLCombiner(url, `?${args.join('&')}`).toString(); } @@ -176,7 +209,7 @@ export class SearchService implements OnDestroy { } }); }), - configureRequest(this.requestService) + configureRequest(this.requestService, this.forceBypassCache) ); const requestEntryObs = requestObs.pipe( @@ -202,6 +235,7 @@ export class SearchService implements OnDestroy { * @returns {Observable>>} Emits the given page of facet values */ getFacetValuesFor(filterConfig: SearchFilterConfig, valuePage: number, searchOptions?: SearchOptions, filterQuery?: string): Observable>> { + console.log('getFacetValuesFor'); const requestObs = this.halService.getEndpoint(this.facetLinkPathPrefix + filterConfig.name).pipe( map((url: string) => { const args: string[] = [`page=${valuePage - 1}`, `size=${filterConfig.pageSize}`]; @@ -219,7 +253,8 @@ export class SearchService implements OnDestroy { } }); }), - configureRequest(this.requestService) + configureRequest(this.requestService, this.forceBypassCache), + first() ); const requestEntryObs = requestObs.pipe( diff --git a/src/app/+search-page/search-settings/search-settings.component.ts b/src/app/+search-page/search-settings/search-settings.component.ts index 7fc5645fcc..24b2ee4778 100644 --- a/src/app/+search-page/search-settings/search-settings.component.ts +++ b/src/app/+search-page/search-settings/search-settings.component.ts @@ -1,10 +1,11 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { SearchService } from '../search-service/search.service'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; import { PaginatedSearchOptions } from '../paginated-search-options.model'; import { Observable } from 'rxjs'; import { SearchConfigurationService } from '../search-service/search-configuration.service'; +import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; @Component({ selector: 'ds-search-settings', @@ -30,7 +31,7 @@ export class SearchSettingsComponent implements OnInit { constructor(private service: SearchService, private route: ActivatedRoute, private router: Router, - private searchConfigurationService: SearchConfigurationService) { + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigurationService: SearchConfigurationService) { } /** diff --git a/src/app/+search-page/search-sidebar/search-sidebar.component.html b/src/app/+search-page/search-sidebar/search-sidebar.component.html index 5ff1e3c8fa..ac9c834443 100644 --- a/src/app/+search-page/search-sidebar/search-sidebar.component.html +++ b/src/app/+search-page/search-sidebar/search-sidebar.component.html @@ -10,6 +10,7 @@
diff --git a/src/app/+search-page/search-sidebar/search-sidebar.component.scss b/src/app/+search-page/search-sidebar/search-sidebar.component.scss index b5bd6dd30d..960a8dfa8c 100644 --- a/src/app/+search-page/search-sidebar/search-sidebar.component.scss +++ b/src/app/+search-page/search-sidebar/search-sidebar.component.scss @@ -8,6 +8,9 @@ ds-view-mode-switch { margin-bottom: $spacer; } + ds-search-switch-configuration { + margin-bottom: 2*$spacer !important; + } .sidebar-content > *:not(:last-child) { margin-bottom: 4*$spacer; display: block; diff --git a/src/app/+search-page/search-sidebar/search-sidebar.component.ts b/src/app/+search-page/search-sidebar/search-sidebar.component.ts index 8b68cda793..bdd90633b0 100644 --- a/src/app/+search-page/search-sidebar/search-sidebar.component.ts +++ b/src/app/+search-page/search-sidebar/search-sidebar.component.ts @@ -1,5 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model'; + /** * This component renders a simple item page. * The route parameter 'id' is used to request the item it represents. @@ -17,6 +19,11 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; */ export class SearchSidebarComponent { + /** + * The list of available configuration options + */ + @Input() configurationList: SearchConfigurationOption[]; + /** * The total amount of results */ diff --git a/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts b/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts new file mode 100644 index 0000000000..7f9b4acd96 --- /dev/null +++ b/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts @@ -0,0 +1,4 @@ +export interface SearchConfigurationOption { + value: string; + label: string; +} diff --git a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html new file mode 100644 index 0000000000..5b1bdc1ddd --- /dev/null +++ b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html @@ -0,0 +1,13 @@ +
+
{{ 'search.switch-configuration.title' | translate}}
+ + + +
diff --git a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.scss b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.spec.ts b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.spec.ts new file mode 100644 index 0000000000..c7367c5f3f --- /dev/null +++ b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.spec.ts @@ -0,0 +1,103 @@ +// import { SearchService } from '../../search-service/search.service'; +// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +// import { SearchSettingsComponent } from '../../search-settings/search-settings.component'; +// import { Observable } from 'rxjs/Observable'; +// import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +// import { SortOptions } from '../../../core/cache/models/sort-options.model'; +// import { TranslateModule } from '@ngx-translate/core'; +// import { RouterTestingModule } from '@angular/router/testing'; +// import { ActivatedRoute } from '@angular/router'; +// import { SearchSidebarService } from '../../search-sidebar/search-sidebar.service'; +// import { NO_ERRORS_SCHEMA } from '@angular/core'; +// import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe'; +// import { By } from '@angular/platform-browser'; +// +// describe('SearchSettingsComponent', () => { +// +// let comp: SearchSettingsComponent; +// let fixture: ComponentFixture; +// let searchServiceObject: SearchService; +// +// const pagination: PaginationComponentOptions = new PaginationComponentOptions(); +// pagination.id = 'search-results-pagination'; +// pagination.currentPage = 1; +// pagination.pageSize = 10; +// const sort: SortOptions = new SortOptions(); +// const mockResults = [ 'test', 'data' ]; +// const searchServiceStub = { +// searchOptions: { pagination: pagination, sort: sort }, +// search: () => mockResults +// }; +// const queryParam = 'test query'; +// const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; +// const activatedRouteStub = { +// queryParams: Observable.of({ +// query: queryParam, +// scope: scopeParam +// }) +// }; +// +// const sidebarService = { +// isCollapsed: Observable.of(true), +// collapse: () => this.isCollapsed = Observable.of(true), +// expand: () => this.isCollapsed = Observable.of(false) +// } +// +// beforeEach(async(() => { +// TestBed.configureTestingModule({ +// imports: [ TranslateModule.forRoot(), RouterTestingModule.withRoutes([]) ], +// declarations: [ SearchSettingsComponent, EnumKeysPipe ], +// providers: [ +// { provide: SearchService, useValue: searchServiceStub }, +// +// { provide: ActivatedRoute, useValue: activatedRouteStub }, +// { +// provide: SearchSidebarService, +// useValue: sidebarService +// }, +// ], +// schemas: [ NO_ERRORS_SCHEMA ] +// }).compileComponents(); +// })); +// +// beforeEach(() => { +// fixture = TestBed.createComponent(SearchSettingsComponent); +// comp = fixture.componentInstance; +// +// // SearchPageComponent test instance +// fixture.detectChanges(); +// searchServiceObject = (comp as any).service; +// spyOn(comp, 'reloadRPP'); +// spyOn(comp, 'reloadOrder'); +// spyOn(searchServiceObject, 'search').and.callThrough(); +// +// }); +// +// it('it should show the order settings with the respective selectable options', () => { +// const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings')); +// expect(orderSetting).toBeDefined(); +// const childElements = orderSetting.query(By.css('.form-control')).children; +// expect(childElements.length).toEqual(2); +// +// }); +// +// it('it should show the size settings with the respective selectable options', () => { +// const pageSizeSetting = fixture.debugElement.query(By.css('div.page-size-settings')); +// expect(pageSizeSetting).toBeDefined(); +// const childElements = pageSizeSetting.query(By.css('.form-control')).children; +// expect(childElements.length).toEqual(7); +// }); +// +// it('should have the proper order value selected by default', () => { +// const orderSetting = fixture.debugElement.query(By.css('div.result-order-settings')); +// const childElementToBeSelected = orderSetting.query(By.css('.form-control option[value="0"][selected="selected"]')) +// expect(childElementToBeSelected).toBeDefined(); +// }); +// +// it('should have the proper rpp value selected by default', () => { +// const pageSizeSetting = fixture.debugElement.query(By.css('div.page-size-settings')); +// const childElementToBeSelected = pageSizeSetting.query(By.css('.form-control option[value="10"][selected="selected"]')) +// expect(childElementToBeSelected).toBeDefined(); +// }); +// +// }); diff --git a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.ts b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.ts new file mode 100644 index 0000000000..d894b4f454 --- /dev/null +++ b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.ts @@ -0,0 +1,54 @@ +import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core'; +import { NavigationExtras, Router } from '@angular/router'; + +import { Subscription } from 'rxjs'; + +import { hasValue } from '../../shared/empty.util'; +import { MYDSPACE_ROUTE, SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; +import { SearchConfigurationService } from '../search-service/search-configuration.service'; +import { MyDSpaceConfigurationValueType } from '../../+my-dspace-page/my-dspace-configuration-value-type'; +import { SearchConfigurationOption } from './search-configuration-option.model'; + +@Component({ + selector: 'ds-search-switch-configuration', + styleUrls: ['./search-switch-configuration.component.scss'], + templateUrl: './search-switch-configuration.component.html', +}) +export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit { + + /** + * The list of available configuration options + */ + @Input() configurationList: SearchConfigurationOption[] = []; + + public selectedOption: string; + + private sub: Subscription; + + constructor(private router: Router, + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { + } + + ngOnInit() { + this.searchConfigService.getCurrentConfiguration('default') + .subscribe((currentConfiguration) => this.selectedOption = currentConfiguration); + } + + onSelect(event: Event) { + const navigationExtras: NavigationExtras = { + queryParams: {configuration: this.selectedOption}, + }; + + this.router.navigate([MYDSPACE_ROUTE], navigationExtras); + } + + compare(item1: MyDSpaceConfigurationValueType, item2: MyDSpaceConfigurationValueType) { + return item1 === item2; + } + + ngOnDestroy() { + if (hasValue(this.sub)) { + this.sub.unsubscribe(); + } + } +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 03edd698fd..b0c9305a66 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -16,6 +16,7 @@ export function getItemModulePath() { { path: 'communities', loadChildren: './+community-page/community-page.module#CommunityPageModule' }, { path: 'collections', loadChildren: './+collection-page/collection-page.module#CollectionPageModule' }, { path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' }, + { path: 'mydspace', loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] }, { path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' }, { path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule' }, { path: 'admin', loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] }, diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index da1857b1c0..cdf7dd6de0 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -2,7 +2,8 @@ import { Injectable } from '@angular/core'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { merge as observableMerge, Observable, of as observableOf, race as observableRace } from 'rxjs'; -import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators'; +import { filter, find, first, map, mergeMap, switchMap, take } from 'rxjs/operators'; +import { remove } from 'lodash'; import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { CacheableObject } from '../cache/object-cache.reducer'; @@ -123,7 +124,10 @@ export class RequestService { // TODO to review "forceBypassCache" param when https://github.com/DSpace/dspace-angular/issues/217 will be fixed configure(request: RestRequest, forceBypassCache: boolean = false): void { const isGetRequest = request.method === RestRequestMethod.GET; - if (!isGetRequest || !this.isCachedOrPending(request) || (forceBypassCache && !this.isPending(request))) { + if (forceBypassCache) { + this.clearRequestsOnTheirWayToTheStore(request); + } + if (!isGetRequest || (forceBypassCache && !this.isPending(request)) || !this.isCachedOrPending(request)) { this.dispatchRequest(request); if (isGetRequest) { this.trackRequestsOnTheirWayToTheStore(request); @@ -248,6 +252,19 @@ export class RequestService { }); } + /** + * This method will store the href of every GET request that gets configured in a local variable, and + * remove it as soon as it can be found in the store. + */ + private clearRequestsOnTheirWayToTheStore(request: GetRequest) { + this.store.pipe(select(this.entryFromUUIDSelector(request.uuid)), + find((re: RequestEntry) => hasValue(re))) + .subscribe((re: RequestEntry) => { + if (!re.responsePending) { + remove(this.requestsOnTheirWayToTheStore, (item) => item === request.href); + } + }); + } /** * Dispatch commit action to send all changes (for a certain method) to the server (buffer) * @param {RestRequestMethod} method RestRequestMethod for which the changes should be committed diff --git a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.ts index 41298b559f..452e5b30ca 100644 --- a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.ts +++ b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.ts @@ -37,9 +37,5 @@ export class UserMenuComponent implements OnInit { // set user this.user$ = this.store.pipe(select(getAuthenticatedUser)); - this.user$.subscribe((user) => { - console.log(user, user.name); - }) - } } diff --git a/src/app/shared/pagination/pagination-component-options.model.ts b/src/app/shared/pagination/pagination-component-options.model.ts index 30ed2becd2..07756f1e6f 100644 --- a/src/app/shared/pagination/pagination-component-options.model.ts +++ b/src/app/shared/pagination/pagination-component-options.model.ts @@ -12,11 +12,19 @@ export class PaginationComponentOptions extends NgbPaginationConfig { */ currentPage = 1; + /** + * Maximum number of pages to display. + */ + maxSize = 10; + /** * A number array that represents options for a context pagination limit. */ pageSizeOptions: number[] = [5, 10, 20, 40, 60, 80, 100]; + /** + * Number of items per page. + */ pageSize: number; } diff --git a/src/app/shared/roles/role.directive.ts b/src/app/shared/roles/role.directive.ts new file mode 100644 index 0000000000..d71e520e35 --- /dev/null +++ b/src/app/shared/roles/role.directive.ts @@ -0,0 +1,114 @@ +import { + ChangeDetectorRef, + Directive, + Input, + OnChanges, + OnDestroy, + SimpleChanges, + TemplateRef, + ViewContainerRef +} from '@angular/core'; + +import { combineLatest, Observable, Subscription } from 'rxjs'; +import { filter, first, map } from 'rxjs/operators'; + +import { hasValue } from '../empty.util'; +import { RoleService } from '../../core/roles/role.service'; +import { RoleType } from '../../core/roles/role-types'; + +@Directive({ + selector: '[dsShowOnlyForRole],[dsShowExceptForRole]' +}) +/** + * Structural Directive for showing or hiding a template based on current user role + */ +export class RoleDirective implements OnChanges, OnDestroy { + + /** + * The role or list of roles that can show template + */ + @Input() dsShowOnlyForRole: RoleType | RoleType[]; + + /** + * The role or list of roles that cannot show template + */ + @Input() dsShowExceptForRole: RoleType | RoleType[]; + + private subs: Subscription[] = []; + + constructor( + private roleService: RoleService, + private viewContainer: ViewContainerRef, + private changeDetector: ChangeDetectorRef, + private templateRef: TemplateRef + ) { + } + + ngOnChanges(changes: SimpleChanges): void { + const onlyChanges = changes.dsShowOnlyForRole; + const exceptChanges = changes.dsShowExceptForRole; + this.hasRoles(this.dsShowOnlyForRole); + if (changes.dsShowOnlyForRole) { + this.validateOnly() + } else if (changes.dsShowExceptForRole) { + this.validateExcept() + } + } + + ngOnDestroy(): void { + this.subs + .filter((subscription) => hasValue(subscription)) + .forEach((subscription) => subscription.unsubscribe()); + } + + /** + * Show template in view container + */ + private showTemplateBlockInView(): void { + this.viewContainer.clear(); + if (!this.templateRef) { + return; + } + + this.viewContainer.createEmbeddedView(this.templateRef); + this.changeDetector.markForCheck(); + } + + /** + * Validate the list of roles that can show template + */ + private validateOnly(): void { + this.subs.push(this.hasRoles(this.dsShowOnlyForRole).pipe(filter((hasRole) => hasRole)) + .subscribe((hasRole) => { + this.showTemplateBlockInView(); + })); + } + + /** + * Validate the list of roles that cannot show template + */ + private validateExcept(): void { + this.subs.push(this.hasRoles(this.dsShowExceptForRole).pipe(filter((hasRole) => !hasRole)) + .subscribe((hasRole) => { + this.showTemplateBlockInView(); + })); + } + + /** + * Check if current user role is included in the specified role list + * + * @param roles + * The role or the list of roles + * @returns {Observable} + * observable of true if current user role is included in the specified role list, observable of false otherwise + */ + private hasRoles(roles: RoleType | RoleType[]): Observable { + const toValidate: RoleType[] = (Array.isArray(roles)) ? roles : [roles]; + const checks: Array> = toValidate.map((role) => this.roleService.checkRole(role)); + + return combineLatest(checks).pipe( + map((permissions: boolean[]) => permissions.includes(true)), + first() + ) + } +} diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts index 21a90daed4..ea96bd8114 100644 --- a/src/app/shared/search-form/search-form.component.ts +++ b/src/app/shared/search-form/search-form.component.ts @@ -3,6 +3,7 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { Router } from '@angular/router'; import { hasValue, isNotEmpty } from '../empty.util'; import { QueryParamsHandling } from '@angular/router/src/config'; +import { MYDSPACE_ROUTE } from '../../+my-dspace-page/my-dspace-page.component'; /** * This component renders a simple item page. @@ -64,7 +65,7 @@ export class SearchFormComponent { updateSearch(data: any) { const newUrl = hasValue(this.currentUrl) ? this.currentUrl : '/search'; let handling: QueryParamsHandling = '' ; - if (this.currentUrl === '/search') { + if (this.currentUrl === '/search' || this.currentUrl === MYDSPACE_ROUTE) { handling = 'merge'; } this.router.navigate([newUrl], { diff --git a/src/app/shared/services/route.service.ts b/src/app/shared/services/route.service.ts index a55a967d3b..f500b18082 100644 --- a/src/app/shared/services/route.service.ts +++ b/src/app/shared/services/route.service.ts @@ -1,9 +1,10 @@ import { Injectable } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Params, Router, } from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Params, Router, RouterStateSnapshot, } from '@angular/router'; import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { Observable } from 'rxjs'; import { select, Store } from '@ngrx/store'; +import { isEqual } from 'lodash'; import { AppState } from '../../app.reducer'; import { AddUrlToHistoryAction } from '../history/history.actions'; @@ -16,35 +17,35 @@ export class RouteService { } getQueryParameterValues(paramName: string): Observable { - return this.route.queryParamMap.pipe( + return this.getQueryParamMap().pipe( map((params) => [...params.getAll(paramName)]), distinctUntilChanged() ); } getQueryParameterValue(paramName: string): Observable { - return this.route.queryParamMap.pipe( + return this.getQueryParamMap().pipe( map((params) => params.get(paramName)), distinctUntilChanged() ); } hasQueryParam(paramName: string): Observable { - return this.route.queryParamMap.pipe( + return this.getQueryParamMap().pipe( map((params) => params.has(paramName)), distinctUntilChanged() ); } hasQueryParamWithValue(paramName: string, paramValue: string): Observable { - return this.route.queryParamMap.pipe( + return this.getQueryParamMap().pipe( map((params) => params.getAll(paramName).indexOf(paramValue) > -1), distinctUntilChanged() ); } getQueryParamsWithPrefix(prefix: string): Observable { - return this.route.queryParamMap.pipe( + return this.getQueryParamMap().pipe( map((qparams) => { const params = {}; qparams.keys @@ -57,6 +58,19 @@ export class RouteService { distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))); } + public getQueryParamMap(): Observable { + return this.route.queryParamMap.pipe( + map((paramMap) => { + const snapshot: RouterStateSnapshot = this.router.routerState.snapshot; + // Due to an Angular bug, sometimes change of QueryParam is not detected so double checks with route snapshot + if (!isEqual(paramMap, snapshot.root.queryParamMap)) { + return snapshot.root.queryParamMap; + } else { + return paramMap; + } + })) + } + public saveRouting(): void { this.router.events .pipe(filter((event) => event instanceof NavigationEnd)) diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index b7250a6e18..1acff996fa 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -77,6 +77,22 @@ import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/ import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; import { MockAdminGuard } from './mocks/mock-admin-guard.service'; import { AlertsComponent } from './alerts/alerts.component'; +import { MyDSpaceResultListElementComponent } from './object-list/my-dspace-result-list-element/my-dspace-result-list-element.component'; +import { MessageBoardComponent } from './message-board/message-board.component'; +import { MessageComponent } from './message-board/message/message.component'; +import { MyDSpaceResultDetailElementComponent } from './object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component'; +import { ClaimedTaskActionsComponent } from './mydspace-actions/claimed-task/claimed-task-actions.component'; +import { PoolTaskActionsComponent } from './mydspace-actions/pool-task/pool-task-actions.component'; +import { ObjectDetailComponent } from './object-detail/object-detail.component'; +import { WrapperDetailElementComponent } from './object-detail/wrapper-detail-element/wrapper-detail-element.component'; +import { ItemDetailPreviewComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component'; +import { MyDSpaceItemStatusComponent } from './object-collection/shared/mydspace-item-status/my-dspace-item-status.component'; +import { WorkspaceitemActionsComponent } from './mydspace-actions/workspaceitem/workspaceitem-actions.component'; +import { WorkflowitemActionsComponent } from './mydspace-actions/workflowitem/workflowitem-actions.component'; +import { ItemSubmitterComponent } from './object-collection/shared/mydspace-item-submitter/item-submitter.component'; +import { ItemActionsComponent } from './mydspace-actions/item/item-actions.component'; +import { ClaimedTaskActionsApproveComponent } from './mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component'; +import { ClaimedTaskActionsRejectComponent } from './mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component'; import { ObjNgFor } from './utils/object-ngfor.pipe'; import { BrowseByComponent } from './browse-by/browse-by.component'; import { BrowseEntryListElementComponent } from './object-list/browse-entry-list-element/browse-entry-list-element.component'; @@ -95,6 +111,20 @@ import { EditComColPageComponent } from './comcol-forms/edit-comcol-page/edit-co import { DeleteComColPageComponent } from './comcol-forms/delete-comcol-page/delete-comcol-page.component'; import { LangSwitchComponent } from './lang-switch/lang-switch.component'; import { ComcolPageBrowseByComponent } from './comcol-page-browse-by/comcol-page-browse-by.component'; +import { ItemListPreviewComponent } from './object-list/item-list-preview/item-list-preview.component'; +import { ItemPageAuthorFieldComponent } from '../+item-page/simple/field-components/specific-field/author/item-page-author-field.component'; +import { ItemPageDateFieldComponent } from '../+item-page/simple/field-components/specific-field/date/item-page-date-field.component'; +import { ItemPageAbstractFieldComponent } from '../+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component'; +import { ItemPageUriFieldComponent } from '../+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component'; +import { ItemPageTitleFieldComponent } from '../+item-page/simple/field-components/specific-field/title/item-page-title-field.component'; +import { ItemPageSpecificFieldComponent } from '../+item-page/simple/field-components/specific-field/item-page-specific-field.component'; +import { FileSectionComponent } from '../+item-page/simple/field-components/file-section/file-section.component'; +import { MetadataFieldWrapperComponent } from '../+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component'; +import { CollectionsComponent } from '../+item-page/field-components/collections/collections.component'; +import { MetadataValuesComponent } from '../+item-page/field-components/metadata-values/metadata-values.component'; +import { MetadataUriValuesComponent } from '../+item-page/field-components/metadata-uri-values/metadata-uri-values.component'; +import { RoleDirective } from './roles/role.directive'; +import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -136,6 +166,7 @@ const COMPONENTS = [ // put shared components here AlertsComponent, AuthNavMenuComponent, + UserMenuComponent, ChipsComponent, ComcolPageContentComponent, ComcolPageHeaderComponent, @@ -163,11 +194,15 @@ const COMPONENTS = [ LoadingComponent, LogInComponent, LogOutComponent, + MessageBoardComponent, + MessageComponent, NumberPickerComponent, ObjectListComponent, + ObjectDetailComponent, + ObjectGridComponent, AbstractListableElementComponent, WrapperListElementComponent, - ObjectGridComponent, + WrapperDetailElementComponent, WrapperGridElementComponent, ObjectCollectionComponent, PaginationComponent, @@ -176,6 +211,17 @@ const COMPONENTS = [ GridThumbnailComponent, UploaderComponent, WrapperListElementComponent, + ItemListPreviewComponent, + MyDSpaceItemStatusComponent, + ItemSubmitterComponent, + ItemDetailPreviewComponent, + ClaimedTaskActionsComponent, + ClaimedTaskActionsApproveComponent, + ClaimedTaskActionsRejectComponent, + ItemActionsComponent, + PoolTaskActionsComponent, + WorkflowitemActionsComponent, + WorkspaceitemActionsComponent, ViewModeSwitchComponent, TruncatableComponent, TruncatablePartComponent, @@ -188,12 +234,15 @@ const ENTRY_COMPONENTS = [ ItemListElementComponent, CollectionListElementComponent, CommunityListElementComponent, + MyDSpaceResultListElementComponent, SearchResultListElementComponent, ItemGridElementComponent, CollectionGridElementComponent, CommunityGridElementComponent, SearchResultGridElementComponent, BrowseEntryListElementComponent, + MyDSpaceResultDetailElementComponent, + SearchResultGridElementComponent, DsDynamicListComponent, DsDynamicLookupComponent, DsDynamicScrollableDropdownComponent, @@ -206,6 +255,20 @@ const ENTRY_COMPONENTS = [ DsDatePickerInlineComponent ]; +const SHARED_ITEM_PAGE_COMPONENTS = [ + CollectionsComponent, + FileSectionComponent, + ItemPageAuthorFieldComponent, + ItemPageDateFieldComponent, + ItemPageAbstractFieldComponent, + ItemPageUriFieldComponent, + ItemPageTitleFieldComponent, + ItemPageSpecificFieldComponent, + MetadataFieldWrapperComponent, + MetadataValuesComponent, + MetadataUriValuesComponent +]; + const PROVIDERS = [ TruncatableService, MockAdminGuard, @@ -220,7 +283,8 @@ const DIRECTIVES = [ DragClickDirective, DebounceDirective, ClickOutsideDirective, - AuthorityConfidenceStateDirective + AuthorityConfidenceStateDirective, + RoleDirective ]; @NgModule({ @@ -232,6 +296,7 @@ const DIRECTIVES = [ ...COMPONENTS, ...DIRECTIVES, ...ENTRY_COMPONENTS, + ...SHARED_ITEM_PAGE_COMPONENTS ], providers: [ ...PROVIDERS @@ -240,6 +305,7 @@ const DIRECTIVES = [ ...MODULES, ...PIPES, ...COMPONENTS, + ...SHARED_ITEM_PAGE_COMPONENTS, ...DIRECTIVES ], entryComponents: [ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index c03e93c2ce..b524e5e754 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1,3 +1,3 @@ -
+
-
\ No newline at end of file +
From 013d46429419de4924ad1643ff30c18a268e1a9a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 11 Mar 2019 20:07:11 +0100 Subject: [PATCH 12/70] Intermediate commit --- .../edit-collection-page.component.ts | 1 - .../edit-item-page.component.ts | 2 +- .../my-dspace-configuration.service.ts | 4 ++ .../my-dspace-page.component.html | 5 ++- .../my-dspace-page.component.ts | 14 +++--- .../+my-dspace-page/my-dspace-result.model.ts | 2 +- .../my-dspace-results.component.html | 2 +- .../my-dspace-results.component.ts | 6 ++- .../search-service/search.service.ts | 44 +++++++++---------- .../search-settings.component.ts | 4 +- .../search-sidebar.component.html | 2 +- .../search-sidebar.component.ts | 5 +++ src/app/core/auth/auth.service.ts | 22 ++-------- src/app/core/data/collection-data.service.ts | 1 - src/app/core/data/community-data.service.ts | 5 +-- .../data/default-change-analyzer.service.ts | 2 - .../data/mydspace-response-parsing.service.ts | 33 +++++++++++--- src/app/core/data/request.service.ts | 6 +-- .../models/normalized-eperson.model.ts | 3 -- .../message-response-parsing.service.ts | 4 +- .../core/tasks/claimed-task-data.service.ts | 5 +-- .../normalized-claimed-task-object.model.ts | 2 +- .../normalized-pool-task-object.model.ts | 2 +- .../models/normalized-task-object.model.ts | 3 +- src/app/core/tasks/pool-task-data.service.ts | 5 +-- src/app/core/tasks/tasks.service.ts | 5 +-- .../user-menu/user-menu.component.html | 4 +- .../user-menu/user-menu.component.ts | 7 +++ .../input-suggestions.component.ts | 2 +- .../message-board/message-board.component.ts | 19 +++----- .../claimed-task-actions.component.html | 2 +- .../claimed-task-actions.component.ts | 3 +- .../item/item-actions.component.html | 14 ++---- .../item/item-actions.component.ts | 17 +------ .../mydspace-actions-service.factory.ts | 3 +- .../mydspace-actions/mydspace-actions.ts | 5 +-- .../pool-task-actions.component.html | 4 +- .../pool-task/pool-task-actions.component.ts | 3 +- .../workflowitem-actions.component.ts | 4 +- .../workspaceitem-actions.component.html | 2 +- .../workspaceitem-actions.component.ts | 3 +- .../notifications/notifications.service.ts | 1 - ...-dspace-result-detail-element.component.ts | 2 +- ...-dspace-result-detail-element.component.ts | 10 ++--- ...-dspace-result-detail-element.component.ts | 10 ++--- .../item-list-preview.component.ts | 2 +- ...my-dspace-result-list-element.component.ts | 3 +- ...-dspace-result-list-element.component.html | 2 +- .../view-mode-switch.component.html | 20 +++++++-- .../view-mode-switch.component.ts | 17 ++++++- 50 files changed, 181 insertions(+), 167 deletions(-) diff --git a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts index a3978a5e43..ba70bd26c6 100644 --- a/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts +++ b/src/app/+collection-page/edit-collection-page/edit-collection-page.component.ts @@ -1,7 +1,6 @@ import { Component } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { EditComColPageComponent } from '../../shared/comcol-forms/edit-comcol-page/edit-comcol-page.component'; -import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model'; import { Collection } from '../../core/shared/collection.model'; import { CollectionDataService } from '../../core/data/collection-data.service'; diff --git a/src/app/+item-page/edit-item-page/edit-item-page.component.ts b/src/app/+item-page/edit-item-page/edit-item-page.component.ts index 4ea47f08e7..eafc04ae0b 100644 --- a/src/app/+item-page/edit-item-page/edit-item-page.component.ts +++ b/src/app/+item-page/edit-item-page/edit-item-page.component.ts @@ -1,6 +1,6 @@ import { fadeIn, fadeInOut } from '../../shared/animations/fade'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Params, Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; import { Observable } from 'rxjs'; diff --git a/src/app/+my-dspace-page/my-dspace-configuration.service.ts b/src/app/+my-dspace-page/my-dspace-configuration.service.ts index 4a06582425..a580ba9920 100644 --- a/src/app/+my-dspace-page/my-dspace-configuration.service.ts +++ b/src/app/+my-dspace-page/my-dspace-configuration.service.ts @@ -97,4 +97,8 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { ) } + public getCurrentView(): Observable { + return this.routeService.getQueryParameterValue('view'); + } + } diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html index 6f15070303..b38edebd97 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.html +++ b/src/app/+my-dspace-page/my-dspace-page.component.html @@ -5,7 +5,8 @@ + [resultCount]="(resultsRD$ | async)?.payload.totalElements" + [viewModeList]="viewModeList">
- +
- +

{{'mydspace.results.no-results' | translate}}

diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts index 1058a3eefd..e6a086fd46 100644 --- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts +++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts @@ -8,6 +8,7 @@ import { MyDSpaceResult } from '../my-dspace-result.model'; import { SearchOptions } from '../../+search-page/search-options.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { ViewMode } from '../../core/shared/view-mode.model'; +import { isEmpty } from '../../shared/empty.util'; /** * This component renders a simple item page. @@ -28,6 +29,9 @@ export class MyDSpaceResultsComponent { @Input() sortConfig: SortOptions; @Input() viewMode: ViewMode; - public hasBorder = true; + hasBorder = true; + isLoading() { + return !this.searchResults || isEmpty(this.searchResults) || this.searchResults.isLoading; + } } diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 1d5ff06193..e98fecd830 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -1,13 +1,7 @@ import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; import { Injectable, OnDestroy } from '@angular/core'; -import { - ActivatedRoute, - NavigationExtras, - PRIMARY_OUTLET, - Router, - UrlSegmentGroup -} from '@angular/router'; -import { distinctUntilChanged, filter, first, map, switchMap, take, tap } from 'rxjs/operators'; +import { ActivatedRoute, NavigationExtras, PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router'; +import { first, map, switchMap } from 'rxjs/operators'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { FacetConfigSuccessResponse, @@ -22,11 +16,7 @@ import { RequestService } from '../../core/data/request.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { GenericConstructor } from '../../core/shared/generic-constructor'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; -import { - configureRequest, filterSuccessfulResponses, - getResponseFromEntry, - getSucceededRemoteData -} from '../../core/shared/operators'; +import { configureRequest, getResponseFromEntry, getSucceededRemoteData } from '../../core/shared/operators'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; import { hasValue, isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; import { NormalizedSearchResult } from '../normalized-search-result.model'; @@ -47,6 +37,7 @@ import { CommunityDataService } from '../../core/data/community-data.service'; import { ViewMode } from '../../core/shared/view-mode.model'; import { ResourceType } from '../../core/shared/resource-type'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; +import { RouteService } from '../../shared/services/route.service'; /** * Service that performs all general actions that have to do with the search page @@ -80,6 +71,7 @@ export class SearchService implements OnDestroy { constructor(private router: Router, private route: ActivatedRoute, + private routeService: RouteService, protected requestService: RequestService, private rdb: RemoteDataBuildService, private halService: HALEndpointService, @@ -235,7 +227,6 @@ export class SearchService implements OnDestroy { * @returns {Observable>>} Emits the given page of facet values */ getFacetValuesFor(filterConfig: SearchFilterConfig, valuePage: number, searchOptions?: SearchOptions, filterQuery?: string): Observable>> { - console.log('getFacetValuesFor'); const requestObs = this.halService.getEndpoint(this.facetLinkPathPrefix + filterConfig.name).pipe( map((url: string) => { const args: string[] = [`page=${valuePage - 1}`, `size=${filterConfig.pageSize}`]; @@ -323,9 +314,9 @@ export class SearchService implements OnDestroy { * @returns {Observable} The current view mode */ getViewMode(): Observable { - return this.route.queryParams.pipe(map((params) => { - if (isNotEmpty(params.view) && hasValue(params.view)) { - return params.view; + return this.routeService.getQueryParamMap().pipe(map((params) => { + if (isNotEmpty(params.get('view')) && hasValue(params.get('view'))) { + return params.get('view'); } else { return ViewMode.List; } @@ -337,12 +328,21 @@ export class SearchService implements OnDestroy { * @param {ViewMode} viewMode Mode to switch to */ setViewMode(viewMode: ViewMode) { - const navigationExtras: NavigationExtras = { - queryParams: { view: viewMode }, - queryParamsHandling: 'merge' - }; + this.routeService.getQueryParameterValue('pageSize').pipe(first()) + .subscribe((pageSize) => { + let queryParams = { view: viewMode }; + if (viewMode === ViewMode.Detail) { + queryParams = Object.assign(queryParams, {pageSize: '1'}); + } else if (pageSize === '1') { + queryParams = Object.assign(queryParams, {pageSize: '10'}); + } + const navigationExtras: NavigationExtras = { + queryParams: queryParams, + queryParamsHandling: 'merge' + }; - this.router.navigate([this.getSearchLink()], navigationExtras); + this.router.navigate([this.getSearchLink()], navigationExtras); + }) } /** diff --git a/src/app/+search-page/search-settings/search-settings.component.ts b/src/app/+search-page/search-settings/search-settings.component.ts index 24b2ee4778..d26545b7f1 100644 --- a/src/app/+search-page/search-settings/search-settings.component.ts +++ b/src/app/+search-page/search-settings/search-settings.component.ts @@ -54,7 +54,7 @@ export class SearchSettingsComponent implements OnInit { }, queryParamsHandling: 'merge' }; - this.router.navigate([ '/search' ], navigationExtras); + this.router.navigate([ this.service.getSearchLink() ], navigationExtras); } /** @@ -71,6 +71,6 @@ export class SearchSettingsComponent implements OnInit { }, queryParamsHandling: 'merge' }; - this.router.navigate([ '/search' ], navigationExtras); + this.router.navigate([ this.service.getSearchLink() ], navigationExtras); } } diff --git a/src/app/+search-page/search-sidebar/search-sidebar.component.html b/src/app/+search-page/search-sidebar/search-sidebar.component.html index ac9c834443..3934f8cdac 100644 --- a/src/app/+search-page/search-sidebar/search-sidebar.component.html +++ b/src/app/+search-page/search-sidebar/search-sidebar.component.html @@ -8,7 +8,7 @@
- + diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.ts b/src/app/shared/view-mode-switch/view-mode-switch.component.ts index 07c47435ff..b011fce6a0 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.ts +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.ts @@ -1,7 +1,10 @@ +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; + import { Subscription } from 'rxjs'; -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { SearchService } from './../../+search-page/search-service/search.service'; + +import { SearchService } from '../../+search-page/search-service/search.service'; import { ViewMode } from '../../core/shared/view-mode.model'; +import { isEmpty } from '../empty.util'; /** * Component to switch between list and grid views. @@ -12,6 +15,8 @@ import { ViewMode } from '../../core/shared/view-mode.model'; templateUrl: './view-mode-switch.component.html' }) export class ViewModeSwitchComponent implements OnInit, OnDestroy { + @Input() viewModeList: ViewMode[]; + currentMode: ViewMode = ViewMode.List; viewModeEnum = ViewMode; private sub: Subscription; @@ -20,6 +25,10 @@ export class ViewModeSwitchComponent implements OnInit, OnDestroy { } ngOnInit(): void { + if (isEmpty(this.viewModeList)) { + this.viewModeList = [ViewMode.List, ViewMode.Grid]; + } + this.sub = this.searchService.getViewMode().subscribe((viewMode: ViewMode) => { this.currentMode = viewMode; }); @@ -34,4 +43,8 @@ export class ViewModeSwitchComponent implements OnInit, OnDestroy { this.sub.unsubscribe(); } } + + isToShow(viewMode: ViewMode) { + return this.viewModeList && this.viewModeList.includes(viewMode); + } } From b871148cc9afba8f37b13e928a35b603377ad8de Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 26 Mar 2019 10:04:05 +0100 Subject: [PATCH 13/70] fixes after merge --- .../normalized-search-result.model.ts | 2 +- .../search-facet-option.component.spec.ts | 9 +++++---- .../search-facet-option.component.ts | 2 +- ...earch-facet-range-option.component.spec.ts | 18 ++++++++++-------- .../search-facet-filter.component.spec.ts | 3 +++ .../search-filter/search-filter.reducer.ts | 7 +------ .../search-range-filter.component.spec.ts | 3 +++ .../search-filters.component.ts | 19 ++++++++++++++----- src/app/+search-page/search-page.module.ts | 10 ---------- .../core/cache/object-cache.service.spec.ts | 7 ++++--- src/app/core/cache/object-cache.service.ts | 2 +- src/app/core/data/data.service.spec.ts | 3 +-- .../data/mydspace-response-parsing.service.ts | 12 ++++++------ .../object-updates/object-updates.service.ts | 9 ++++++--- src/app/core/data/request.models.ts | 1 - src/app/core/data/request.service.ts | 13 ++++--------- .../data/search-response-parsing.service.ts | 4 ++-- src/app/core/json-patch/selectors.ts | 3 ++- .../dso-selector/dso-selector.component.html | 2 +- .../dso-selector.component.spec.ts | 2 +- ...te-collection-parent-selector.component.ts | 9 ++------- .../create-item-parent-selector.component.ts | 13 ++----------- ...o-selector-modal-wrapper.component.spec.ts | 7 ++----- .../dso-selector-modal-wrapper.component.ts | 2 +- .../edit-item-selector.component.ts | 15 +++------------ .../onclick-menu-item.component.spec.ts | 1 - src/app/shared/shared.module.ts | 1 - yarn.lock | 8 ++++++++ 28 files changed, 84 insertions(+), 103 deletions(-) diff --git a/src/app/+search-page/normalized-search-result.model.ts b/src/app/+search-page/normalized-search-result.model.ts index c7335bcde4..cb1238936a 100644 --- a/src/app/+search-page/normalized-search-result.model.ts +++ b/src/app/+search-page/normalized-search-result.model.ts @@ -9,7 +9,7 @@ export class NormalizedSearchResult implements ListableObject { /** * The UUID of the DSpaceObject that was found */ - @autoserializeAs(String, 'rObject') + @autoserializeAs(String, 'resultObject') dspaceObject: string; /** diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index f1dbedfb40..279ce0f97a 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -33,10 +33,11 @@ describe('SearchFacetOptionComponent', () => { maxValue: 3000, }); const value: FacetValue = { - value: value2, - count: 20, - search: '' - }; + label: value2, + value: value2, + count: 20, + search: '' + }; const searchLink = '/search'; const selectedValues = [value1]; diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index 7a6a51e99d..c4b339f464 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -1,5 +1,5 @@ import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs'; -import { map, take } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { FacetValue } from '../../../../search-service/facet-value.model'; diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts index 218730263b..d3264214ed 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts @@ -35,10 +35,11 @@ describe('SearchFacetRangeOptionComponent', () => { maxValue: 3000, }); const value: FacetValue = { - value: value2, - count: 20, - search: '' - }; + label: value2, + value: value2, + count: 20, + search: '' + }; const searchLink = '/search'; let filterService; @@ -92,10 +93,11 @@ describe('SearchFacetRangeOptionComponent', () => { it('should update the changeQueryParams with the new parameter values', () => { comp.changeQueryParams = {}; comp.filterValue = { - value: '50-60', - count: 20, - search: '' - }; + label: '50-60', + value: '50-60', + count: 20, + search: '' + }; (comp as any).updateChangeParams(); expect(comp.changeQueryParams).toEqual({ [mockFilterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: ['50'], diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index cb3d4730b4..9e775ab08b 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -35,14 +35,17 @@ describe('SearchFacetFilterComponent', () => { }); const values: FacetValue[] = [ { + label: value1, value: value1, count: 52, search: '' }, { + label: value2, value: value2, count: 20, search: '' }, { + label: value3, value: value3, count: 5, search: '' diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts index 187bcd50d0..7102c8c9bc 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts @@ -1,9 +1,4 @@ -import { - SearchFilterAction, - SearchFilterActionTypes, - SearchFilterInitializeAction -} from './search-filter.actions'; -import { isEmpty, isNotUndefined } from '../../../shared/empty.util'; +import { SearchFilterAction, SearchFilterActionTypes, SearchFilterInitializeAction } from './search-filter.actions'; /** * Interface that represents the state for a single filters diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts index 930ea8c9fb..845babd79c 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -41,14 +41,17 @@ describe('SearchRangeFilterComponent', () => { }); const values: FacetValue[] = [ { + label: value1, value: value1, count: 52, search: '' }, { + label: value2, value: value2, count: 20, search: '' }, { + label: value3, value: value3, count: 5, search: '' diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index 876d2a5f74..a0a140c784 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -1,7 +1,7 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, switchMap, tap } from 'rxjs/operators'; import { SearchService } from '../search-service/search.service'; import { RemoteData } from '../../core/data/remote-data'; @@ -20,7 +20,7 @@ import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.comp /** * This component represents the part of the search sidebar that contains filters. */ -export class SearchFiltersComponent { +export class SearchFiltersComponent implements OnInit { /** * An observable containing configuration about which filters are shown and how they are shown */ @@ -43,8 +43,16 @@ export class SearchFiltersComponent { @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, private filterService: SearchFilterService) { - this.filters = searchService.getConfig().pipe(getSucceededRemoteData()); - this.clearParams = searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { + } + + ngOnInit(): void { + + this.filters = this.searchConfigService.searchOptions.pipe( + tap((o) => console.log(o)), + switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getSucceededRemoteData())) + ); + + this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => { Object.keys(filters).forEach((f) => filters[f] = null); return filters; })); @@ -63,4 +71,5 @@ export class SearchFiltersComponent { trackUpdate(index, config: SearchFilterConfig) { return config ? config.name : undefined; } + } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index ec44a5d74e..482d2db8c1 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -5,9 +5,6 @@ import { SharedModule } from '../shared/shared.module'; import { SearchPageRoutingModule } from './search-page-routing.module'; import { SearchPageComponent } from './search-page.component'; import { SearchResultsComponent } from './search-results/search-results.component'; -import { ItemSearchResultListElementComponent } from '../shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component'; -import { CollectionSearchResultListElementComponent } from '../shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component'; -import { CommunitySearchResultListElementComponent } from '../shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component'; import { ItemSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component'; import { CommunitySearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component' import { CollectionSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; @@ -41,13 +38,9 @@ const components = [ SearchResultsComponent, SearchSidebarComponent, SearchSettingsComponent, - ItemSearchResultListElementComponent, - CollectionSearchResultListElementComponent, - CommunitySearchResultListElementComponent, ItemSearchResultGridElementComponent, CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, - CommunitySearchResultListElementComponent, SearchFiltersComponent, SearchFilterComponent, SearchFacetFilterComponent, @@ -79,9 +72,6 @@ const components = [ SearchConfigurationService ], entryComponents: [ - ItemSearchResultListElementComponent, - CollectionSearchResultListElementComponent, - CommunitySearchResultListElementComponent, ItemSearchResultGridElementComponent, CollectionSearchResultGridElementComponent, CommunitySearchResultGridElementComponent, diff --git a/src/app/core/cache/object-cache.service.spec.ts b/src/app/core/cache/object-cache.service.spec.ts index eae7c06be7..20e12108ad 100644 --- a/src/app/core/cache/object-cache.service.spec.ts +++ b/src/app/core/cache/object-cache.service.spec.ts @@ -1,18 +1,19 @@ +import * as ngrx from '@ngrx/store'; import { Store } from '@ngrx/store'; import { of as observableOf } from 'rxjs'; import { ObjectCacheService } from './object-cache.service'; import { AddPatchObjectCacheAction, - AddToObjectCacheAction, ApplyPatchObjectCacheAction, + AddToObjectCacheAction, + ApplyPatchObjectCacheAction, RemoveFromObjectCacheAction } from './object-cache.actions'; import { CoreState } from '../core.reducers'; import { ResourceType } from '../shared/resource-type'; import { NormalizedItem } from './models/normalized-item.model'; import { first } from 'rxjs/operators'; -import * as ngrx from '@ngrx/store'; -import { Operation } from '../../../../node_modules/fast-json-patch'; +import { Operation } from 'fast-json-patch'; import { RestRequestMethod } from '../data/rest-request-method'; import { AddToSSBAction } from './server-sync-buffer.actions'; import { Patch } from './object-cache.reducer'; diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index 483de65b98..e6384571c3 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -4,7 +4,7 @@ import { applyPatch, Operation } from 'fast-json-patch'; import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { distinctUntilChanged, filter, map, mergeMap, take, } from 'rxjs/operators'; -import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util'; +import { hasNoValue, isNotEmpty } from '../../shared/empty.util'; import { CoreState } from '../core.reducers'; import { coreSelector } from '../core.selectors'; import { RestRequestMethod } from '../data/rest-request-method'; diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts index 4a244db24f..dede6f8ae2 100644 --- a/src/app/core/data/data.service.spec.ts +++ b/src/app/core/data/data.service.spec.ts @@ -9,13 +9,12 @@ import { Observable, of as observableOf } from 'rxjs'; import { FindAllOptions } from './request.models'; import { SortDirection, SortOptions } from '../cache/models/sort-options.model'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { Operation } from '../../../../node_modules/fast-json-patch'; +import { compare, Operation } from 'fast-json-patch'; import { DSpaceObject } from '../shared/dspace-object.model'; import { ChangeAnalyzer } from './change-analyzer'; import { HttpClient } from '@angular/common/http'; import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { compare } from 'fast-json-patch'; import { Item } from '../shared/item.model'; const endpoint = 'https://rest.api/core'; diff --git a/src/app/core/data/mydspace-response-parsing.service.ts b/src/app/core/data/mydspace-response-parsing.service.ts index 9cd2103657..076103158f 100644 --- a/src/app/core/data/mydspace-response-parsing.service.ts +++ b/src/app/core/data/mydspace-response-parsing.service.ts @@ -40,7 +40,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { const dsoSelfLinks = payload._embedded.objects .filter((object) => hasValue(object._embedded)) - .map((object) => object._embedded.rObject) + .map((object) => object._embedded.resultObject) .map((dso) => this.dsoParser.parse(request, { payload: dso, statusCode: data.statusCode, @@ -52,7 +52,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { const objects = payload._embedded.objects .filter((object) => hasValue(object._embedded)) .map((object, index) => Object.assign({}, object, { - rObject: dsoSelfLinks[index], + resultObject: dsoSelfLinks[index], hitHighlights: hitHighlights[index], _embedded: this.filterEmbeddedObjects(object) })); @@ -63,13 +63,13 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { protected filterEmbeddedObjects(object) { const allowedEmbeddedKeys = ['submitter', 'item', 'workspaceitem', 'workflowitem']; - if (object._embedded.rObject && object._embedded.rObject._embedded) { + if (object._embedded.resultObject && object._embedded.resultObject._embedded) { return Object.assign({}, object._embedded, { - rObject: Object.assign({}, object._embedded.rObject, { - _embedded: Object.keys(object._embedded.rObject._embedded) + resultObject: Object.assign({}, object._embedded.resultObject, { + _embedded: Object.keys(object._embedded.resultObject._embedded) .filter((key) => allowedEmbeddedKeys.includes(key)) .reduce((obj, key) => { - obj[key] = object._embedded.rObject._embedded[key]; + obj[key] = object._embedded.resultObject._embedded[key]; return obj; }, {}) }) diff --git a/src/app/core/data/object-updates/object-updates.service.ts b/src/app/core/data/object-updates/object-updates.service.ts index a13fb9487b..22d5fd3e77 100644 --- a/src/app/core/data/object-updates/object-updates.service.ts +++ b/src/app/core/data/object-updates/object-updates.service.ts @@ -5,7 +5,8 @@ import { coreSelector } from '../../core.selectors'; import { FieldState, FieldUpdates, - Identifiable, OBJECT_UPDATES_TRASH_PATH, + Identifiable, + OBJECT_UPDATES_TRASH_PATH, ObjectUpdatesEntry, ObjectUpdatesState } from './object-updates.reducer'; @@ -17,9 +18,10 @@ import { InitializeFieldsAction, ReinstateObjectUpdatesAction, RemoveFieldUpdateAction, - SetEditableFieldUpdateAction, SetValidFieldUpdateAction + SetEditableFieldUpdateAction, + SetValidFieldUpdateAction } from './object-updates.actions'; -import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../../shared/empty.util'; import { INotification } from '../../../shared/notifications/models/notification.model'; @@ -212,6 +214,7 @@ export class ObjectUpdatesService { /** * Method to dispatch an RemoveFieldUpdateAction to the store * @param url The page's URL for which the changes should be removed + * @param uuid The UUID of the field that should be set */ removeSingleFieldUpdate(url: string, uuid) { this.store.dispatch(new RemoveFieldUpdateAction(url, uuid)); diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index 1dedcc89e2..f8cc0a4fd8 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -14,7 +14,6 @@ import { RestRequestMethod } from './rest-request-method'; import { SearchParam } from '../cache/models/search-param.model'; import { EpersonResponseParsingService } from '../eperson/eperson-response-parsing.service'; import { BrowseItemsResponseParsingService } from './browse-items-response-parsing-service'; -import { RegistryMetadataschemasResponseParsingService } from './registry-metadataschemas-response-parsing.service'; import { MetadataschemaParsingService } from './metadataschema-parsing.service'; import { MetadatafieldParsingService } from './metadatafield-parsing.service'; import { URLCombiner } from '../url-combiner/url-combiner'; diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index efc3ecb449..1bf86dc1e2 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@angular/core'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; -import { merge as observableMerge, Observable, of as observableOf, race as observableRace } from 'rxjs'; -import { filter, find, first, map, mergeMap, switchMap, take } from 'rxjs/operators'; +import { Observable, race as observableRace } from 'rxjs'; +import { filter, find, mergeMap, take } from 'rxjs/operators'; import { remove } from 'lodash'; import { AppState } from '../../app.reducer'; -import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { CacheableObject } from '../cache/object-cache.reducer'; import { ObjectCacheService } from '../cache/object-cache.service'; import { CoreState } from '../core.reducers'; @@ -17,11 +17,7 @@ import { uuidFromHrefSelector } from '../index/index.selectors'; import { UUIDService } from '../shared/uuid.service'; -import { - RequestConfigureAction, - RequestExecuteAction, - RequestRemoveAction -} from './request.actions'; +import { RequestConfigureAction, RequestExecuteAction, RequestRemoveAction } from './request.actions'; import { GetRequest, RestRequest } from './request.models'; import { RequestEntry, RequestState } from './request.reducer'; import { CommitSSBAction } from '../cache/server-sync-buffer.actions'; @@ -52,7 +48,6 @@ const entryFromUUIDSelector = (uuid: string): MemoizedSelector hasValue(object._embedded)) - .map((object) => object._embedded.rObject) + .map((object) => object._embedded.resultObject) // we don't need embedded collections, bitstreamformats, etc for search results. // And parsing them all takes up a lot of time. Throw them away to improve performance // until objs until partial results are supported by the rest api @@ -53,7 +53,7 @@ export class SearchResponseParsingService implements ResponseParsingService { const objects = payload._embedded.objects .filter((object) => hasValue(object._embedded)) .map((object, index) => Object.assign({}, object, { - rObject: dsoSelfLinks[index], + resultObject: dsoSelfLinks[index], hitHighlights: hitHighlights[index], // we don't need embedded collections, bitstreamformats, etc for search results. // And parsing them all takes up a lot of time. Throw them away to improve performance diff --git a/src/app/core/json-patch/selectors.ts b/src/app/core/json-patch/selectors.ts index a77afb7b7d..f6df4e1d07 100644 --- a/src/app/core/json-patch/selectors.ts +++ b/src/app/core/json-patch/selectors.ts @@ -1,7 +1,8 @@ // @TODO: Merge with keySelector function present in 'src/app/core/shared/selectors.ts' import { createSelector, MemoizedSelector, Selector } from '@ngrx/store'; import { hasValue } from '../../shared/empty.util'; -import { coreSelector, CoreState } from '../core.reducers'; +import { CoreState } from '../core.reducers'; +import { coreSelector } from '../core.selectors'; import { JsonPatchOperationsEntry, JsonPatchOperationsResourceEntry } from './json-patch-operations.reducer'; export function keySelector(parentSelector: Selector, subState: string, key: string): MemoizedSelector { diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html index 1e0deed4b9..da6bfa40ba 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html @@ -17,4 +17,4 @@ (click)="onSelect.emit(listEntry.dspaceObject)" #listEntryElement> -
\ No newline at end of file +
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts index 04111a4ea6..f9d1567245 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { DSOSelectorComponent } from './dso-selector.component'; diff --git a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts index 1e129c0dbe..0533addb01 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts @@ -1,7 +1,5 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; -import { Community } from '../../../../core/shared/community.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; @@ -9,10 +7,7 @@ import { COLLECTION_PARENT_PARAMETER, getCollectionCreatePath } from '../../../../+collection-page/collection-page-routing.module'; -import { - DSOSelectorModalWrapperComponent, - SelectorActionType -} from '../dso-selector-modal-wrapper.component'; +import { DSOSelectorModalWrapperComponent, SelectorActionType } from '../dso-selector-modal-wrapper.component'; /** * Component to wrap a list of existing communities inside a modal diff --git a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts index dac5888bf7..29af9f624e 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts @@ -1,18 +1,9 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Community } from '../../../../core/shared/community.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { Collection } from '../../../../core/shared/collection.model'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; -import { hasValue } from '../../../empty.util'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { map } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { - DSOSelectorModalWrapperComponent, - SelectorActionType -} from '../dso-selector-modal-wrapper.component'; +import { DSOSelectorModalWrapperComponent, SelectorActionType } from '../dso-selector-modal-wrapper.component'; /** * Component to wrap a list of existing collections inside a modal diff --git a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.spec.ts b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.spec.ts index ea857f7d62..4ceaeccb3a 100644 --- a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.spec.ts +++ b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.spec.ts @@ -5,10 +5,7 @@ import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model' import { RemoteData } from '../../../core/data/remote-data'; import { Item } from '../../../core/shared/item.model'; import { of as observableOf } from 'rxjs'; -import { - DSOSelectorModalWrapperComponent, - SelectorActionType -} from './dso-selector-modal-wrapper.component'; +import { DSOSelectorModalWrapperComponent, SelectorActionType } from './dso-selector-modal-wrapper.component'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ActivatedRoute } from '@angular/router'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; @@ -16,7 +13,7 @@ import { first } from 'rxjs/operators'; import { By } from '@angular/platform-browser'; import { DSOSelectorComponent } from '../dso-selector/dso-selector.component'; import { MockComponent } from 'ng-mocks'; -import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models'; +import { MetadataValue } from '../../../core/shared/metadata.models'; describe('DSOSelectorModalWrapperComponent', () => { let component: DSOSelectorModalWrapperComponent; diff --git a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts index 351a92302c..881476cac6 100644 --- a/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/dso-selector-modal-wrapper.component.ts @@ -1,4 +1,4 @@ -import { Component, Injectable, Input, OnInit } from '@angular/core'; +import { Injectable, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts index 9182df8045..dae36d3017 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts @@ -1,19 +1,10 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; -import { Community } from '../../../../core/shared/community.model'; -import { RemoteData } from '../../../../core/data/remote-data'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { Collection } from '../../../../core/shared/collection.model'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { Item } from '../../../../core/shared/item.model'; import { getItemEditPath } from '../../../../+item-page/item-page-routing.module'; -import { - DSOSelectorModalWrapperComponent, - SelectorActionType -} from '../dso-selector-modal-wrapper.component'; +import { DSOSelectorModalWrapperComponent, SelectorActionType } from '../dso-selector-modal-wrapper.component'; /** * Component to wrap a list of existing items inside a modal diff --git a/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts b/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts index dd031a96e0..dbe6fdab6a 100644 --- a/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts +++ b/src/app/shared/menu/menu-item/onclick-menu-item.component.spec.ts @@ -1,5 +1,4 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TextMenuItemComponent } from './text-menu-item.component'; import { TranslateModule } from '@ngx-translate/core'; import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index d9fc667e23..cef04918c8 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -126,7 +126,6 @@ import { ItemSearchResultListElementComponent } from './object-list/search-resul import { EditItemSelectorComponent } from './dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component'; import { EditCommunitySelectorComponent } from './dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component'; import { EditCollectionSelectorComponent } from './dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component'; -import { DSOSelectorModalWrapperComponent } from './dso-selector/modal-wrappers/dso-selector-modal-wrapper.component'; import { ItemListPreviewComponent } from './object-list/item-list-preview/item-list-preview.component'; import { ItemPageAuthorFieldComponent } from '../+item-page/simple/field-components/specific-field/author/item-page-author-field.component'; import { ItemPageDateFieldComponent } from '../+item-page/simple/field-components/specific-field/date/item-page-date-field.component'; diff --git a/yarn.lock b/yarn.lock index a3a3b043c7..9ca37783d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -285,6 +285,7 @@ "@types/circular-json@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be" + integrity sha512-7+kYB7x5a7nFWW1YPBh3KxhwKfiaI4PbZ1RvzBU91LZy7lWJO822CI+pqzSre/DZ7KsCuMKdHnLHHFu8AyXbQg== "@types/connect@*": version "3.4.32" @@ -448,6 +449,7 @@ "@types/stacktrace-js@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/stacktrace-js/-/stacktrace-js-0.0.32.tgz#d23e4a36a5073d39487fbea8234cc6186862d389" + integrity sha512-SdxmlrHfO0BxgbBP9HZWMUo2rima8lwMjPiWm6S0dyKkDa5CseamktFhXg8umu3TPVBkSlX6ZoB5uUDJK89yvg== "@types/strip-bom@^3.0.0": version "3.0.0" @@ -1881,6 +1883,7 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: circular-json@^0.5.0: version "0.5.9" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== circular-json@^0.5.5: version "0.5.5" @@ -3052,6 +3055,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: error-stack-parser@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.2.tgz#4ae8dbaa2bf90a8b450707b9149dcabca135520d" + integrity sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw== dependencies: stackframe "^1.0.4" @@ -8418,6 +8422,7 @@ rx@^4.1.0: rxjs-spy@^7.5.1: version "7.5.1" resolved "https://registry.yarnpkg.com/rxjs-spy/-/rxjs-spy-7.5.1.tgz#1a9ef50bc8d7dd00d9ecf3c54c00929231eaf319" + integrity sha512-dJ9mO4HvW2r16PsU15Qsc0RVkG7pFrfyCNTGx3vrxWje3kIgZ6QjMVnWblQxbniZ32lwLk/2x9+D2O6GhgXV/w== dependencies: "@types/circular-json" "^0.4.0" "@types/stacktrace-js" "^0.0.32" @@ -8936,6 +8941,7 @@ source-map@0.5.0: source-map@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= source-map@0.7.3: version "0.7.3" @@ -9079,10 +9085,12 @@ ssri@^5.2.4: stackframe@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b" + integrity sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw== stacktrace-gps@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.2.tgz#33f8baa4467323ab2bd1816efa279942ba431ccc" + integrity sha512-9o+nWhiz5wFnrB3hBHs2PTyYrS60M1vvpSzHxwxnIbtY2q9Nt51hZvhrG1+2AxD374ecwyS+IUwfkHRE/2zuGg== dependencies: source-map "0.5.6" stackframe "^1.0.4" From 67c9fc9fddb90503c6174a6e32339d6595225d26 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 26 Mar 2019 16:32:38 +0100 Subject: [PATCH 14/70] Fixes --- .../+search-page/search-filters/search-filters.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index a0a140c784..a6612154cf 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -1,7 +1,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { map, switchMap, tap } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { SearchService } from '../search-service/search.service'; import { RemoteData } from '../../core/data/remote-data'; @@ -48,7 +48,6 @@ export class SearchFiltersComponent implements OnInit { ngOnInit(): void { this.filters = this.searchConfigService.searchOptions.pipe( - tap((o) => console.log(o)), switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getSucceededRemoteData())) ); From 9b65189b4a7c9e339ff185aa261fab40e466fcdc Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 26 Mar 2019 17:03:03 +0100 Subject: [PATCH 15/70] Fixed build errors --- src/app/shared/log-out/log-out.component.html | 2 +- src/app/shared/log-out/log-out.component.ts | 1 + src/app/shared/message-board/message/message.component.html | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/shared/log-out/log-out.component.html b/src/app/shared/log-out/log-out.component.html index ab398d1735..d522fc6fb9 100644 --- a/src/app/shared/log-out/log-out.component.html +++ b/src/app/shared/log-out/log-out.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/shared/log-out/log-out.component.ts b/src/app/shared/log-out/log-out.component.ts index 0a6b936cd5..6fa71caa32 100644 --- a/src/app/shared/log-out/log-out.component.ts +++ b/src/app/shared/log-out/log-out.component.ts @@ -25,6 +25,7 @@ export class LogOutComponent implements OnInit { /** * @constructor * @param {Store} store + * @param {Router} router */ constructor(private router: Router, private store: Store) { diff --git a/src/app/shared/message-board/message/message.component.html b/src/app/shared/message-board/message/message.component.html index d8637e87fe..e6dfe7dcb5 100644 --- a/src/app/shared/message-board/message/message.component.html +++ b/src/app/shared/message-board/message/message.component.html @@ -1,4 +1,4 @@ -
  • @@ -7,7 +7,7 @@
    - {{m.findMetadata('dc.date.issued') | date: 'dd/MM/yyyy HH:mm'}} + {{m.firstMetadataValue('dc.date.issued') | date: 'dd/MM/yyyy HH:mm'}} - +
    From 39b98f7f1ca44c5daa8fbd70863872cb184a4a2a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 27 Mar 2019 14:49:37 +0100 Subject: [PATCH 16/70] Fixed unit tests --- .../metadata-field-form.component.spec.ts | 6 +++ .../search-facet-filter.component.spec.ts | 5 +- .../search-filter.component.spec.ts | 6 +-- .../search-filter/search-filter.component.ts | 8 ++- .../search-filter.service.spec.ts | 19 +------ .../search-range-filter.component.spec.ts | 6 +-- .../search-filters.component.spec.ts | 10 ++-- .../search-filters.component.ts | 4 +- .../search-labels.component.spec.ts | 5 +- .../search-page.component.spec.ts | 54 ++++++++++--------- src/app/+search-page/search-page.component.ts | 6 +-- .../search-configuration.service.ts | 6 +-- .../search-service/search.service.spec.ts | 28 +++++----- .../search-service/search.service.ts | 1 - .../search-settings.component.spec.ts | 4 +- .../auth-nav-menu.component.spec.ts | 4 +- src/app/shared/mocks/mock-router.ts | 9 +++- .../pagination/pagination.component.spec.ts | 2 +- src/app/shared/services/route.service.spec.ts | 5 +- src/app/shared/testing/route-service-stub.ts | 26 +++++++++ .../search-configuration-service-stub.ts | 16 ++++++ 21 files changed, 143 insertions(+), 87 deletions(-) create mode 100644 src/app/shared/testing/route-service-stub.ts create mode 100644 src/app/shared/testing/search-configuration-service-stub.ts diff --git a/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts b/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts index 4364b0234a..c6402c1f3b 100644 --- a/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts +++ b/src/app/+admin/admin-registries/metadata-schema/metadata-field-form/metadata-field-form.component.spec.ts @@ -28,6 +28,7 @@ describe('MetadataFieldFormComponent', () => { const registryServiceStub = { getActiveMetadataField: () => observableOf(undefined), createOrUpdateMetadataField: (field: MetadataField) => observableOf(field), + cancelEditMetadataField: () => {}, cancelEditMetadataSchema: () => {}, }; const formBuilderServiceStub = { @@ -62,6 +63,11 @@ describe('MetadataFieldFormComponent', () => { registryService = s; })); + afterEach(() => { + component = null; + registryService = null + }) + describe('when submitting the form', () => { const element = 'fakeElement'; const qualifier = 'fakeQualifier'; diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index 9e775ab08b..adb2919653 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -17,7 +17,8 @@ import { Router } from '@angular/router'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { SearchFacetFilterComponent } from './search-facet-filter.component'; import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; -import { SearchConfigurationService } from '../../../search-service/search-configuration.service'; +import { SearchConfigurationServiceStub } from '../../../../shared/testing/search-configuration-service-stub'; +import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component'; describe('SearchFacetFilterComponent', () => { let comp: SearchFacetFilterComponent; @@ -69,7 +70,7 @@ describe('SearchFacetFilterComponent', () => { { provide: Router, useValue: new RouterStub() }, { provide: FILTER_CONFIG, useValue: new SearchFilterConfig() }, { provide: RemoteDataBuildService, useValue: {aggregate: () => observableOf({})} }, - { provide: SearchConfigurationService, useValue: {searchOptions: observableOf({})} }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SearchFilterService, useValue: { getSelectedValuesForFilter: () => observableOf(selectedValues), diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.spec.ts index 30ef349675..23c4ab3b53 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.spec.ts @@ -11,6 +11,8 @@ import { SearchFilterComponent } from './search-filter.component'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { FilterType } from '../../search-service/filter-type.model'; import { SearchConfigurationService } from '../../search-service/search-configuration.service'; +import { SearchConfigurationServiceStub } from '../../../shared/testing/search-configuration-service-stub'; +import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component'; describe('SearchFilterComponent', () => { let comp: SearchFilterComponent; @@ -54,8 +56,6 @@ describe('SearchFilterComponent', () => { getFacetValuesFor: (filter) => mockResults }; - const searchConfigServiceStub = {}; - beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule], @@ -66,7 +66,7 @@ describe('SearchFilterComponent', () => { provide: SearchFilterService, useValue: mockFilterService }, - { provide: SearchConfigurationService, useValue: searchConfigServiceStub }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(SearchFilterComponent, { diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts index 83bf436e6e..5c6973bd98 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Inject, Input, OnInit } from '@angular/core'; import { Observable, of as observableOf } from 'rxjs'; import { filter, first, map, startWith, switchMap, take } from 'rxjs/operators'; @@ -9,6 +9,7 @@ import { slide } from '../../../shared/animations/slide'; import { isNotEmpty } from '../../../shared/empty.util'; import { SearchService } from '../../search-service/search.service'; import { SearchConfigurationService } from '../../search-service/search-configuration.service'; +import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component'; @Component({ selector: 'ds-search-filter', @@ -46,7 +47,10 @@ export class SearchFilterComponent implements OnInit { */ active$: Observable; - constructor(private filterService: SearchFilterService, private searchService: SearchService, private searchConfigService: SearchConfigurationService) { + constructor( + private filterService: SearchFilterService, + private searchService: SearchService, + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { } /** diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts index 19239d899c..24648c8995 100644 --- a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts @@ -14,6 +14,7 @@ import { SearchFilterConfig } from '../../search-service/search-filter-config.mo import { FilterType } from '../../search-service/filter-type.model'; import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub'; import { of as observableOf } from 'rxjs'; +import { routeServiceStub } from '../../../shared/testing/route-service-stub'; describe('SearchFilterService', () => { let service: SearchFilterService; @@ -34,24 +35,6 @@ describe('SearchFilterService', () => { select: observableOf(true) }); - const routeServiceStub: any = { - /* tslint:disable:no-empty */ - hasQueryParamWithValue: (param: string, value: string) => { - }, - hasQueryParam: (param: string) => { - }, - removeQueryParameterValue: (param: string, value: string) => { - }, - addQueryParameterValue: (param: string, value: string) => { - }, - getQueryParameterValues: (param: string) => { - return observableOf({}); - }, - getQueryParamsWithPrefix: (param: string) => { - return observableOf({}); - } - /* tslint:enable:no-empty */ - }; const activatedRoute: any = new ActivatedRouteStub(); const searchServiceStub: any = { uiSearchRoute: '/search' diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts index 845babd79c..4fc3222600 100644 --- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -19,6 +19,8 @@ import { SearchRangeFilterComponent } from './search-range-filter.component'; import { RouteService } from '../../../../shared/services/route.service'; import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; import { SearchConfigurationService } from '../../../search-service/search-configuration.service'; +import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component'; +import { SearchConfigurationServiceStub } from '../../../../shared/testing/search-configuration-service-stub'; describe('SearchRangeFilterComponent', () => { let comp: SearchRangeFilterComponent; @@ -76,9 +78,7 @@ describe('SearchRangeFilterComponent', () => { { provide: FILTER_CONFIG, useValue: mockFilterConfig }, { provide: RemoteDataBuildService, useValue: {aggregate: () => observableOf({})} }, { provide: RouteService, useValue: {getQueryParameterValue: () => observableOf({})} }, - { provide: SearchConfigurationService, useValue: { - searchOptions: observableOf({}) } - }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SearchFilterService, useValue: { getSelectedValuesForFilter: () => selectedValues, diff --git a/src/app/+search-page/search-filters/search-filters.component.spec.ts b/src/app/+search-page/search-filters/search-filters.component.spec.ts index db21fc8a69..dc883cd290 100644 --- a/src/app/+search-page/search-filters/search-filters.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filters.component.spec.ts @@ -7,13 +7,15 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { SearchFilterService } from './search-filter/search-filter.service'; import { SearchFiltersComponent } from './search-filters.component'; import { SearchService } from '../search-service/search.service'; -import { SearchConfigurationService } from '../search-service/search-configuration.service'; import { of as observableOf } from 'rxjs'; +import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; +import { SearchConfigurationServiceStub } from '../../shared/testing/search-configuration-service-stub'; describe('SearchFiltersComponent', () => { let comp: SearchFiltersComponent; let fixture: ComponentFixture; let searchService: SearchService; + const searchServiceStub = { /* tslint:disable:no-empty */ getConfig: () => @@ -30,17 +32,13 @@ describe('SearchFiltersComponent', () => { [] }; - const searchConfigServiceStub = jasmine.createSpyObj('SearchConfigurationService', { - getCurrentFrontendFilters: observableOf({}) - }); - beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule], declarations: [SearchFiltersComponent], providers: [ { provide: SearchService, useValue: searchServiceStub }, - { provide: SearchConfigurationService, useValue: searchConfigServiceStub }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, { provide: SearchFilterService, useValue: searchFiltersStub }, ], diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index a6612154cf..9c235b2f58 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -40,8 +40,8 @@ export class SearchFiltersComponent implements OnInit { */ constructor( private searchService: SearchService, - @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService, - private filterService: SearchFilterService) { + private filterService: SearchFilterService, + @Inject(SEARCH_CONFIG_SERVICE) private searchConfigService: SearchConfigurationService) { } diff --git a/src/app/+search-page/search-labels/search-labels.component.spec.ts b/src/app/+search-page/search-labels/search-labels.component.spec.ts index 81fa5b5df8..aada73673e 100644 --- a/src/app/+search-page/search-labels/search-labels.component.spec.ts +++ b/src/app/+search-page/search-labels/search-labels.component.spec.ts @@ -10,6 +10,8 @@ import { Observable, of as observableOf } from 'rxjs'; import { Params } from '@angular/router'; import { ObjectKeysPipe } from '../../shared/utils/object-keys-pipe'; import { SearchConfigurationService } from '../search-service/search-configuration.service'; +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; @@ -35,7 +37,8 @@ describe('SearchLabelsComponent', () => { declarations: [SearchLabelsComponent, ObjectKeysPipe], providers: [ { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, - { provide: SearchConfigurationService, useValue: {getCurrentFrontendFilters : () => observableOf({})} } + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() } + // { provide: SearchConfigurationService, useValue: {getCurrentFrontendFilters : () => observableOf({})} } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(SearchLabelsComponent, { diff --git a/src/app/+search-page/search-page.component.spec.ts b/src/app/+search-page/search-page.component.spec.ts index 1991cf8f1b..71d6997420 100644 --- a/src/app/+search-page/search-page.component.spec.ts +++ b/src/app/+search-page/search-page.component.spec.ts @@ -4,7 +4,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { Store } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; -import { cold, hot } from 'jasmine-marbles'; +import { cold } from 'jasmine-marbles'; import { of as observableOf } from 'rxjs'; import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; import { CommunityDataService } from '../core/data/community-data.service'; @@ -20,11 +20,17 @@ import { SearchSidebarService } from './search-sidebar/search-sidebar.service'; import { SearchFilterService } from './search-filters/search-filter/search-filter.service'; 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 { routeServiceStub } from '../shared/testing/route-service-stub'; +import { SearchConfigurationServiceStub } from '../shared/testing/search-configuration-service-stub'; +import { PaginatedSearchOptions } from './paginated-search-options.model'; describe('SearchPageComponent', () => { let comp: SearchPageComponent; let fixture: ComponentFixture; let searchServiceObject: SearchService; + let searchConfigurationServiceObject: SearchConfigurationService; const store: Store = jasmine.createSpyObj('store', { /* tslint:disable:no-empty */ dispatch: {}, @@ -42,15 +48,23 @@ describe('SearchPageComponent', () => { getSearchLink: '/search', getScopes: observableOf(['test-scope']) }); + const configurationParam = 'default'; const queryParam = 'test query'; const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; - const paginatedSearchOptions = { + const paginatedSearchOptions = new PaginatedSearchOptions({ + configuration: configurationParam, query: queryParam, scope: scopeParam, pagination, sort - }; + }); const activatedRouteStub = { + snapshot: { + queryParamMap: new Map([ + ['query', queryParam], + ['scope', scopeParam] + ]) + }, queryParams: observableOf({ query: queryParam, scope: scopeParam @@ -73,6 +87,7 @@ describe('SearchPageComponent', () => { useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll']) }, { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: RouteService, useValue: routeServiceStub }, { provide: Store, useValue: store }, @@ -92,13 +107,8 @@ describe('SearchPageComponent', () => { provide: SearchFilterService, useValue: {} }, { - provide: SearchConfigurationService, - useValue: { - paginatedSearchOptions: hot('a', { - a: paginatedSearchOptions - }), - getCurrentScope: (a) => observableOf('test-id') - } + provide: SEARCH_CONFIG_SERVICE, + useValue: new SearchConfigurationServiceStub() }, ], schemas: [NO_ERRORS_SCHEMA] @@ -112,25 +122,21 @@ describe('SearchPageComponent', () => { comp = fixture.componentInstance; // SearchPageComponent test instance fixture.detectChanges(); searchServiceObject = (comp as any).service; + searchConfigurationServiceObject = (comp as any).searchConfigService; + }); + + afterEach(() => { + comp = null; + searchServiceObject = null; + searchConfigurationServiceObject = null; }); it('should get the scope and query from the route parameters', () => { + + searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions); expect(comp.searchOptions$).toBeObservable(cold('b', { b: paginatedSearchOptions })); - }); - - describe('when the closeSidebar event is emitted clicked in mobile view', () => { - - beforeEach(() => { - spyOn(comp, 'closeSidebar'); - const closeSidebarButton = fixture.debugElement.query(By.css('#search-sidebar-sm')); - closeSidebarButton.triggerEventHandler('toggleSidebar', null); - }); - - it('should trigger the closeSidebar function', () => { - expect(comp.closeSidebar).toHaveBeenCalled(); - }); }); @@ -177,4 +183,4 @@ describe('SearchPageComponent', () => { }); }); -}) +}); diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 333faacc47..610811981c 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -53,7 +53,7 @@ export class SearchPageComponent implements OnInit { /** * The current relevant scopes */ - scopeListRD$: Observable; + scopeListRD$: Observable = new BehaviorSubject(null); /** * Emits true if were on a small screen @@ -86,9 +86,9 @@ export class SearchPageComponent implements OnInit { .subscribe((results) => { this.resultsRD$.next(results); }); - this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( +/* this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( switchMap((scopeId) => this.service.getScopes(scopeId)) - ); + );*/ } /** diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts index 380bace080..39f1919f72 100644 --- a/src/app/+search-page/search-service/search-configuration.service.ts +++ b/src/app/+search-page/search-service/search-configuration.service.ts @@ -87,8 +87,8 @@ export class SearchConfigurationService implements OnDestroy { .pipe(getSucceededRemoteData()) .subscribe((defRD) => { const defs = defRD.payload; - this.paginatedSearchOptions = new BehaviorSubject(defs); - this.searchOptions = new BehaviorSubject(defs); + this.paginatedSearchOptions = new BehaviorSubject(defs); + this.searchOptions = new BehaviorSubject(defs); this.subs.push(this.subscribeToSearchOptions(defs)); this.subs.push(this.subscribeToPaginatedSearchOptions(defs)); @@ -129,7 +129,7 @@ export class SearchConfigurationService implements OnDestroy { */ getCurrentDSOType(): Observable { return this.routeService.getQueryParameterValue('dsoType').pipe( - filter((type) => hasValue(type) && hasValue(DSpaceObjectType[type.toUpperCase()])), + filter((type) => isNotEmpty(type) && hasValue(DSpaceObjectType[type.toUpperCase()])), map((type) => DSpaceObjectType[type.toUpperCase()]),); } diff --git a/src/app/+search-page/search-service/search.service.spec.ts b/src/app/+search-page/search-service/search.service.spec.ts index ca48b02aa7..b188dc35b8 100644 --- a/src/app/+search-page/search-service/search.service.spec.ts +++ b/src/app/+search-page/search-service/search.service.spec.ts @@ -6,27 +6,25 @@ import { Component } from '@angular/core'; import { SearchService } from './search.service'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; -import { ActivatedRoute, Router, UrlTree } from '@angular/router'; +import { Router, UrlTree } from '@angular/router'; import { RequestService } from '../../core/data/request.service'; import { ActivatedRouteStub } from '../../shared/testing/active-router-stub'; import { RouterStub } from '../../shared/testing/router-stub'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; -import { Observable, combineLatest as observableCombineLatest } from 'rxjs'; +import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; import { PaginatedSearchOptions } from '../paginated-search-options.model'; import { RemoteData } from '../../core/data/remote-data'; import { RequestEntry } from '../../core/data/request.reducer'; import { getMockRequestService } from '../../shared/mocks/mock-request.service'; -import { - FacetConfigSuccessResponse, - SearchSuccessResponse -} from '../../core/cache/response.models'; +import { FacetConfigSuccessResponse, SearchSuccessResponse } from '../../core/cache/response.models'; import { SearchQueryResponse } from './search-query-response.model'; import { SearchFilterConfig } from './search-filter-config.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 { of as observableOf } from 'rxjs'; import { map } from 'rxjs/operators'; +import { RouteService } from '../../shared/services/route.service'; +import { routeServiceStub } from '../../shared/testing/route-service-stub'; @Component({ template: '' }) class DummyComponent { @@ -50,7 +48,7 @@ describe('SearchService', () => { ], providers: [ { provide: Router, useValue: router }, - { provide: ActivatedRoute, useValue: route }, + { provide: RouteService, useValue: routeServiceStub }, { provide: RequestService, useValue: getMockRequestService() }, { provide: RemoteDataBuildService, useValue: {} }, { provide: HALEndpointService, useValue: {} }, @@ -71,7 +69,7 @@ describe('SearchService', () => { describe('', () => { let searchService: SearchService; const router = new RouterStub(); - const route = new ActivatedRouteStub(); + let routeService; const halService = { /* tslint:disable:no-empty */ @@ -107,7 +105,7 @@ describe('SearchService', () => { ], providers: [ { provide: Router, useValue: router }, - { provide: ActivatedRoute, useValue: route }, + { provide: RouteService, useValue: routeServiceStub }, { provide: RequestService, useValue: getMockRequestService() }, { provide: RemoteDataBuildService, useValue: remoteDataBuildService }, { provide: HALEndpointService, useValue: halService }, @@ -117,6 +115,7 @@ describe('SearchService', () => { ], }); searchService = TestBed.get(SearchService); + routeService = TestBed.get(RouteService); const urlTree = Object.assign(new UrlTree(), { root: { children: { primary: 'search' } } }); router.parseUrl.and.returnValue(urlTree); }); @@ -139,14 +138,19 @@ describe('SearchService', () => { it('should return ViewMode.List when the viewMode is set to ViewMode.List in the ActivatedRoute', () => { let viewMode = ViewMode.Grid; - route.testParams = { view: ViewMode.List }; + spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ + [ 'view', ViewMode.List ], + ]))); + searchService.getViewMode().subscribe((mode) => viewMode = mode); expect(viewMode).toEqual(ViewMode.List); }); it('should return ViewMode.Grid when the viewMode is set to ViewMode.Grid in the ActivatedRoute', () => { let viewMode = ViewMode.List; - route.testParams = { view: ViewMode.Grid }; + spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ + [ 'view', ViewMode.Grid ], + ]))); searchService.getViewMode().subscribe((mode) => viewMode = mode); expect(viewMode).toEqual(ViewMode.Grid); }); diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 361f08b724..ed19f1df68 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -74,7 +74,6 @@ export class SearchService implements OnDestroy { private sub; constructor(private router: Router, - private route: ActivatedRoute, private routeService: RouteService, protected requestService: RequestService, private rdb: RemoteDataBuildService, diff --git a/src/app/+search-page/search-settings/search-settings.component.spec.ts b/src/app/+search-page/search-settings/search-settings.component.spec.ts index b1585c4347..b9b5c5a5eb 100644 --- a/src/app/+search-page/search-settings/search-settings.component.spec.ts +++ b/src/app/+search-page/search-settings/search-settings.component.spec.ts @@ -14,8 +14,8 @@ import { By } from '@angular/platform-browser'; import { SearchFilterService } from '../search-filters/search-filter/search-filter.service'; import { hot } from 'jasmine-marbles'; import { VarDirective } from '../../shared/utils/var.directive'; -import { SearchConfigurationService } from '../search-service/search-configuration.service'; import { first } from 'rxjs/operators'; +import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; describe('SearchSettingsComponent', () => { @@ -73,7 +73,7 @@ describe('SearchSettingsComponent', () => { useValue: {} }, { - provide: SearchConfigurationService, + provide: SEARCH_CONFIG_SERVICE, useValue: { paginatedSearchOptions: hot('a', { a: paginatedSearchOptions diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts index ff4948caa0..5e01494674 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts @@ -228,8 +228,8 @@ describe('AuthNavMenuComponent', () => { fixture.destroy(); component = null; }); - it('should render logout dropdown menu', () => { - const logoutDropdownMenu = deNavMenuItem.query(By.css('ul[id=logoutDropdownMenu]')); + it('should render UserMenuComponent component', () => { + const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-user-menu')); expect(logoutDropdownMenu.nativeElement).toBeDefined(); }); }) diff --git a/src/app/shared/mocks/mock-router.ts b/src/app/shared/mocks/mock-router.ts index 9ebe321cf6..f1357104b4 100644 --- a/src/app/shared/mocks/mock-router.ts +++ b/src/app/shared/mocks/mock-router.ts @@ -4,7 +4,10 @@ export class MockRouter { public events = observableOf({}); public routerState = { snapshot: { - url: '' + url: '', + root: { + queryParamMap: null + } } }; @@ -15,4 +18,8 @@ export class MockRouter { setRoute(route) { this.routerState.snapshot.url = route; } + + setParams(paramsMap) { + this.routerState.snapshot.root.queryParamMap = paramsMap; + } } diff --git a/src/app/shared/pagination/pagination.component.spec.ts b/src/app/shared/pagination/pagination.component.spec.ts index 7b340b2eed..dfbef9123a 100644 --- a/src/app/shared/pagination/pagination.component.spec.ts +++ b/src/app/shared/pagination/pagination.component.spec.ts @@ -262,7 +262,7 @@ describe('Pagination component', () => { changePage(testFixture, 3); tick(); - expect(routerStub.navigate).toHaveBeenCalledWith([], { queryParams: { pageId: 'test', page: 3, pageSize: 10, sortDirection: 'ASC', sortField: 'dc.title' }, queryParamsHandling: 'merge' }); + expect(routerStub.navigate).toHaveBeenCalledWith([], { queryParams: { pageId: 'test', page: '3', pageSize: 10, sortDirection: 'ASC', sortField: 'dc.title' }, queryParamsHandling: 'merge' }); })); diff --git a/src/app/shared/services/route.service.spec.ts b/src/app/shared/services/route.service.spec.ts index 7d249cb12a..c9b3710ee6 100644 --- a/src/app/shared/services/route.service.spec.ts +++ b/src/app/shared/services/route.service.spec.ts @@ -29,6 +29,9 @@ describe('RouteService', () => { select: jasmine.createSpy('select') }); + const router = new MockRouter(); + router.setParams(convertToParamMap(paramObject)); + paramObject[paramName1] = paramValue1; paramObject[paramName2] = [paramValue2a, paramValue2b]; @@ -42,7 +45,7 @@ describe('RouteService', () => { queryParamMap: observableOf(convertToParamMap(paramObject)) }, }, - { provide: Router, useValue: new MockRouter() }, + { provide: Router, useValue: router }, { provide: Store, useValue: store }, ] }); diff --git a/src/app/shared/testing/route-service-stub.ts b/src/app/shared/testing/route-service-stub.ts new file mode 100644 index 0000000000..e872d0703b --- /dev/null +++ b/src/app/shared/testing/route-service-stub.ts @@ -0,0 +1,26 @@ +import { of as observableOf } from 'rxjs/internal/observable/of'; + +export const routeServiceStub: any = { + /* tslint:disable:no-empty */ + hasQueryParamWithValue: (param: string, value: string) => { + }, + hasQueryParam: (param: string) => { + }, + removeQueryParameterValue: (param: string, value: string) => { + }, + addQueryParameterValue: (param: string, value: string) => { + }, + getQueryParameterValues: (param: string) => { + return observableOf({}); + }, + getQueryParamsWithPrefix: (param: string) => { + return observableOf({}); + }, + getQueryParamMap: () => { + return observableOf(new Map()) + }, + getQueryParameterValue: () => { + return observableOf({}) + } + /* tslint:enable:no-empty */ +}; diff --git a/src/app/shared/testing/search-configuration-service-stub.ts b/src/app/shared/testing/search-configuration-service-stub.ts new file mode 100644 index 0000000000..4c9d94c877 --- /dev/null +++ b/src/app/shared/testing/search-configuration-service-stub.ts @@ -0,0 +1,16 @@ +import { BehaviorSubject, of as observableOf } from 'rxjs'; + +export class SearchConfigurationServiceStub { + + private searchOptions: BehaviorSubject = new BehaviorSubject({}); + private paginatedSearchOptions: BehaviorSubject = new BehaviorSubject({}); + + getCurrentFrontendFilters() { + return observableOf([]); + } + + getCurrentScope(a) { + return observableOf('test-id') + } + +} From 237100a9cf6dab6530f269f564a52dc3d4186a52 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 27 Mar 2019 16:01:49 +0100 Subject: [PATCH 17/70] fixed after merge --- src/app/+my-dspace-page/my-dspace-page.component.ts | 2 +- src/app/+search-page/search-page.component.ts | 6 +++--- src/app/core/data/request.service.spec.ts | 2 +- .../workspaceitem/workspaceitem-actions.component.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-page.component.ts b/src/app/+my-dspace-page/my-dspace-page.component.ts index a173a39d99..712a25b0c0 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.ts @@ -67,7 +67,7 @@ export class MyDSpacePageComponent implements OnInit { /** * The current relevant scopes */ - scopeListRD$: Observable; + scopeListRD$: Observable = new BehaviorSubject([]); /** * Emits true if were on a small screen diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 610811981c..b2a5b9a6eb 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -53,7 +53,7 @@ export class SearchPageComponent implements OnInit { /** * The current relevant scopes */ - scopeListRD$: Observable = new BehaviorSubject(null); + scopeListRD$: Observable = new BehaviorSubject([]); /** * Emits true if were on a small screen @@ -86,9 +86,9 @@ export class SearchPageComponent implements OnInit { .subscribe((results) => { this.resultsRD$.next(results); }); -/* this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( + this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( switchMap((scopeId) => this.service.getScopes(scopeId)) - );*/ + ); } /** diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index b83481fb24..9cce2509ef 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -1,7 +1,7 @@ import * as ngrx from '@ngrx/store'; import { ActionsSubject, Store } from '@ngrx/store'; import { cold, getTestScheduler, hot } from 'jasmine-marbles'; -import { EMPTY, of as observableOf } from 'rxjs'; +import { BehaviorSubject, EMPTY, of as observableOf } from 'rxjs'; import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service'; import { defaultUUID, getMockUUIDService } from '../../shared/mocks/mock-uuid.service'; import { ObjectCacheService } from '../cache/object-cache.service'; diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts index 05eee97d2a..c05eb557d2 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts @@ -7,7 +7,7 @@ import { TranslateService } from '@ngx-translate/core'; import { Workspaceitem } from '../../../core/submission/models/workspaceitem.model'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; -import { SubmissionRestService } from '../../../submission/submission-rest.service'; +import { SubmissionRestService } from '../../../core/submission/submission-rest.service'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; import { ResourceType } from '../../../core/shared/resource-type'; import { NotificationsService } from '../../notifications/notifications.service'; From 96bb4e9bb4fef079dda61970ec703852deef802e Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 27 Mar 2019 16:04:00 +0100 Subject: [PATCH 18/70] Removed wrong initialization --- src/app/+my-dspace-page/my-dspace-page.component.ts | 2 +- src/app/+search-page/search-page.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-page.component.ts b/src/app/+my-dspace-page/my-dspace-page.component.ts index 712a25b0c0..a173a39d99 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.ts @@ -67,7 +67,7 @@ export class MyDSpacePageComponent implements OnInit { /** * The current relevant scopes */ - scopeListRD$: Observable = new BehaviorSubject([]); + scopeListRD$: Observable; /** * Emits true if were on a small screen diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index b2a5b9a6eb..333faacc47 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -53,7 +53,7 @@ export class SearchPageComponent implements OnInit { /** * The current relevant scopes */ - scopeListRD$: Observable = new BehaviorSubject([]); + scopeListRD$: Observable; /** * Emits true if were on a small screen From c44216652254920f157f2bf9501823719ef8921b Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 10:14:01 +0100 Subject: [PATCH 19/70] Added tests --- .../my-dspace-configuration.service.spec.ts | 253 ++++++++++++++++++ .../my-dspace-configuration.service.ts | 6 +- .../my-dspace-page.component.html | 2 +- .../my-dspace-page.component.spec.ts | 194 ++++++++++++++ .../my-dspace-results.component.spec.ts | 58 ++++ src/app/+my-dspace-page/my-dspace.guard.ts | 11 +- .../search-configuration.service.spec.ts | 15 ++ src/app/shared/mocks/mock-role-service.ts | 51 ++++ 8 files changed, 583 insertions(+), 7 deletions(-) create mode 100644 src/app/+my-dspace-page/my-dspace-configuration.service.spec.ts create mode 100644 src/app/+my-dspace-page/my-dspace-page.component.spec.ts create mode 100644 src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts create mode 100644 src/app/shared/mocks/mock-role-service.ts diff --git a/src/app/+my-dspace-page/my-dspace-configuration.service.spec.ts b/src/app/+my-dspace-page/my-dspace-configuration.service.spec.ts new file mode 100644 index 0000000000..84909777c4 --- /dev/null +++ b/src/app/+my-dspace-page/my-dspace-configuration.service.spec.ts @@ -0,0 +1,253 @@ +import { of as observableOf } from 'rxjs'; + +import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; +import { PaginatedSearchOptions } from '../+search-page/paginated-search-options.model'; +import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; +import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; +import { SearchFilter } from '../+search-page/search-filter.model'; +import { ActivatedRouteStub } from '../shared/testing/active-router-stub'; +import { MockRoleService } from '../shared/mocks/mock-role-service'; +import { cold, hot } from 'jasmine-marbles'; +import { MyDSpaceConfigurationValueType } from './my-dspace-configuration-value-type'; + +describe('MyDSpaceConfigurationService', () => { + let service: MyDSpaceConfigurationService; + const value1 = 'random value'; + const prefixFilter = { + 'f.namedresourcetype': ['another value'], + 'f.dateSubmitted.min': ['2013'], + 'f.dateSubmitted.max': ['2018'] + }; + const defaults = new PaginatedSearchOptions({ + pagination: Object.assign(new PaginationComponentOptions(), { currentPage: 1, pageSize: 20 }), + sort: new SortOptions('score', SortDirection.DESC), + query: '', + scope: '' + }); + + const backendFilters = [new SearchFilter('f.namedresourcetype', ['another value']), new SearchFilter('f.dateSubmitted', ['[2013 TO 2018]'])]; + + const spy = jasmine.createSpyObj('RouteService', { + getQueryParameterValue: observableOf(value1), + getQueryParamsWithPrefix: observableOf(prefixFilter) + }); + + const activatedRoute: any = new ActivatedRouteStub(); + + const roleService: any = new MockRoleService(); + + beforeEach(() => { + service = new MyDSpaceConfigurationService(roleService, spy, activatedRoute); + }); + + describe('when the scope is called', () => { + beforeEach(() => { + service.getCurrentScope(''); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'scope\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('scope'); + }); + }); + + describe('when getCurrentConfiguration is called', () => { + beforeEach(() => { + service.getCurrentConfiguration(''); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'configuration\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('configuration'); + }); + }); + + describe('when getCurrentQuery is called', () => { + beforeEach(() => { + service.getCurrentQuery(''); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'query\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('query'); + }); + }); + + describe('when getCurrentDSOType is called', () => { + beforeEach(() => { + service.getCurrentDSOType(); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'dsoType\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('dsoType'); + }); + }); + + describe('when getCurrentFrontendFilters is called', () => { + beforeEach(() => { + service.getCurrentFrontendFilters(); + }); + it('should call getQueryParamsWithPrefix on the routeService with parameter prefix \'f.\'', () => { + expect((service as any).routeService.getQueryParamsWithPrefix).toHaveBeenCalledWith('f.'); + }); + }); + + describe('when getCurrentFilters is called', () => { + let parsedValues$; + beforeEach(() => { + parsedValues$ = service.getCurrentFilters(); + }); + it('should call getQueryParamsWithPrefix on the routeService with parameter prefix \'f.\'', () => { + expect((service as any).routeService.getQueryParamsWithPrefix).toHaveBeenCalledWith('f.'); + parsedValues$.subscribe((values) => { + expect(values).toEqual(backendFilters); + }); + }); + }); + + describe('when getCurrentSort is called', () => { + beforeEach(() => { + service.getCurrentSort({} as any); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'sortDirection\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('sortDirection'); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'sortField\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('sortField'); + }); + }); + + describe('when getCurrentPagination is called', () => { + beforeEach(() => { + service.getCurrentPagination({ currentPage: 1, pageSize: 10 } as any); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'page\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('page'); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'pageSize\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('pageSize'); + }); + }); + + describe('when subscribeToSearchOptions or subscribeToPaginatedSearchOptions is called', () => { + beforeEach(() => { + spyOn(service, 'getCurrentPagination').and.callThrough(); + spyOn(service, 'getCurrentSort').and.callThrough(); + spyOn(service, 'getCurrentScope').and.callThrough(); + spyOn(service, 'getCurrentConfiguration').and.callThrough(); + spyOn(service, 'getCurrentQuery').and.callThrough(); + spyOn(service, 'getCurrentDSOType').and.callThrough(); + spyOn(service, 'getCurrentFilters').and.callThrough(); + }); + + describe('when subscribeToSearchOptions is called', () => { + beforeEach(() => { + (service as any).subscribeToSearchOptions(defaults) + }); + it('should call all getters it needs, but not call any others', () => { + expect(service.getCurrentPagination).not.toHaveBeenCalled(); + expect(service.getCurrentSort).not.toHaveBeenCalled(); + expect(service.getCurrentScope).toHaveBeenCalled(); + expect(service.getCurrentConfiguration).toHaveBeenCalled(); + expect(service.getCurrentQuery).toHaveBeenCalled(); + expect(service.getCurrentDSOType).toHaveBeenCalled(); + expect(service.getCurrentFilters).toHaveBeenCalled(); + }); + }); + + describe('when subscribeToPaginatedSearchOptions is called', () => { + beforeEach(() => { + (service as any).subscribeToPaginatedSearchOptions(defaults); + }); + it('should call all getters it needs', () => { + expect(service.getCurrentPagination).toHaveBeenCalled(); + expect(service.getCurrentSort).toHaveBeenCalled(); + expect(service.getCurrentScope).toHaveBeenCalled(); + expect(service.getCurrentConfiguration).toHaveBeenCalled(); + expect(service.getCurrentQuery).toHaveBeenCalled(); + expect(service.getCurrentDSOType).toHaveBeenCalled(); + expect(service.getCurrentFilters).toHaveBeenCalled(); + }); + }); + }); + + describe('when getAvailableConfigurationTypes is called', () => { + + it('should return properly list when user is submitter', () => { + roleService.setSubmitter(true); + roleService.setController(false); + roleService.setAdmin(false); + + const list$ = service.getAvailableConfigurationTypes(); + + expect(list$).toBeObservable(cold('(b|)', { + b: [ + MyDSpaceConfigurationValueType.Workspace + ] + })); + }); + + it('should return properly list when user is controller', () => { + roleService.setSubmitter(false); + roleService.setController(true); + roleService.setAdmin(false); + + const list$ = service.getAvailableConfigurationTypes(); + + expect(list$).toBeObservable(cold('(b|)', { + b: [ + MyDSpaceConfigurationValueType.Workflow + ] + })); + }); + + it('should return properly list when user is admin', () => { + roleService.setSubmitter(false); + roleService.setController(false); + roleService.setAdmin(true); + + const list$ = service.getAvailableConfigurationTypes(); + + expect(list$).toBeObservable(cold('(b|)', { + b: [ + MyDSpaceConfigurationValueType.Workflow + ] + })); + }); + + it('should return properly list when user is submitter and controller', () => { + roleService.setSubmitter(true); + roleService.setController(true); + roleService.setAdmin(false); + + const list$ = service.getAvailableConfigurationTypes(); + + expect(list$).toBeObservable(cold('(b|)', { + b: [ + MyDSpaceConfigurationValueType.Workspace, + MyDSpaceConfigurationValueType.Workflow + ] + })); + }); + }); + + describe('when getAvailableConfigurationOptions is called', () => { + + it('should return properly options list', () => { + spyOn(service, 'getAvailableConfigurationTypes').and.returnValue(hot('a', { + a: [ + MyDSpaceConfigurationValueType.Workspace, + MyDSpaceConfigurationValueType.Workflow + ] + })); + + const list$ = service.getAvailableConfigurationOptions(); + + expect(list$).toBeObservable(cold('(b|)', { + b: [ + { + value: MyDSpaceConfigurationValueType.Workspace, + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workspace}` + }, + { + value: MyDSpaceConfigurationValueType.Workflow, + label: `mydspace.show.${MyDSpaceConfigurationValueType.Workflow}` + } + ] + })); + }); + }); +}); diff --git a/src/app/+my-dspace-page/my-dspace-configuration.service.ts b/src/app/+my-dspace-page/my-dspace-configuration.service.ts index a580ba9920..c5c37ae367 100644 --- a/src/app/+my-dspace-page/my-dspace-configuration.service.ts +++ b/src/app/+my-dspace-page/my-dspace-configuration.service.ts @@ -13,7 +13,7 @@ import { PaginationComponentOptions } from '../shared/pagination/pagination-comp import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; /** - * Service that performs all actions that have to do with the current search configuration + * Service that performs all actions that have to do with the current mydspace configuration */ @Injectable() export class MyDSpaceConfigurationService extends SearchConfigurationService { @@ -97,8 +97,4 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { ) } - public getCurrentView(): Observable { - return this.routeService.getQueryParameterValue('view'); - } - } diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html index b38edebd97..80b52a273c 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.html +++ b/src/app/+my-dspace-page/my-dspace-page.component.html @@ -3,7 +3,7 @@ (uploadEnd)="reload($event)">
    diff --git a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts new file mode 100644 index 0000000000..34053af3b9 --- /dev/null +++ b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts @@ -0,0 +1,194 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ActivatedRoute } from '@angular/router'; +import { By } from '@angular/platform-browser'; +import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { Store } from '@ngrx/store'; +import { TranslateModule } from '@ngx-translate/core'; +import { cold } from 'jasmine-marbles'; +import { of as observableOf } from 'rxjs'; + +import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; +import { CommunityDataService } from '../core/data/community-data.service'; +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 { 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'; +import { SearchConfigurationService } from '../+search-page/search-service/search-configuration.service'; +import { PaginatedSearchOptions } from '../+search-page/paginated-search-options.model'; +import { SearchSidebarService } from '../+search-page/search-sidebar/search-sidebar.service'; +import { SearchFilterService } from '../+search-page/search-filters/search-filter/search-filter.service'; +import { RoleDirective } from '../shared/roles/role.directive'; +import { RoleService } from '../core/roles/role.service'; +import { MockRoleService } from '../shared/mocks/mock-role-service'; + +describe('MyDSpacePageComponent', () => { + let comp: MyDSpacePageComponent; + let fixture: ComponentFixture; + let searchServiceObject: SearchService; + let searchConfigurationServiceObject: SearchConfigurationService; + const store: Store = jasmine.createSpyObj('store', { + /* tslint:disable:no-empty */ + dispatch: {}, + /* tslint:enable:no-empty */ + select: observableOf(true) + }); + const pagination: PaginationComponentOptions = new PaginationComponentOptions(); + pagination.id = 'mydspace-results-pagination'; + pagination.currentPage = 1; + pagination.pageSize = 10; + const sort: SortOptions = new SortOptions('score', SortDirection.DESC); + const mockResults = observableOf(new RemoteData(false, false, true, null, ['test', 'data'])); + const searchServiceStub = jasmine.createSpyObj('SearchService', { + search: mockResults, + getSearchLink: '/mydspace', + getScopes: observableOf(['test-scope']), + setServiceOptions: {} + }); + const configurationParam = 'default'; + const queryParam = 'test query'; + const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; + const paginatedSearchOptions = new PaginatedSearchOptions({ + configuration: configurationParam, + query: queryParam, + scope: scopeParam, + pagination, + sort + }); + const activatedRouteStub = { + snapshot: { + queryParamMap: new Map([ + ['query', queryParam], + ['scope', scopeParam] + ]) + }, + queryParams: observableOf({ + query: queryParam, + scope: scopeParam + }) + }; + const sidebarService = { + isCollapsed: observableOf(true), + collapse: () => this.isCollapsed = observableOf(true), + expand: () => this.isCollapsed = observableOf(false) + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NoopAnimationsModule, NgbCollapseModule.forRoot()], + declarations: [MyDSpacePageComponent, RoleDirective], + providers: [ + { provide: SearchService, useValue: searchServiceStub }, + { + provide: CommunityDataService, + useValue: jasmine.createSpyObj('communityService', ['findById', 'findAll']) + }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: RouteService, useValue: routeServiceStub }, + { + provide: Store, useValue: store + }, + { + provide: HostWindowService, useValue: jasmine.createSpyObj('hostWindowService', + { + isXs: observableOf(true), + isSm: observableOf(false), + isXsOrSm: observableOf(true) + }) + }, + { + provide: SearchSidebarService, + useValue: sidebarService + }, + { + provide: SearchFilterService, + useValue: {} + }, { + provide: SEARCH_CONFIG_SERVICE, + useValue: new SearchConfigurationServiceStub() + }, + { + provide: RoleService, + useValue: new MockRoleService() + } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(MyDSpacePageComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MyDSpacePageComponent); + comp = fixture.componentInstance; // SearchPageComponent test instance + fixture.detectChanges(); + searchServiceObject = (comp as any).service; + searchConfigurationServiceObject = (comp as any).searchConfigService; + }); + + afterEach(() => { + comp = null; + searchServiceObject = null; + searchConfigurationServiceObject = null; + }); + + it('should get the scope and query from the route parameters', () => { + + searchConfigurationServiceObject.paginatedSearchOptions.next(paginatedSearchOptions); + expect(comp.searchOptions$).toBeObservable(cold('b', { + b: paginatedSearchOptions + })); + + }); + + describe('when the open sidebar button is clicked in mobile view', () => { + + beforeEach(() => { + spyOn(comp, 'openSidebar'); + const openSidebarButton = fixture.debugElement.query(By.css('.open-sidebar')); + openSidebarButton.triggerEventHandler('click', null); + }); + + it('should trigger the openSidebar function', () => { + expect(comp.openSidebar).toHaveBeenCalled(); + }); + + }); + + describe('when sidebarCollapsed is true in mobile view', () => { + let menu: HTMLElement; + + beforeEach(() => { + menu = fixture.debugElement.query(By.css('#mydspace-sidebar-sm')).nativeElement; + comp.isSidebarCollapsed = () => observableOf(true); + fixture.detectChanges(); + }); + + it('should close the sidebar', () => { + expect(menu.classList).not.toContain('active'); + }); + + }); + + describe('when sidebarCollapsed is false in mobile view', () => { + let menu: HTMLElement; + + beforeEach(() => { + menu = fixture.debugElement.query(By.css('#mydspace-sidebar-sm')).nativeElement; + comp.isSidebarCollapsed = () => observableOf(false); + fixture.detectChanges(); + }); + + it('should open the menu', () => { + expect(menu.classList).toContain('active'); + }); + + }); +}); diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts new file mode 100644 index 0000000000..67625706a6 --- /dev/null +++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.spec.ts @@ -0,0 +1,58 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; + +import { TranslateModule } from '@ngx-translate/core'; +import { QueryParamsDirectiveStub } from '../../shared/testing/query-params-directive-stub'; +import { MyDSpaceResultsComponent } from './my-dspace-results.component'; + +describe('MyDSpaceResultsComponent', () => { + let comp: MyDSpaceResultsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), NoopAnimationsModule], + declarations: [ + MyDSpaceResultsComponent, + QueryParamsDirectiveStub], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MyDSpaceResultsComponent); + comp = fixture.componentInstance; // MyDSpaceResultsComponent test instance + }); + + it('should display results when results are not empty', () => { + (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; + (comp as any).searchConfig = {}; + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).not.toBeNull(); + }); + + it('should not display link when results are not empty', () => { + (comp as any).searchResults = { hasSucceeded: true, isLoading: false, payload: { page: { length: 2 } } }; + (comp as any).searchConfig = {}; + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('a'))).toBeNull(); + }); + + it('should display error message if error is != 400', () => { + (comp as any).searchResults = { hasFailed: true, error: { statusCode: 500 } }; + fixture.detectChanges(); + expect(fixture.debugElement.query(By.css('ds-error'))).not.toBeNull(); + }); + + it('should display a message if search result is empty', () => { + (comp as any).searchResults = { payload: { page: { length: 0 } } }; + (comp as any).searchConfig = { query: 'foobar' }; + fixture.detectChanges(); + + const linkDes = fixture.debugElement.queryAll(By.css('text-muted')); + + expect(linkDes).toBeDefined() + }); +}); diff --git a/src/app/+my-dspace-page/my-dspace.guard.ts b/src/app/+my-dspace-page/my-dspace.guard.ts index c8cea6b272..9cb9aff485 100644 --- a/src/app/+my-dspace-page/my-dspace.guard.ts +++ b/src/app/+my-dspace-page/my-dspace.guard.ts @@ -22,7 +22,7 @@ export class MyDSpaceGuard implements CanActivate { } /** - * True when user is authenticated + * True when configuration is valid * @method canActivate */ canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { @@ -31,6 +31,15 @@ export class MyDSpaceGuard implements CanActivate { map((configurationList) => this.validateConfigurationParam(route.queryParamMap.get('configuration'), configurationList))); } + /** + * Check if the given configuration is present in the list of those available + * + * @param configuration + * the configuration to validate + * @param configurationList + * the list of available configuration + * + */ private validateConfigurationParam(configuration: string, configurationList: MyDSpaceConfigurationValueType[]): boolean { const configurationDefault: string = configurationList[0]; if (isEmpty(configuration) || !configurationList.includes(configuration as MyDSpaceConfigurationValueType)) { diff --git a/src/app/+search-page/search-service/search-configuration.service.spec.ts b/src/app/+search-page/search-service/search-configuration.service.spec.ts index f1f4ef8bdc..f695bf268b 100644 --- a/src/app/+search-page/search-service/search-configuration.service.spec.ts +++ b/src/app/+search-page/search-service/search-configuration.service.spec.ts @@ -17,6 +17,7 @@ describe('SearchConfigurationService', () => { const defaults = new PaginatedSearchOptions({ pagination: Object.assign(new PaginationComponentOptions(), { currentPage: 1, pageSize: 20 }), sort: new SortOptions('score', SortDirection.DESC), + configuration: 'default', query: '', scope: '' }); @@ -43,6 +44,15 @@ describe('SearchConfigurationService', () => { }); }); + describe('when getCurrentConfiguration is called', () => { + beforeEach(() => { + service.getCurrentConfiguration(''); + }); + it('should call getQueryParameterValue on the routeService with parameter name \'configuration\'', () => { + expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('configuration'); + }); + }); + describe('when getCurrentQuery is called', () => { beforeEach(() => { service.getCurrentQuery(''); @@ -94,6 +104,7 @@ describe('SearchConfigurationService', () => { expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('sortField'); }); }); + describe('when getCurrentPagination is called', () => { beforeEach(() => { service.getCurrentPagination({ currentPage: 1, pageSize: 10 } as any); @@ -105,11 +116,13 @@ describe('SearchConfigurationService', () => { expect((service as any).routeService.getQueryParameterValue).toHaveBeenCalledWith('pageSize'); }); }); + describe('when subscribeToSearchOptions or subscribeToPaginatedSearchOptions is called', () => { beforeEach(() => { spyOn(service, 'getCurrentPagination').and.callThrough(); spyOn(service, 'getCurrentSort').and.callThrough(); spyOn(service, 'getCurrentScope').and.callThrough(); + spyOn(service, 'getCurrentConfiguration').and.callThrough(); spyOn(service, 'getCurrentQuery').and.callThrough(); spyOn(service, 'getCurrentDSOType').and.callThrough(); spyOn(service, 'getCurrentFilters').and.callThrough(); @@ -123,6 +136,7 @@ describe('SearchConfigurationService', () => { expect(service.getCurrentPagination).not.toHaveBeenCalled(); expect(service.getCurrentSort).not.toHaveBeenCalled(); expect(service.getCurrentScope).toHaveBeenCalled(); + expect(service.getCurrentConfiguration).toHaveBeenCalled(); expect(service.getCurrentQuery).toHaveBeenCalled(); expect(service.getCurrentDSOType).toHaveBeenCalled(); expect(service.getCurrentFilters).toHaveBeenCalled(); @@ -137,6 +151,7 @@ describe('SearchConfigurationService', () => { expect(service.getCurrentPagination).toHaveBeenCalled(); expect(service.getCurrentSort).toHaveBeenCalled(); expect(service.getCurrentScope).toHaveBeenCalled(); + expect(service.getCurrentConfiguration).toHaveBeenCalled(); expect(service.getCurrentQuery).toHaveBeenCalled(); expect(service.getCurrentDSOType).toHaveBeenCalled(); expect(service.getCurrentFilters).toHaveBeenCalled(); diff --git a/src/app/shared/mocks/mock-role-service.ts b/src/app/shared/mocks/mock-role-service.ts new file mode 100644 index 0000000000..dad296f986 --- /dev/null +++ b/src/app/shared/mocks/mock-role-service.ts @@ -0,0 +1,51 @@ +import { Observable } from 'rxjs/internal/Observable'; +import { RoleType } from '../../core/roles/role-types'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; + +export class MockRoleService { + + _isSubmitter = new BehaviorSubject(true); + _isController = new BehaviorSubject(true); + _isAdmin = new BehaviorSubject(true); + + setSubmitter(isSubmitter: boolean) { + this._isSubmitter.next(isSubmitter); + } + + setController(isController: boolean) { + this._isController.next(isController); + } + + setAdmin(isAdmin: boolean) { + this._isAdmin.next(isAdmin); + } + + isSubmitter(): Observable { + return this._isSubmitter; + } + + isController(): Observable { + return this._isController; + } + + isAdmin(): Observable { + return this._isAdmin; + } + + checkRole(role: RoleType): Observable { + let check: Observable; + switch (role) { + case RoleType.Submitter: + check = this.isSubmitter(); + break; + case RoleType.Controller: + check = this.isController(); + break; + case RoleType.Admin: + check = this.isAdmin(); + break; + } + + return check; + } +} From eeea331748266fd252105392e147add2d1086a46 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 13:23:01 +0100 Subject: [PATCH 20/70] Fixed issue with initialization of child class --- .../my-dspace-configuration.service.ts | 9 +++++++-- .../search-service/search-configuration.service.ts | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-configuration.service.ts b/src/app/+my-dspace-page/my-dspace-configuration.service.ts index c5c37ae367..3ee91c5f31 100644 --- a/src/app/+my-dspace-page/my-dspace-configuration.service.ts +++ b/src/app/+my-dspace-page/my-dspace-configuration.service.ts @@ -21,7 +21,7 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { * Default pagination settings */ protected defaultPagination = Object.assign(new PaginationComponentOptions(), { - id: 'mydspace-page-configuration', + id: 'mydspace-page', pageSize: 10, currentPage: 1 }); @@ -34,7 +34,7 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { /** * Default configuration parameter setting */ - protected defaultConfiguration = 'default'; + protected defaultConfiguration = 'workspace'; /** * Default scope setting @@ -62,6 +62,11 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { protected route: ActivatedRoute) { super(routeService, route); + + // override parent class initialization + this._defaults = null; + this.initDefaults(); + this.isSubmitter$ = this.roleService.isSubmitter(); this.isController$ = this.roleService.isController(); this.isAdmin$ = this.roleService.isAdmin(); diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts index 39f1919f72..5d33d3dac7 100644 --- a/src/app/+search-page/search-service/search-configuration.service.ts +++ b/src/app/+search-page/search-service/search-configuration.service.ts @@ -59,7 +59,7 @@ export class SearchConfigurationService implements OnDestroy { /** * Emits the current default values */ - private _defaults: Observable>; + protected _defaults: Observable>; /** * Emits the current search options @@ -74,7 +74,7 @@ export class SearchConfigurationService implements OnDestroy { /** * List of subscriptions to unsubscribe from on destroy */ - private subs: Subscription[] = new Array(); + protected subs: Subscription[] = new Array(); /** * Initialize the search options @@ -83,6 +83,14 @@ export class SearchConfigurationService implements OnDestroy { */ constructor(protected routeService: RouteService, protected route: ActivatedRoute) { + + this.initDefaults(); + } + + /** + * Initialize the search options + */ + protected initDefaults() { this.defaults .pipe(getSucceededRemoteData()) .subscribe((defRD) => { From 6b40efdf992fd91e740386bf6ddf765d991a5f3c Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 14:14:02 +0100 Subject: [PATCH 21/70] Fixed loadin spin icon --- .../approve/claimed-task-actions-approve.component.html | 2 +- .../reject/claimed-task-actions-reject.component.html | 4 ++-- .../pool-task/pool-task-actions.component.html | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html index 39b0f34a7b..1b6b1ea755 100644 --- a/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.html @@ -3,6 +3,6 @@ ngbTooltip="{{'submission.workflow.tasks.claimed.approve_help' | translate}}" [disabled]="processingApprove" (click)="click()"> - {{'submission.workflow.tasks.generic.processing' | translate}} + {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.approve' | translate}} diff --git a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html index 29835f2b40..7c7f4365b8 100644 --- a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.html @@ -3,7 +3,7 @@ [ngbTooltip]="rejectTipContent" [disabled]="processingReject" (click)="openRejectModal(rejectModal)" > - {{'submission.workflow.tasks.generic.processing' | translate}} + {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.reject.submit' | translate}} @@ -32,7 +32,7 @@ class="btn btn-danger btn-lg btn-block mt-3" [disabled]="!rejectForm.valid || processingReject" type="submit"> - {{'submission.workflow.tasks.generic.processing' | translate}} + {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.reject.reason.submit' | translate}} diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html index faf1fcc37e..7ab3c12ea4 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html @@ -1,5 +1,3 @@ - - - - + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts index c3c27a53ae..123032b86f 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts @@ -1,20 +1,19 @@ -import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; -import { Observable, Subscription } from 'rxjs'; -import { find, first } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { find } from 'rxjs/operators'; import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { RemoteData } from '../../../../core/data/remote-data'; -import { hasValue, isNotUndefined } from '../../../empty.util'; +import { isNotUndefined } from '../../../empty.util'; import { ListableObject } from '../../../object-collection/shared/listable-object.model'; import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; -import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { MYDSPACE_ROUTE } from '../../../../+my-dspace-page/my-dspace-page.component'; @Component({ selector: 'ds-pooltask-my-dspace-result-list-element', @@ -24,11 +23,9 @@ import { MYDSPACE_ROUTE } from '../../../../+my-dspace-page/my-dspace-page.compo @renderElementsFor(PoolTaskMyDSpaceResult, ViewMode.List) @renderElementsFor(PoolTask, ViewMode.List) -export class PoolTaskMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnDestroy, OnInit { +export class PoolTaskMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnInit { public status = MyDspaceItemStatusType.WAITING_CONTROLLER; public workFlow: Workflowitem; - public viewMode: ViewMode = ViewMode.List; - private sub: Subscription; constructor(@Inject('objectElementProvider') public listable: ListableObject, @Inject('indexElementProvider') public index: number, @@ -48,34 +45,4 @@ export class PoolTaskMyDSpaceResultListElementComponent extends MyDSpaceResultLi this.workFlow = rd.payload; }); } - - switchView() { - this.viewMode = (this.viewMode === ViewMode.List) ? ViewMode.Detail : ViewMode.List; - } - - view() { - this.sub = this.route.queryParams.pipe( - first() - ).subscribe((params) => { - const pageSize = params.pageSize || 1; - const page = (pageSize * this.dsoIndex ) + 1; - - const navigationExtras: NavigationExtras = { - queryParams: { - view: ViewMode.Detail, - page, - pageSize - }, - queryParamsHandling: 'merge' - }; - this.router.navigate([MYDSPACE_ROUTE], navigationExtras); - }); - } - - ngOnDestroy() { - if (hasValue(this.sub)) { - this.sub.unsubscribe(); - } - } - } From 1a57fe703ab8d6e19386d37f80112a69537998d6 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 14:18:55 +0100 Subject: [PATCH 23/70] Added comments --- .../my-dspace-page.component.html | 2 +- .../+my-dspace-page/my-dspace-page.component.ts | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html index 80b52a273c..4fecfa3209 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.html +++ b/src/app/+my-dspace-page/my-dspace-page.component.html @@ -1,5 +1,5 @@
    -
    = new InjectionToken('searchConfigurationService'); /** - * This component renders a simple item page. - * The route parameter 'id' is used to request the item it represents. - * All fields of the item that should be displayed, are defined in its template. + * This component represents the whole mydspace page */ - @Component({ selector: 'ds-my-dspace-page', styleUrls: ['./my-dspace-page.component.scss'], @@ -43,10 +40,6 @@ export const SEARCH_CONFIG_SERVICE: InjectionToken = } ] }) - -/** - * This component represents the whole mydspace page - */ export class MyDSpacePageComponent implements OnInit { /** @@ -79,8 +72,14 @@ export class MyDSpacePageComponent implements OnInit { */ sub: Subscription; + /** + * Variable for enumeration RoleType + */ roleTypeEnum = RoleType; + /** + * List of available view mode + */ viewModeList = [ViewMode.List, ViewMode.Detail]; constructor(private service: SearchService, @@ -92,6 +91,8 @@ export class MyDSpacePageComponent implements OnInit { } /** + * Initialize available configuration list + * * Listening to changes in the paginated search options * If something changes, update the search results * From 6616d759cb1649cd13577effbdca5448453b7881 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 14:47:03 +0100 Subject: [PATCH 24/70] Renamed mydspace results components and files --- .../+my-dspace-page/my-dspace-page.module.ts | 34 +++++++++---------- ...pace-result-detail-element.component.html} | 0 ...dspace-result-detail-element.component.ts} | 6 ++-- ...pace-result-detail-element.component.html} | 0 ...-dspace-result-detail-lement.component.ts} | 6 ++-- ...pace-result-detail-element.component.html} | 0 ...dspace-result-detail-element.component.ts} | 2 +- ...pace-result-detail-element.component.html} | 0 ...pace-result-detail-element.component.scss} | 0 ...dspace-result-detail-element.component.ts} | 4 +-- ...dspace-result-list-element.component.html} | 0 ...y-dspace-result-list-element.component.ts} | 6 ++-- ...dspace-result-list-element.component.html} | 0 ...y-dspace-result-list-element.component.ts} | 11 +++--- ...dspace-result-list-element.component.html} | 0 ...y-dspace-result-list-element.component.ts} | 2 +- ...dspace-result-list-element.component.html} | 0 ...dspace-result-list-element.component.scss} | 0 ...y-dspace-result-list-element.component.ts} | 4 +-- 19 files changed, 36 insertions(+), 39 deletions(-) rename src/app/shared/object-detail/my-dspace-result-detail-element/{ct-my-dspace-result/ct-my-dspace-result-detail-element.component.html => claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html} (100%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{ct-my-dspace-result/ct-my-dspace-result-detail-element.component.ts => claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts} (89%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{pt-my-dspace-result/pt-my-dspace-result-detail-element.component.html => pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html} (100%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{pt-my-dspace-result/pt-my-dspace-result-detail-lement.component.ts => pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts} (86%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.html => workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.html} (100%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.ts => workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts} (96%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.html => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.html} (100%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.scss => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.scss} (100%) rename src/app/shared/object-detail/my-dspace-result-detail-element/{wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.ts => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts} (92%) rename src/app/shared/object-list/my-dspace-result-list-element/{ct-my-dspace-result/ct-my-dspace-result-list-element.component.html => claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html} (100%) rename src/app/shared/object-list/my-dspace-result-list-element/{ct-my-dspace-result/ct-my-dspace-result-list-element.component.ts => claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts} (86%) rename src/app/shared/object-list/my-dspace-result-list-element/{pt-my-dspace-result/pt-my-dspace-result-list-element.component.html => pool-my-dspace-result/pool-my-dspace-result-list-element.component.html} (100%) rename src/app/shared/object-list/my-dspace-result-list-element/{pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts => pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts} (81%) rename src/app/shared/object-list/my-dspace-result-list-element/{wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.html => workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.html} (100%) rename src/app/shared/object-list/my-dspace-result-list-element/{wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.ts => workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts} (95%) rename src/app/shared/object-list/my-dspace-result-list-element/{wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.html => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.html} (100%) rename src/app/shared/object-list/my-dspace-result-list-element/{wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.scss => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.scss} (100%) rename src/app/shared/object-list/my-dspace-result-list-element/{wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.ts => workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts} (91%) diff --git a/src/app/+my-dspace-page/my-dspace-page.module.ts b/src/app/+my-dspace-page/my-dspace-page.module.ts index 4be59b4181..697c22dd0e 100644 --- a/src/app/+my-dspace-page/my-dspace-page.module.ts +++ b/src/app/+my-dspace-page/my-dspace-page.module.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { CUSTOM_ELEMENTS_SCHEMA, NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NgModule } from '@angular/core'; import { SharedModule } from '../shared/shared.module'; @@ -7,17 +7,17 @@ import { MyDspacePageRoutingModule } from './my-dspace-page-routing.module'; import { MyDSpacePageComponent } from './my-dspace-page.component'; import { SearchPageModule } from '../+search-page/search-page.module'; import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component'; -import { WorkspaceitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component'; +import { WorkspaceitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component'; import { ItemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component'; -import { WorkflowitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component'; -import { ClaimedTaskMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component'; -import { PoolTaskMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component'; +import { WorkflowitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component'; +import { ClaimedMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component'; +import { PoolMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component'; import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component'; import { ItemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component'; -import { WorkspaceitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component'; -import { WorkflowitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component'; -import { ClaimedTaskMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component'; -import { PoolTaskMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-lement.component'; +import { WorkspaceitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component'; +import { WorkflowitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component'; +import { ClaimedMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component'; +import { PoolMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component'; import { MyDSpaceGuard } from './my-dspace.guard'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; @@ -34,13 +34,13 @@ import { MyDSpaceConfigurationService } from './my-dspace-configuration.service' ItemMyDSpaceResultListElementComponent, WorkspaceitemMyDSpaceResultListElementComponent, WorkflowitemMyDSpaceResultListElementComponent, - ClaimedTaskMyDSpaceResultListElementComponent, - PoolTaskMyDSpaceResultListElementComponent, + ClaimedMyDSpaceResultListElementComponent, + PoolMyDSpaceResultListElementComponent, ItemMyDSpaceResultDetailElementComponent, WorkspaceitemMyDSpaceResultDetailElementComponent, WorkflowitemMyDSpaceResultDetailElementComponent, - ClaimedTaskMyDSpaceResultDetailElementComponent, - PoolTaskMyDSpaceResultDetailElementComponent, + ClaimedMyDSpaceResultDetailElementComponent, + PoolMyDSpaceResultDetailElementComponent, MyDSpaceNewSubmissionComponent ], providers: [ @@ -51,13 +51,13 @@ import { MyDSpaceConfigurationService } from './my-dspace-configuration.service' ItemMyDSpaceResultListElementComponent, WorkspaceitemMyDSpaceResultListElementComponent, WorkflowitemMyDSpaceResultListElementComponent, - ClaimedTaskMyDSpaceResultListElementComponent, - PoolTaskMyDSpaceResultListElementComponent, + ClaimedMyDSpaceResultListElementComponent, + PoolMyDSpaceResultListElementComponent, ItemMyDSpaceResultDetailElementComponent, WorkspaceitemMyDSpaceResultDetailElementComponent, WorkflowitemMyDSpaceResultDetailElementComponent, - ClaimedTaskMyDSpaceResultDetailElementComponent, - PoolTaskMyDSpaceResultDetailElementComponent + ClaimedMyDSpaceResultDetailElementComponent, + PoolMyDSpaceResultDetailElementComponent ] }) export class MyDSpacePageModule { diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts similarity index 89% rename from src/app/shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts index 90531af2b0..4a5367d2a0 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/ct-my-dspace-result/ct-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts @@ -19,15 +19,15 @@ import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; @Component({ - selector: 'ds-claimtask-my-dspace-result-detail-element', + selector: 'ds-claimed-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './ct-my-dspace-result-detail-element.component.html', + templateUrl: './claimed-my-dspace-result-detail-element.component.html', providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}] }) @renderElementsFor(ClaimedTaskMyDSpaceResult, ViewMode.Detail) @renderElementsFor(ClaimedTask, ViewMode.Detail) -export class ClaimedTaskMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { +export class ClaimedMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { public status = MyDspaceItemStatusType.VALIDATION; public workFlow: Workflowitem; public rejectForm: FormGroup; diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-lement.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts similarity index 86% rename from src/app/shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-lement.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts index 28ebefe633..1917a5f1af 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pt-my-dspace-result/pt-my-dspace-result-detail-lement.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts @@ -15,14 +15,14 @@ import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; @Component({ - selector: 'ds-pooltask-my-dspace-result-detail-element', + selector: 'ds-pool-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './pt-my-dspace-result-detail-element.component.html', + templateUrl: './pool-my-dspace-result-detail-element.component.html', }) @renderElementsFor(PoolTaskMyDSpaceResult, ViewMode.Detail) @renderElementsFor(PoolTask, ViewMode.Detail) -export class PoolTaskMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { +export class PoolMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { public status = MyDspaceItemStatusType.WAITING_CONTROLLER; public workFlow: Workflowitem; diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts similarity index 96% rename from src/app/shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts index 865e9c4fec..c76ad84b22 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/wfi-my-dspace-result/wfi-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts @@ -16,7 +16,7 @@ import { isNotUndefined } from '../../../empty.util'; @Component({ selector: 'ds-workflowitem-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './wfi-my-dspace-result-detail-element.component.html', + templateUrl: './workflowitem-my-dspace-result-detail-element.component.html', }) @renderElementsFor(WorkflowitemMyDSpaceResult, ViewMode.Detail) diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.scss b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.scss similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.scss rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.scss diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts similarity index 92% rename from src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts index c600ba9773..4a1635ec5d 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/wsi-my-dspace-result/wsi-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts @@ -16,8 +16,8 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @Component({ selector: 'ds-workspaceitem-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss', './wsi-my-dspace-result-detail-element.component.scss'], - templateUrl: './wsi-my-dspace-result-detail-element.component.html', + styleUrls: ['../my-dspace-result-detail-element.component.scss', './workspaceitem-my-dspace-result-detail-element.component.scss'], + templateUrl: './workspaceitem-my-dspace-result-detail-element.component.html', }) @renderElementsFor(WorkspaceitemMyDSpaceResult, ViewMode.Detail) diff --git a/src/app/shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts similarity index 86% rename from src/app/shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts index 36626e1968..c37973ae11 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/ct-my-dspace-result/ct-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts @@ -15,15 +15,15 @@ import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/cla import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; @Component({ - selector: 'ds-claimtask-my-dspace-result-list-element', + selector: 'ds-claimed-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './ct-my-dspace-result-list-element.component.html', + templateUrl: './claimed-my-dspace-result-list-element.component.html', providers: [Location, { provide: LocationStrategy, useClass: PathLocationStrategy }] }) @renderElementsFor(ClaimedTaskMyDSpaceResult, ViewMode.List) @renderElementsFor(ClaimedTask, ViewMode.List) -export class ClaimedTaskMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { +export class ClaimedMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { public showSubmitter = true; public status = MyDspaceItemStatusType.VALIDATION; public workFlow: Workflowitem; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts similarity index 81% rename from src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts index 123032b86f..443d5d7e8c 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pt-my-dspace-result/pt-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts @@ -12,25 +12,22 @@ import { ListableObject } from '../../../object-collection/shared/listable-objec import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; -import { ActivatedRoute, Router } from '@angular/router'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; @Component({ - selector: 'ds-pooltask-my-dspace-result-list-element', + selector: 'ds-pool-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './pt-my-dspace-result-list-element.component.html', + templateUrl: './pool-my-dspace-result-list-element.component.html', }) @renderElementsFor(PoolTaskMyDSpaceResult, ViewMode.List) @renderElementsFor(PoolTask, ViewMode.List) -export class PoolTaskMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnInit { +export class PoolMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnInit { public status = MyDspaceItemStatusType.WAITING_CONTROLLER; public workFlow: Workflowitem; constructor(@Inject('objectElementProvider') public listable: ListableObject, - @Inject('indexElementProvider') public index: number, - private route: ActivatedRoute, - private router: Router) { + @Inject('indexElementProvider') public index: number) { super(listable, index); } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts similarity index 95% rename from src/app/shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts index a0f1e8decd..7fad9d7677 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/wfi-my-dspace-result/wfi-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts @@ -16,7 +16,7 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @Component({ selector: 'ds-workflowitem-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './wfi-my-dspace-result-list-element.component.html', + templateUrl: './workflowitem-my-dspace-result-list-element.component.html', }) @renderElementsFor(WorkflowitemMyDSpaceResult, ViewMode.List) diff --git a/src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.scss b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.scss similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.scss rename to src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.scss diff --git a/src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts similarity index 91% rename from src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts index 7a19f54a10..b0df02c64c 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/wsi-my-dspace-result/wsi-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts @@ -15,8 +15,8 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @Component({ selector: 'ds-workspaceitem-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss', './wsi-my-dspace-result-list-element.component.scss'], - templateUrl: './wsi-my-dspace-result-list-element.component.html', + styleUrls: ['../my-dspace-result-list-element.component.scss', './workspaceitem-my-dspace-result-list-element.component.scss'], + templateUrl: './workspaceitem-my-dspace-result-list-element.component.html', }) @renderElementsFor(WorkspaceitemMyDSpaceResult, ViewMode.List) From 7b63d145d85061cffa0b5b222c7f27102eeef314 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 28 Mar 2019 19:33:40 +0100 Subject: [PATCH 25/70] Added more tests and comments --- ...space-result-detail-element.component.html | 10 +- ...ce-result-detail-element.component.spec.ts | 89 ++++++++++++ ...-dspace-result-detail-element.component.ts | 43 +++--- .../item-detail-preview.component.html | 33 +---- .../item-detail-preview.component.spec.ts | 90 ++++++++++++ .../item-detail-preview.component.ts | 31 ++++- ...ce-result-detail-element.component.spec.ts | 78 +++++++++++ ...-dspace-result-detail-element.component.ts | 6 + ...space-result-detail-element.component.html | 7 +- ...ce-result-detail-element.component.spec.ts | 89 ++++++++++++ ...y-dspace-result-detail-lement.component.ts | 27 +++- ...ce-result-detail-element.component.spec.ts | 86 ++++++++++++ ...-dspace-result-detail-element.component.ts | 16 +++ ...ce-result-detail-element.component.spec.ts | 86 ++++++++++++ ...-dspace-result-detail-element.component.ts | 17 +++ .../item-list-preview.component.scss | 5 - ...-dspace-result-list-element.component.html | 6 +- ...pace-result-list-element.component.spec.ts | 89 ++++++++++++ ...my-dspace-result-list-element.component.ts | 29 +++- .../item-list-preview.component.html | 0 .../item-list-preview.component.scss | 5 + .../item-list-preview.component.spec.ts | 131 ++++++++++++++++++ .../item-list-preview.component.ts | 28 +++- ...pace-result-list-element.component.spec.ts | 78 +++++++++++ ...my-dspace-result-list-element.component.ts | 6 + ...-dspace-result-list-element.component.html | 6 +- ...pace-result-list-element.component.spec.ts | 89 ++++++++++++ ...my-dspace-result-list-element.component.ts | 26 +++- ...pace-result-list-element.component.spec.ts | 86 ++++++++++++ ...my-dspace-result-list-element.component.ts | 17 +++ ...pace-result-list-element.component.spec.ts | 86 ++++++++++++ ...my-dspace-result-list-element.component.ts | 16 +++ src/app/shared/shared.module.ts | 2 +- 33 files changed, 1326 insertions(+), 87 deletions(-) create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts create mode 100644 src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts delete mode 100644 src/app/shared/object-list/item-list-preview/item-list-preview.component.scss create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts rename src/app/shared/object-list/{ => my-dspace-result-list-element}/item-list-preview/item-list-preview.component.html (100%) create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.scss create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts rename src/app/shared/object-list/{ => my-dspace-result-list-element}/item-list-preview/item-list-preview.component.ts (69%) create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html index 134b85523e..d4ecaaa332 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html @@ -1,6 +1,8 @@ - + [showSubmitter]="showSubmitter" + [status]="status"> + - + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts new file mode 100644 index 0000000000..38c4f461cd --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts @@ -0,0 +1,89 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { ClaimedMyDSpaceResultDetailElementComponent } from './claimed-my-dspace-result-detail-element.component'; +import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; +import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; + +let component: ClaimedMyDSpaceResultDetailElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: ClaimedTaskMyDSpaceResult = new ClaimedTaskMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rdItem = new RemoteData(false, false, true, null, item); +const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject.dspaceObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('ClaimedMyDSpaceResultDetailElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [ClaimedMyDSpaceResultDetailElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ClaimedMyDSpaceResultDetailElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ClaimedMyDSpaceResultDetailElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.workflowitem).toEqual(workflowitem); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.VALIDATION); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts index 4a5367d2a0..29e8e907ad 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts @@ -11,47 +11,56 @@ import { ListableObject } from '../../../object-collection/shared/listable-objec import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; -import { ClaimedTaskDataService } from '../../../../core/tasks/claimed-task-data.service'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common'; import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders claimed task object for the mydspace result in the detail view. + */ @Component({ selector: 'ds-claimed-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './claimed-my-dspace-result-detail-element.component.html', - providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}] + templateUrl: './claimed-my-dspace-result-detail-element.component.html' }) @renderElementsFor(ClaimedTaskMyDSpaceResult, ViewMode.Detail) @renderElementsFor(ClaimedTask, ViewMode.Detail) export class ClaimedMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { + + /** + * A boolean representing if to show submitter information + */ + public showSubmitter = true; + + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.VALIDATION; - public workFlow: Workflowitem; - public rejectForm: FormGroup; - constructor(private ctDataService: ClaimedTaskDataService, - private modalService: NgbModal, - private formBuilder: FormBuilder, - @Inject('objectElementProvider') public listable: ListableObject) { + /** + * The workflowitem object that belonging to the result object + */ + public workflowitem: Workflowitem; + + constructor(@Inject('objectElementProvider') public listable: ListableObject) { super(listable); - - this.rejectForm = this.formBuilder.group({ - reason: ['', Validators.required] - }); } + /** + * Initialize all instance variables + */ ngOnInit() { this.initWorkflowItem(this.dso.workflowitem as Observable>); } + /** + * Retrieve workflowitem from result object + */ initWorkflowItem(wfi$: Observable>) { wfi$.pipe( find((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))) ).subscribe((rd: RemoteData) => { - this.workFlow = rd.payload; + this.workflowitem = rd.payload; }); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html index 4f9d8f3e94..3cb4665884 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html @@ -24,35 +24,4 @@
    - - - - - - + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts new file mode 100644 index 0000000000..5823e9969b --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts @@ -0,0 +1,90 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; + +import { of as observableOf } from 'rxjs'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Item } from '../../../../core/shared/item.model'; +import { ItemDetailPreviewComponent } from './item-detail-preview.component'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +let component: ItemDetailPreviewComponent; +let fixture: ComponentFixture; + +const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ] + } +}); + +describe('ItemDetailPreviewComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NoopAnimationsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }), + ], + declarations: [ItemDetailPreviewComponent, TruncatePipe], + providers: [ + { provide: 'objectElementProvider', useValue: { mockItemWithAuthorAndDate } } + + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemDetailPreviewComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemDetailPreviewComponent); + component = fixture.componentInstance; + + })); + + beforeEach(() => { + component.object = { hitHighlights: {} }; + component.item = mockItemWithAuthorAndDate; + fixture.detectChanges(); + }); + + it('should init thumbnail on init', () => { + expect(component.thumbnail$).toBeDefined(); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts index 9b42bb2268..9f92f79859 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts @@ -7,25 +7,46 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa import { fadeInOut } from '../../../animations/fade'; import { Bitstream } from '../../../../core/shared/bitstream.model'; +/** + * This component show metadata for the given item object in the detail view. + */ @Component({ selector: 'ds-item-detail-preview', styleUrls: ['./item-detail-preview.component.scss'], templateUrl: './item-detail-preview.component.html', animations: [fadeInOut] }) -export class ItemDetailPreviewComponent { +export class ItemDetailPreviewComponent { + /** + * The item to display + */ @Input() item: Item; + + /** + * The mydspace result object + */ @Input() object: any; + + /** + * Represent item's status + */ @Input() status: MyDspaceItemStatusType; - public ALL_STATUS = []; + /** + * A boolean representing if to show submitter information + */ + @Input() showSubmitter = false; + + /** + * The item's thumbnail + */ public thumbnail$: Observable; + /** + * Initialize all instance variables + */ ngOnInit() { - Object.keys(MyDspaceItemStatusType).forEach((s) => { - this.ALL_STATUS.push(MyDspaceItemStatusType[s]); - }); this.thumbnail$ = this.item.getThumbnail(); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts new file mode 100644 index 0000000000..c48d755d61 --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts @@ -0,0 +1,78 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { ItemMyDSpaceResultDetailElementComponent } from './item-my-dspace-result-detail-element.component'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; + +let component: ItemMyDSpaceResultDetailElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +mockResultObject.dspaceObject = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); + +describe('ItemMyDSpaceResultDetailElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [ItemMyDSpaceResultDetailElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemMyDSpaceResultDetailElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemMyDSpaceResultDetailElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.ACCEPTED); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts index 75bfb30939..a55d911581 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts @@ -7,6 +7,9 @@ import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-ds import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders item object for the mydspace result in the detail view. + */ @Component({ selector: 'ds-workspaceitem-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss', './item-my-dspace-result-detail-element.component.scss'], @@ -16,6 +19,9 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(ItemMyDSpaceResult, ViewMode.Detail) export class ItemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.ACCEPTED; } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html index 8d808815c2..96ef68e3f8 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html @@ -1,6 +1,7 @@ - - + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts new file mode 100644 index 0000000000..b108d48c33 --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts @@ -0,0 +1,89 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { PoolMyDSpaceResultDetailElementComponent } from './pool-my-dspace-result-detail-lement.component'; +import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; +import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; + +let component: PoolMyDSpaceResultDetailElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: PoolTaskMyDSpaceResult = new PoolTaskMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rdItem = new RemoteData(false, false, true, null, item); +const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject.dspaceObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('PoolMyDSpaceResultDetailElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [PoolMyDSpaceResultDetailElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PoolMyDSpaceResultDetailElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PoolMyDSpaceResultDetailElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.workflowitem).toEqual(workflowitem); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.WAITING_CONTROLLER); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts index 1917a5f1af..fbc37c9525 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts @@ -14,6 +14,9 @@ import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-t import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders pool task object for the mydspace result in the detail view. + */ @Component({ selector: 'ds-pool-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], @@ -23,23 +26,41 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(PoolTaskMyDSpaceResult, ViewMode.Detail) @renderElementsFor(PoolTask, ViewMode.Detail) export class PoolMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { + + /** + * A boolean representing if to show submitter information + */ + public showSubmitter = true; + + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.WAITING_CONTROLLER; - public workFlow: Workflowitem; + + /** + * The workflowitem object that belonging to the result object + */ + public workflowitem: Workflowitem; constructor(@Inject('objectElementProvider') public listable: ListableObject) { - super(listable); } + /** + * Initialize all instance variables + */ ngOnInit() { this.initWorkflowItem(this.dso.workflowitem as Observable>); } + /** + * Retrieve workflowitem from result object + */ initWorkflowItem(wfi$: Observable>) { wfi$.pipe( find((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))) ).subscribe((rd: RemoteData) => { - this.workFlow = rd.payload; + this.workflowitem = rd.payload; }); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts new file mode 100644 index 0000000000..3c6505218e --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts @@ -0,0 +1,86 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { WorkflowitemMyDSpaceResultDetailElementComponent } from './workflowitem-my-dspace-result-detail-element.component'; +import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; + +let component: WorkflowitemMyDSpaceResultDetailElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: WorkflowitemMyDSpaceResult = new WorkflowitemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockResultObject.dspaceObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); + +describe('WorkflowitemMyDSpaceResultDetailElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [WorkflowitemMyDSpaceResultDetailElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkflowitemMyDSpaceResultDetailElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(WorkflowitemMyDSpaceResultDetailElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.item).toEqual(item); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.WORKFLOW); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts index c76ad84b22..32e005309d 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts @@ -13,6 +13,9 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { find } from 'rxjs/operators'; import { isNotUndefined } from '../../../empty.util'; +/** + * This component renders workflowitem object for the mydspace result in the detail view. + */ @Component({ selector: 'ds-workflowitem-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss'], @@ -23,17 +26,30 @@ import { isNotUndefined } from '../../../empty.util'; @renderElementsFor(Workflowitem, ViewMode.Detail) export class WorkflowitemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { + /** + * The item object that belonging to the result object + */ public item: Item; + + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.WORKFLOW; constructor(@Inject('objectElementProvider') public listable: ListableObject) { super(listable); } + /** + * Initialize all instance variables + */ ngOnInit() { this.initItem(this.dso.item as Observable>); } + /** + * Retrieve item from result object + */ initItem(item$: Observable>) { item$.pipe( find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts new file mode 100644 index 0000000000..830ab80cf1 --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts @@ -0,0 +1,86 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { WorkspaceitemMyDSpaceResultDetailElementComponent } from './workspaceitem-my-dspace-result-detail-element.component'; +import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; +import { Workspaceitem } from '../../../../core/submission/models/workspaceitem.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; + +let component: WorkspaceitemMyDSpaceResultDetailElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: WorkspaceitemMyDSpaceResult = new WorkspaceitemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockResultObject.dspaceObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); + +describe('WorkspaceitemMyDSpaceResultDetailElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [WorkspaceitemMyDSpaceResultDetailElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkspaceitemMyDSpaceResultDetailElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(WorkspaceitemMyDSpaceResultDetailElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.item).toEqual(item); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.IN_PROGRESS); + }); +}); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts index 4a1635ec5d..ca6ed59c12 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts @@ -14,6 +14,9 @@ import { ListableObject } from '../../../object-collection/shared/listable-objec import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders workspaceitem object for the mydspace result in the detail view. + */ @Component({ selector: 'ds-workspaceitem-my-dspace-result-detail-element', styleUrls: ['../my-dspace-result-detail-element.component.scss', './workspaceitem-my-dspace-result-detail-element.component.scss'], @@ -23,17 +26,31 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(WorkspaceitemMyDSpaceResult, ViewMode.Detail) @renderElementsFor(Workspaceitem, ViewMode.Detail) export class WorkspaceitemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { + + /** + * The item object that belonging to the result object + */ public item: Item; + + /** + * Represent item's status + */ status = MyDspaceItemStatusType.IN_PROGRESS; constructor(@Inject('objectElementProvider') public listable: ListableObject) { super(listable); } + /** + * Initialize all instance variables + */ ngOnInit() { this.initItem(this.dso.item as Observable>); } + /** + * Retrieve item from result object + */ initItem(item$: Observable>) { item$.pipe( find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) diff --git a/src/app/shared/object-list/item-list-preview/item-list-preview.component.scss b/src/app/shared/object-list/item-list-preview/item-list-preview.component.scss deleted file mode 100644 index 8d0339f264..0000000000 --- a/src/app/shared/object-list/item-list-preview/item-list-preview.component.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import '../../../../styles/_variables.scss'; - -.h3-title { - color: $link-color; -} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html index 5ec6e59f95..5ec4c9a5b5 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html @@ -1,7 +1,7 @@ - - + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts new file mode 100644 index 0000000000..c79812d10b --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts @@ -0,0 +1,89 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { ClaimedMyDSpaceResultListElementComponent } from './claimed-my-dspace-result-list-element.component'; +import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; +import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; + +let component: ClaimedMyDSpaceResultListElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: ClaimedTaskMyDSpaceResult = new ClaimedTaskMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rdItem = new RemoteData(false, false, true, null, item); +const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject.dspaceObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('ClaimedMyDSpaceResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [ClaimedMyDSpaceResultListElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ClaimedMyDSpaceResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ClaimedMyDSpaceResultListElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.workflowitem).toEqual(workflowitem); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.VALIDATION); + }); +}); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts index c37973ae11..5f2cd2495e 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts @@ -14,6 +14,9 @@ import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.m import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders claimed task object for the mydspace result in the list view. + */ @Component({ selector: 'ds-claimed-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], @@ -24,19 +27,37 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(ClaimedTaskMyDSpaceResult, ViewMode.List) @renderElementsFor(ClaimedTask, ViewMode.List) export class ClaimedMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { - public showSubmitter = true; - public status = MyDspaceItemStatusType.VALIDATION; - public workFlow: Workflowitem; + /** + * A boolean representing if to show submitter information + */ + public showSubmitter = true; + + /** + * Represent item's status + */ + public status = MyDspaceItemStatusType.VALIDATION; + + /** + * The workflowitem object that belonging to the result object + */ + public workflowitem: Workflowitem; + + /** + * Initialize all instance variables + */ ngOnInit() { this.initWorkflowItem(this.dso.workflowitem as Observable>); } + /** + * Retrieve workflowitem from result object + */ initWorkflowItem(wfi$: Observable>) { wfi$.pipe( find((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))) ).subscribe((rd: RemoteData) => { - this.workFlow = rd.payload; + this.workflowitem = rd.payload; }); } } diff --git a/src/app/shared/object-list/item-list-preview/item-list-preview.component.html b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html similarity index 100% rename from src/app/shared/object-list/item-list-preview/item-list-preview.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.scss b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.scss new file mode 100644 index 0000000000..949e96d484 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.scss @@ -0,0 +1,5 @@ +@import '../../../../../styles/variables'; + +.h3-title { + color: $link-color; +} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts new file mode 100644 index 0000000000..9b917b56e4 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts @@ -0,0 +1,131 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +import { of as observableOf } from 'rxjs'; + +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Item } from '../../../../core/shared/item.model'; +import { ItemListPreviewComponent } from './item-list-preview.component'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; + +let component: ItemListPreviewComponent; +let fixture: ComponentFixture; + +const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ] + } +}); + +describe('ItemListPreviewComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }), + ], + declarations: [ItemListPreviewComponent, TruncatePipe], + providers: [ + { provide: 'objectElementProvider', useValue: { mockItemWithAuthorAndDate } } + + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemListPreviewComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemListPreviewComponent); + component = fixture.componentInstance; + + })); + + beforeEach(() => { + component.object = { hitHighlights: {} }; + }); + + describe('When the item has an author', () => { + beforeEach(() => { + component.item = mockItemWithAuthorAndDate; + fixture.detectChanges(); + }); + + it('should show the author paragraph', () => { + const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); + expect(itemAuthorField).not.toBeNull(); + }); + }); + + describe('When the item has no author', () => { + beforeEach(() => { + component.item = mockItemWithoutAuthorAndDate; + fixture.detectChanges(); + }); + + it('should not show the author paragraph', () => { + const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); + expect(itemAuthorField).toBeNull(); + }); + }); + + describe('When the item has an issuedate', () => { + beforeEach(() => { + component.item = mockItemWithAuthorAndDate; + fixture.detectChanges(); + }); + + it('should show the issuedate span', () => { + const dateField = fixture.debugElement.query(By.css('span.item-list-date')); + expect(dateField).not.toBeNull(); + }); + }); + + describe('When the item has no issuedate', () => { + beforeEach(() => { + component.item = mockItemWithoutAuthorAndDate; + fixture.detectChanges(); + }); + + it('should show the issuedate empty placeholder', () => { + const dateField = fixture.debugElement.query(By.css('span.item-list-date')); + expect(dateField).not.toBeNull(); + }); + }); +}); diff --git a/src/app/shared/object-list/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts similarity index 69% rename from src/app/shared/object-list/item-list-preview/item-list-preview.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts index 0a853b9c5e..5112069071 100644 --- a/src/app/shared/object-list/item-list-preview/item-list-preview.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts @@ -1,21 +1,39 @@ import { Component, Input } from '@angular/core'; -import { Item } from '../../../core/shared/item.model'; -import { fadeInOut } from '../../animations/fade'; -import { MyDspaceItemStatusType } from '../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { Metadata } from '../../../core/shared/metadata.utils'; +import { Item } from '../../../../core/shared/item.model'; +import { fadeInOut } from '../../../animations/fade'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { Metadata } from '../../../../core/shared/metadata.utils'; +/** + * This component show metadata for the given item object in the list view. + */ @Component({ selector: 'ds-item-list-preview', styleUrls: ['item-list-preview.component.scss'], templateUrl: 'item-list-preview.component.html', animations: [fadeInOut] }) - export class ItemListPreviewComponent { + + /** + * The item to display + */ @Input() item: Item; + + /** + * The mydspace result object + */ @Input() object: any; + + /** + * Represent item's status + */ @Input() status: MyDspaceItemStatusType; + + /** + * A boolean representing if to show submitter information + */ @Input() showSubmitter = false; /** diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts new file mode 100644 index 0000000000..bcd323ae2a --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts @@ -0,0 +1,78 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { ItemMyDSpaceResultListElementComponent } from './item-my-dspace-result-list-element.component'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; + +let component: ItemMyDSpaceResultListElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +mockResultObject.dspaceObject = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); + +describe('ItemMyDSpaceResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [ItemMyDSpaceResultListElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemMyDSpaceResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemMyDSpaceResultListElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.ACCEPTED); + }); +}); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts index 484ca9af11..faeeed8ea2 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts @@ -7,6 +7,9 @@ import { Item } from '../../../../core/shared/item.model'; import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders item object for the mydspace result in the list view. + */ @Component({ selector: 'ds-workspaceitem-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss', './item-my-dspace-result-list-element.component.scss'], @@ -16,6 +19,9 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(ItemMyDSpaceResult, ViewMode.List) export class ItemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.ACCEPTED; } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html index b6771db087..5f0f1bb6d4 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html @@ -1,7 +1,7 @@ - diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts new file mode 100644 index 0000000000..3b2545e069 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts @@ -0,0 +1,89 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { PoolMyDSpaceResultListElementComponent } from './pool-my-dspace-result-list-element.component'; +import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; +import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; + +let component: PoolMyDSpaceResultListElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: PoolTaskMyDSpaceResult = new PoolTaskMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rdItem = new RemoteData(false, false, true, null, item); +const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject.dspaceObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('PoolMyDSpaceResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [PoolMyDSpaceResultListElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PoolMyDSpaceResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PoolMyDSpaceResultListElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.workflowitem).toEqual(workflowitem); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.WAITING_CONTROLLER); + }); +}); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts index 443d5d7e8c..36b95271c7 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts @@ -14,6 +14,9 @@ import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders pool task object for the mydspace result in the list view. + */ @Component({ selector: 'ds-pool-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], @@ -23,23 +26,42 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(PoolTaskMyDSpaceResult, ViewMode.List) @renderElementsFor(PoolTask, ViewMode.List) export class PoolMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnInit { + + /** + * A boolean representing if to show submitter information + */ + public showSubmitter = true; + + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.WAITING_CONTROLLER; - public workFlow: Workflowitem; + + /** + * The workflowitem object that belonging to the result object + */ + public workflowitem: Workflowitem; constructor(@Inject('objectElementProvider') public listable: ListableObject, @Inject('indexElementProvider') public index: number) { super(listable, index); } + /** + * Initialize all instance variables + */ ngOnInit() { this.initWorkflowItem(this.dso.workflowitem as Observable>); } + /** + * Retrieve workflowitem from result object + */ initWorkflowItem(wfi$: Observable>) { wfi$.pipe( find((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))) ).subscribe((rd: RemoteData) => { - this.workFlow = rd.payload; + this.workflowitem = rd.payload; }); } } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts new file mode 100644 index 0000000000..de2dfd73f4 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts @@ -0,0 +1,86 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { WorkflowitemMyDSpaceResultListElementComponent } from './workflowitem-my-dspace-result-list-element.component'; +import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; + +let component: WorkflowitemMyDSpaceResultListElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: WorkflowitemMyDSpaceResult = new WorkflowitemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockResultObject.dspaceObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); + +describe('WorkflowitemMyDSpaceResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [WorkflowitemMyDSpaceResultListElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkflowitemMyDSpaceResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(WorkflowitemMyDSpaceResultListElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.item).toEqual(item); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.WORKFLOW); + }); +}); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts index 7fad9d7677..ebce79c2b8 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts @@ -13,6 +13,9 @@ import { Workflowitem } from '../../../../core/submission/models/workflowitem.mo import { Item } from '../../../../core/shared/item.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders workflowitem object for the mydspace result in the list view. + */ @Component({ selector: 'ds-workflowitem-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss'], @@ -22,13 +25,27 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(WorkflowitemMyDSpaceResult, ViewMode.List) @renderElementsFor(Workflowitem, ViewMode.List) export class WorkflowitemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { + + /** + * The item object that belonging to the result object + */ public item: Item; + + /** + * Represent item's status + */ public status = MyDspaceItemStatusType.WORKFLOW; + /** + * Initialize all instance variables + */ ngOnInit() { this.initItem(this.dso.item as Observable>); } + /** + * Retrieve item from result object + */ initItem(item$: Observable>) { item$.pipe( find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts new file mode 100644 index 0000000000..f47c05c9e9 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts @@ -0,0 +1,86 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +import { of as observableOf } from 'rxjs'; + +import { Item } from '../../../../core/shared/item.model'; +import { WorkspaceitemMyDSpaceResultListElementComponent } from './workspaceitem-my-dspace-result-list-element.component'; +import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; +import { Workspaceitem } from '../../../../core/submission/models/workspaceitem.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; + +let component: WorkspaceitemMyDSpaceResultListElementComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +const mockResultObject: WorkspaceitemMyDSpaceResult = new WorkspaceitemMyDSpaceResult(); +mockResultObject.hitHighlights = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockResultObject.dspaceObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); + +describe('WorkspaceitemMyDSpaceResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [WorkspaceitemMyDSpaceResultListElementComponent], + providers: [ + { provide: 'objectElementProvider', useValue: (mockResultObject) }, + { provide: 'indexElementProvider', useValue: (compIndex) } + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkspaceitemMyDSpaceResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(WorkspaceitemMyDSpaceResultListElementComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.dso = mockResultObject.dspaceObject; + fixture.detectChanges(); + }); + + it('should init item properly', () => { + expect(component.item).toEqual(item); + }); + + it('should have properly status', () => { + expect(component.status).toEqual(MyDspaceItemStatusType.IN_PROGRESS); + }); +}); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts index b0df02c64c..c60b742ae0 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts @@ -13,6 +13,9 @@ import { isNotUndefined } from '../../../empty.util'; import { Item } from '../../../../core/shared/item.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +/** + * This component renders workspaceitem object for the mydspace result in the list view. + */ @Component({ selector: 'ds-workspaceitem-my-dspace-result-list-element', styleUrls: ['../my-dspace-result-list-element.component.scss', './workspaceitem-my-dspace-result-list-element.component.scss'], @@ -22,13 +25,26 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa @renderElementsFor(WorkspaceitemMyDSpaceResult, ViewMode.List) export class WorkspaceitemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { + /** + * The item object that belonging to the result object + */ item: Item; + + /** + * Represent item's status + */ status = MyDspaceItemStatusType.IN_PROGRESS; + /** + * Initialize all instance variables + */ ngOnInit() { this.initItem(this.dso.item as Observable>); } + /** + * Retrieve item from result object + */ initItem(item$: Observable>) { item$.pipe( find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 94d9e73e5c..a5a426f1a7 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -126,7 +126,7 @@ import { ItemSearchResultListElementComponent } from './object-list/search-resul import { EditItemSelectorComponent } from './dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component'; import { EditCommunitySelectorComponent } from './dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component'; import { EditCollectionSelectorComponent } from './dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component'; -import { ItemListPreviewComponent } from './object-list/item-list-preview/item-list-preview.component'; +import { ItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component'; import { ItemPageAuthorFieldComponent } from '../+item-page/simple/field-components/specific-field/author/item-page-author-field.component'; import { ItemPageDateFieldComponent } from '../+item-page/simple/field-components/specific-field/date/item-page-date-field.component'; import { ItemPageAbstractFieldComponent } from '../+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component'; From 607beb1bef379bf2731b93339a9948c779fd9fca Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 2 Apr 2019 15:14:50 +0200 Subject: [PATCH 26/70] Added ClaimedTaskActionsReturnToPoolComponent --- ...task-actions-return-to-pool.component.html | 8 +++ ...task-actions-return-to-pool.component.scss | 0 ...k-actions-return-to-pool.component.spec.ts | 65 +++++++++++++++++++ ...d-task-actions-return-to-pool.component.ts | 32 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html create mode 100644 src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.scss create mode 100644 src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html new file mode 100644 index 0000000000..2002c55528 --- /dev/null +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html @@ -0,0 +1,8 @@ + diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.scss b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts new file mode 100644 index 0000000000..fcb370595a --- /dev/null +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts @@ -0,0 +1,65 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { ClaimedTaskActionsReturnToPoolComponent } from './claimed-task-actions-return-to-pool.component'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; + +let component: ClaimedTaskActionsReturnToPoolComponent; +let fixture: ComponentFixture; + +describe('ClaimedTaskActionsReturnToPoolComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [ClaimedTaskActionsReturnToPoolComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ClaimedTaskActionsReturnToPoolComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ClaimedTaskActionsReturnToPoolComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + }); + + it('should display return to pool button', () => { + const btn = fixture.debugElement.query(By.css('.btn-secondary')); + + expect(btn).toBeDefined(); + }); + + it('should display spin icon when return to pool action is pending', () => { + component.processingReturnToPool = true; + fixture.detectChanges(); + + const span = fixture.debugElement.query(By.css('.btn-secondary .fa-spin')); + + expect(span).toBeDefined(); + }); + + it('should emit return to pool event', () => { + spyOn(component.returnToPool, 'emit'); + + component.confirmApprove(); + fixture.detectChanges(); + + expect(component.returnToPool.emit).toHaveBeenCalled(); + }); + +}); diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts new file mode 100644 index 0000000000..381b8f1afe --- /dev/null +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts @@ -0,0 +1,32 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'ds-claimed-task-actions-return-to-pool', + styleUrls: ['./claimed-task-actions-return-to-pool.component.scss'], + templateUrl: './claimed-task-actions-return-to-pool.component.html', +}) + +export class ClaimedTaskActionsReturnToPoolComponent { + + /** + * A boolean representing if a return to pool operation is pending + */ + @Input() processingReturnToPool: boolean; + + /** + * CSS classes to append to return to pool button + */ + @Input() wrapperClass: string; + + /** + * An event fired when a return to pool action is confirmed. + */ + @Output() returnToPool: EventEmitter = new EventEmitter(); + + /** + * Emit approve event + */ + confirmApprove() { + this.returnToPool.emit(); + } +} From 16b8e91585c37de1564d83a377b710d1e015ef9d Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 2 Apr 2019 15:18:06 +0200 Subject: [PATCH 27/70] Added tests and comments --- .../my-dspace-configuration.service.ts | 12 + .../my-dspace-page-routing.module.ts | 3 + .../+my-dspace-page/my-dspace-page.module.ts | 4 + .../my-dspace-results.component.ts | 24 +- .../search-configuration-option.model.ts | 11 + ...search-switch-configuration.component.html | 2 +- ...rch-switch-configuration.component.spec.ts | 212 +++++++------- .../search-switch-configuration.component.ts | 32 ++- src/app/core/eperson/models/eperson.model.ts | 4 +- .../normalized-submission-object.model.ts | 8 +- .../models/submission-object.model.ts | 5 + .../user-menu/user-menu.component.spec.ts | 151 ++++++++++ .../user-menu/user-menu.component.ts | 6 + ...laimed-task-actions-approve.component.html | 2 +- ...med-task-actions-approve.component.spec.ts | 65 +++++ .../claimed-task-actions-approve.component.ts | 17 +- .../claimed-task-actions.component.html | 27 +- .../claimed-task-actions.component.spec.ts | 269 ++++++++++++++++++ .../claimed-task-actions.component.ts | 84 ++++-- ...claimed-task-actions-reject.component.html | 20 +- ...imed-task-actions-reject.component.spec.ts | 108 +++++++ .../claimed-task-actions-reject.component.ts | 43 ++- .../item/item-actions.component.spec.ts | 96 +++++++ .../item/item-actions.component.ts | 31 +- .../mydspace-actions-service.factory.ts | 7 + .../mydspace-actions/mydspace-actions.ts | 66 ++++- .../pool-task-actions.component.spec.ts | 170 +++++++++++ .../pool-task/pool-task-actions.component.ts | 63 ++-- .../workflowitem-actions.component.spec.ts | 98 +++++++ .../workflowitem-actions.component.ts | 32 ++- .../workspaceitem-actions.component.spec.ts | 163 +++++++++++ .../workspaceitem-actions.component.ts | 49 +++- src/app/shared/shared.module.ts | 2 + src/app/shared/testing/eperson-mock.ts | 48 ++-- src/app/shared/testing/router-stub.ts | 1 + .../search-configuration-service-stub.ts | 5 +- 36 files changed, 1693 insertions(+), 247 deletions(-) create mode 100644 src/app/shared/auth-nav-menu/user-menu/user-menu.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/claimed-task/approve/claimed-task-actions-approve.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/item/item-actions.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.spec.ts create mode 100644 src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts diff --git a/src/app/+my-dspace-page/my-dspace-configuration.service.ts b/src/app/+my-dspace-page/my-dspace-configuration.service.ts index 3ee91c5f31..420e045887 100644 --- a/src/app/+my-dspace-page/my-dspace-configuration.service.ts +++ b/src/app/+my-dspace-page/my-dspace-configuration.service.ts @@ -72,6 +72,12 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { this.isAdmin$ = this.roleService.isAdmin(); } + /** + * Returns the list of available configuration depend on the user role + * + * @return {Observable} + * Emits the available configuration list + */ public getAvailableConfigurationTypes(): Observable { return combineLatest(this.isSubmitter$, this.isController$, this.isAdmin$).pipe( first(), @@ -87,6 +93,12 @@ export class MyDSpaceConfigurationService extends SearchConfigurationService { })); } + /** + * Returns the select options for the available configuration list + * + * @return {Observable} + * Emits the select options list + */ public getAvailableConfigurationOptions(): Observable { return this.getAvailableConfigurationTypes().pipe( first(), diff --git a/src/app/+my-dspace-page/my-dspace-page-routing.module.ts b/src/app/+my-dspace-page/my-dspace-page-routing.module.ts index 70b758af0d..d70a007e3a 100644 --- a/src/app/+my-dspace-page/my-dspace-page-routing.module.ts +++ b/src/app/+my-dspace-page/my-dspace-page-routing.module.ts @@ -18,5 +18,8 @@ import { MyDSpaceGuard } from './my-dspace.guard'; ]) ] }) +/** + * This module defines the default component to load when navigating to the mydspace page path. + */ export class MyDspacePageRoutingModule { } diff --git a/src/app/+my-dspace-page/my-dspace-page.module.ts b/src/app/+my-dspace-page/my-dspace-page.module.ts index 697c22dd0e..4b8cf37b7a 100644 --- a/src/app/+my-dspace-page/my-dspace-page.module.ts +++ b/src/app/+my-dspace-page/my-dspace-page.module.ts @@ -60,6 +60,10 @@ import { MyDSpaceConfigurationService } from './my-dspace-configuration.service' PoolMyDSpaceResultDetailElementComponent ] }) + +/** + * This module handles all components that are necessary for the mydspace page + */ export class MyDSpacePageModule { } diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts index e6a086fd46..3a16def9c1 100644 --- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts +++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts @@ -3,7 +3,6 @@ import { Component, Input } from '@angular/core'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { fadeIn, fadeInOut } from '../../shared/animations/fade'; -import { SortOptions } from '../../core/cache/models/sort-options.model'; import { MyDSpaceResult } from '../my-dspace-result.model'; import { SearchOptions } from '../../+search-page/search-options.model'; import { PaginatedList } from '../../core/data/paginated-list'; @@ -11,9 +10,7 @@ import { ViewMode } from '../../core/shared/view-mode.model'; import { isEmpty } from '../../shared/empty.util'; /** - * This component renders a simple item page. - * The route parameter 'id' is used to request the item it represents. - * All fields of the item that should be displayed, are defined in its template. + * Component that represents all results for mydspace page */ @Component({ selector: 'ds-my-dspace-results', @@ -24,13 +21,30 @@ import { isEmpty } from '../../shared/empty.util'; ] }) export class MyDSpaceResultsComponent { + + /** + * The actual search result objects + */ @Input() searchResults: RemoteData>>; + + /** + * The current configuration of the search + */ @Input() searchConfig: SearchOptions; - @Input() sortConfig: SortOptions; + + /** + * The current view mode for the search results + */ @Input() viewMode: ViewMode; + /** + * A boolean representing if search results entry are separated by a line + */ hasBorder = true; + /** + * Check if mydspace search results are loading + */ isLoading() { return !this.searchResults || isEmpty(this.searchResults) || this.searchResults.isLoading; } diff --git a/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts b/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts index 7f9b4acd96..6f9a72da48 100644 --- a/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts +++ b/src/app/+search-page/search-switch-configuration/search-configuration-option.model.ts @@ -1,4 +1,15 @@ +/** + * Represents a search configuration select option + */ export interface SearchConfigurationOption { + + /** + * The select option value + */ value: string; + + /** + * The select option label + */ label: string; } diff --git a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html index 5b1bdc1ddd..8df37214d1 100644 --- a/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html +++ b/src/app/+search-page/search-switch-configuration/search-switch-configuration.component.html @@ -4,7 +4,7 @@ - diff --git a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts new file mode 100644 index 0000000000..d7e0b53748 --- /dev/null +++ b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.spec.ts @@ -0,0 +1,108 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; +import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { By } from '@angular/platform-browser'; + +import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { ClaimedTaskActionsRejectComponent } from './claimed-task-actions-reject.component'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; + +let component: ClaimedTaskActionsRejectComponent; +let fixture: ComponentFixture; +let formBuilder: FormBuilder; +let modalService: NgbModal; + +describe('ClaimedTaskActionsRejectComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NgbModule.forRoot(), + ReactiveFormsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [ClaimedTaskActionsRejectComponent], + providers: [ + FormBuilder, + NgbModal + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ClaimedTaskActionsRejectComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ClaimedTaskActionsRejectComponent); + component = fixture.componentInstance; + formBuilder = TestBed.get(FormBuilder); + modalService = TestBed.get(NgbModal); + component.modalRef = modalService.open('ok'); + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + modalService = null; + formBuilder = null; + }); + + it('should init reject form properly', () => { + expect(component.rejectForm).toBeDefined(); + expect(component.rejectForm instanceof FormGroup).toBeTruthy(); + expect(component.rejectForm.controls.reason).toBeDefined(); + }); + + it('should display reject button', () => { + const btn = fixture.debugElement.query(By.css('.btn-danger')); + + expect(btn).toBeDefined(); + }); + + it('should display spin icon when reject is pending', () => { + component.processingReject = true; + fixture.detectChanges(); + + const span = fixture.debugElement.query(By.css('.btn-danger .fa-spin')); + + expect(span).toBeDefined(); + }); + + it('should call openRejectModal on reject button click', fakeAsync(() => { + spyOn(component.rejectForm, 'reset'); + const btn = fixture.debugElement.query(By.css('.btn-danger')); + btn.nativeElement.click(); + fixture.detectChanges(); + + expect(component.rejectForm.reset).toHaveBeenCalled(); + expect(component.modalRef).toBeDefined(); + + component.modalRef.close() + })); + + it('should call confirmReject on form submit', fakeAsync(() => { + spyOn(component.reject, 'emit'); + + const btn = fixture.debugElement.query(By.css('.btn-danger')); + btn.nativeElement.click(); + fixture.detectChanges(); + + expect(component.modalRef).toBeDefined(); + + const form = ((document as any).querySelector('form')); + form.dispatchEvent(new Event('ngSubmit')); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(component.reject.emit).toHaveBeenCalled(); + }); + + })); +}); diff --git a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.ts b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.ts index 7f09896b4c..b66c104695 100644 --- a/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.ts +++ b/src/app/shared/mydspace-actions/claimed-task/reject/claimed-task-actions-reject.component.ts @@ -10,18 +10,45 @@ import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; }) export class ClaimedTaskActionsRejectComponent implements OnInit { + + /** + * A boolean representing if a reject operation is pending + */ @Input() processingReject: boolean; - @Input() taskId: string; + + /** + * CSS classes to append to reject button + */ @Input() wrapperClass: string; + /** + * An event fired when a reject action is confirmed. + * Event's payload equals to reject reason. + */ @Output() reject: EventEmitter = new EventEmitter(); + /** + * The reject form group + */ public rejectForm: FormGroup; + + /** + * Reference to NgbModal + */ public modalRef: NgbModalRef; + /** + * Initialize instance variables + * + * @param {FormBuilder} formBuilder + * @param {NgbModal} modalService + */ constructor(private formBuilder: FormBuilder, private modalService: NgbModal) { } + /** + * Initialize form + */ ngOnInit() { this.rejectForm = this.formBuilder.group({ reason: ['', Validators.required] @@ -29,15 +56,23 @@ export class ClaimedTaskActionsRejectComponent implements OnInit { } - click() { + /** + * Close modal and emit reject event + */ + confirmReject() { this.processingReject = true; this.modalRef.close('Send Button'); const reason = this.rejectForm.get('reason').value; this.reject.emit(reason); } - openRejectModal(rejectModal) { + /** + * Open modal + * + * @param content + */ + openRejectModal(content: any) { this.rejectForm.reset(); - this.modalRef = this.modalService.open(rejectModal); + this.modalRef = this.modalService.open(content); } } diff --git a/src/app/shared/mydspace-actions/item/item-actions.component.spec.ts b/src/app/shared/mydspace-actions/item/item-actions.component.spec.ts new file mode 100644 index 0000000000..72be122c8f --- /dev/null +++ b/src/app/shared/mydspace-actions/item/item-actions.component.spec.ts @@ -0,0 +1,96 @@ +import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; + +import { of as observableOf } from 'rxjs'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { MockTranslateLoader } from '../../mocks/mock-translate-loader'; +import { RouterStub } from '../../testing/router-stub'; +import { Item } from '../../../core/shared/item.model'; +import { ItemActionsComponent } from './item-actions.component'; +import { ItemDataService } from '../../../core/data/item-data.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; + +let component: ItemActionsComponent; +let fixture: ComponentFixture; + +let mockObject: Item; + +const mockDataService = {}; + +mockObject = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); + +describe('ItemActionsComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [ItemActionsComponent], + providers: [ + { provide: Injector, useValue: {} }, + { provide: Router, useValue: new RouterStub() }, + { provide: ItemDataService, useValue: mockDataService }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemActionsComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemActionsComponent); + component = fixture.componentInstance; + component.object = mockObject; + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + }); + + it('should init object properly', () => { + component.object = null; + component.initObjects(mockObject); + + expect(component.object).toEqual(mockObject); + }); + +}); diff --git a/src/app/shared/mydspace-actions/item/item-actions.component.ts b/src/app/shared/mydspace-actions/item/item-actions.component.ts index b2022bbdd4..0760fe54e0 100644 --- a/src/app/shared/mydspace-actions/item/item-actions.component.ts +++ b/src/app/shared/mydspace-actions/item/item-actions.component.ts @@ -1,11 +1,17 @@ import { Component, Injector, Input } from '@angular/core'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; + import { MyDSpaceActionsComponent } from '../mydspace-actions'; -import { ResourceType } from '../../../core/shared/resource-type'; import { ItemDataService } from '../../../core/data/item-data.service'; import { Item } from '../../../core/shared/item.model'; +import { ResourceType } from '../../../core/shared/resource-type'; +import { NotificationsService } from '../../notifications/notifications.service'; +/** + * This component represents mydspace actions related to Item object. + */ @Component({ selector: 'ds-item-actions', styleUrls: ['./item-actions.component.scss'], @@ -13,13 +19,32 @@ import { Item } from '../../../core/shared/item.model'; }) export class ItemActionsComponent extends MyDSpaceActionsComponent { + + /** + * The Item object + */ @Input() object: Item; + /** + * Initialize instance variables + * + * @param {Injector} injector + * @param {Router} router + * @param {NotificationsService} notificationsService + * @param {TranslateService} translate + */ constructor(protected injector: Injector, - protected router: Router) { - super(ResourceType.Workspaceitem, injector, router); + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService) { + super(ResourceType.Item, injector, router, notificationsService, translate); } + /** + * Init the target object + * + * @param {Item} object + */ initObjects(object: Item) { this.object = object; } diff --git a/src/app/shared/mydspace-actions/mydspace-actions-service.factory.ts b/src/app/shared/mydspace-actions/mydspace-actions-service.factory.ts index b3efa4c9db..7aa948f689 100644 --- a/src/app/shared/mydspace-actions/mydspace-actions-service.factory.ts +++ b/src/app/shared/mydspace-actions/mydspace-actions-service.factory.ts @@ -5,10 +5,17 @@ import { ClaimedTaskDataService } from '../../core/tasks/claimed-task-data.servi import { PoolTaskDataService } from '../../core/tasks/pool-task-data.service'; import { WorkflowitemDataService } from '../../core/submission/workflowitem-data.service'; import { CacheableObject } from '../../core/cache/object-cache.reducer'; +import { ItemDataService } from '../../core/data/item-data.service'; +/** + * Class to return DataService for given ResourceType + */ export class MydspaceActionsServiceFactory> { public getConstructor(type: ResourceType): TService { switch (type) { + case ResourceType.Item: { + return ItemDataService as any; + } case ResourceType.Workspaceitem: { return WorkspaceitemDataService as any; } diff --git a/src/app/shared/mydspace-actions/mydspace-actions.ts b/src/app/shared/mydspace-actions/mydspace-actions.ts index ab76eaf280..8e465644c3 100644 --- a/src/app/shared/mydspace-actions/mydspace-actions.ts +++ b/src/app/shared/mydspace-actions/mydspace-actions.ts @@ -8,19 +8,55 @@ import { RemoteData } from '../../core/data/remote-data'; import { DataService } from '../../core/data/data.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { ResourceType } from '../../core/shared/resource-type'; +import { NotificationOptions } from '../notifications/models/notification-options.model'; +import { NotificationsService } from '../notifications/notifications.service'; +import { TranslateService } from '@ngx-translate/core'; +/** + * Abstract class for all different representations of mydspace actions + */ export abstract class MyDSpaceActionsComponent> { + + /** + * The target mydspace object + */ @Input() abstract object: T; + + /** + * Instance of DataService realted to mydspace object + */ protected objectDataService: TService; - constructor(protected objectType: ResourceType, protected injector: Injector, protected router: Router) { + /** + * Initialize instance variables + * + * @param {ResourceType} objectType + * @param {Injector} injector + * @param {Router} router + * @param {NotificationsService} notificationsService + * @param {TranslateService} translate + */ + constructor( + protected objectType: ResourceType, + protected injector: Injector, + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService) { const factory = new MydspaceActionsServiceFactory(); this.objectDataService = injector.get(factory.getConstructor(objectType)); } + /** + * Abstract method called to init the target object + * + * @param {T} object + */ abstract initObjects(object: T): void; - reload() { + /** + * Refresh current page + */ + reload(): void { // override the route reuse strategy this.router.routeReuseStrategy.shouldReuseRoute = () => { return false; @@ -30,12 +66,34 @@ export abstract class MyDSpaceActionsComponent) => rd.hasSucceeded) ).subscribe((rd: RemoteData) => { this.initObjects(rd.payload as T); }); } + + /** + * Handle action response and show properly notification + * + * @param result + * true on success, false otherwise + */ + handleActionResponse(result: boolean): void { + if (result) { + this.reload(); + this.notificationsService.success(null, + this.translate.get('submission.workflow.tasks.generic.success'), + new NotificationOptions(5000, false)); + } else { + this.notificationsService.error(null, + this.translate.get('submission.workflow.tasks.generic.error'), + new NotificationOptions(20000, true)); + } + } } diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts new file mode 100644 index 0000000000..1c0e8e71fa --- /dev/null +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts @@ -0,0 +1,170 @@ +import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { By } from '@angular/platform-browser'; + +import { of as observableOf } from 'rxjs'; +import { cold } from 'jasmine-marbles'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { MockTranslateLoader } from '../../mocks/mock-translate-loader'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; +import { RouterStub } from '../../testing/router-stub'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Item } from '../../../core/shared/item.model'; +import { PoolTaskDataService } from '../../../core/tasks/pool-task-data.service'; +import { PoolTaskActionsComponent } from './pool-task-actions.component'; +import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; +import { Workflowitem } from '../../../core/submission/models/workflowitem.model'; + +let component: PoolTaskActionsComponent; +let fixture: ComponentFixture; + +let mockObject: PoolTask; +let notificationsServiceStub: NotificationsServiceStub; +let router: RouterStub; + +const mockDataService = jasmine.createSpyObj('PoolTaskDataService', { + claimTask: jasmine.createSpy('claimTask') +}); + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rdItem = new RemoteData(false, false, true, null, item); +const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem), id: '1234' }); + +describe('PoolTaskActionsComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [PoolTaskActionsComponent], + providers: [ + { provide: Injector, useValue: {} }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: Router, useValue: new RouterStub() }, + { provide: PoolTaskDataService, useValue: mockDataService }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PoolTaskActionsComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PoolTaskActionsComponent); + component = fixture.componentInstance; + component.object = mockObject; + notificationsServiceStub = TestBed.get(NotificationsService); + router = TestBed.get(Router); + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + }); + + it('should init objects properly', () => { + component.object = null; + component.initObjects(mockObject); + + expect(component.object).toEqual(mockObject); + + expect(component.workflowitem$).toBeObservable(cold('(b|)', { + b: rdWorkflowitem.payload + })) + }); + + it('should display claim task button', () => { + const btn = fixture.debugElement.query(By.css('.btn-info')); + + expect(btn).toBeDefined(); + }); + + it('should call claimTask method on claim', fakeAsync(() => { + spyOn(component, 'reload'); + mockDataService.claimTask.and.returnValue(observableOf({hasSucceeded: true})); + + component.claim(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(mockDataService.claimTask).toHaveBeenCalledWith(mockObject.id); + }); + + })); + + it('should display a success notification on claim success', async(() => { + spyOn(component, 'reload'); + mockDataService.claimTask.and.returnValue(observableOf({hasSucceeded: true})); + + component.claim(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(notificationsServiceStub.success).toHaveBeenCalled(); + }); + })); + + it('should reload page on claim success', async(() => { + spyOn(router, 'navigateByUrl'); + router.url = 'test.url/test'; + mockDataService.claimTask.and.returnValue(observableOf({hasSucceeded: true})); + + component.claim(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(router.navigateByUrl).toHaveBeenCalledWith('test.url/test'); + }); + })); + + it('should display an error notification on claim failure', async(() => { + mockDataService.claimTask.and.returnValue(observableOf({hasSucceeded: false})); + + component.claim(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(notificationsServiceStub.error).toHaveBeenCalled(); + }); + })); + +}); diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts index eccd427668..bd8f3f1a37 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts @@ -10,35 +10,64 @@ import { ProcessTaskResponse } from '../../../core/tasks/models/process-task-res import { RemoteData } from '../../../core/data/remote-data'; import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; import { PoolTaskDataService } from '../../../core/tasks/pool-task-data.service'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationOptions } from '../../notifications/models/notification-options.model'; import { isNotUndefined } from '../../empty.util'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { ResourceType } from '../../../core/shared/resource-type'; +import { NotificationsService } from '../../notifications/notifications.service'; +/** + * This component represents mydspace actions related to PoolTask object. + */ @Component({ selector: 'ds-pool-task-actions', styleUrls: ['./pool-task-actions.component.scss'], templateUrl: './pool-task-actions.component.html', }) - export class PoolTaskActionsComponent extends MyDSpaceActionsComponent { + + /** + * The PoolTask object + */ @Input() object: PoolTask; + /** + * A boolean representing if a claim operation is pending + * @type {BehaviorSubject} + */ public processingClaim$ = new BehaviorSubject(false); + + /** + * The workflowitem object that belonging to the PoolTask object + */ public workflowitem$: Observable; + /** + * Initialize instance variables + * + * @param {Injector} injector + * @param {Router} router + * @param {NotificationsService} notificationsService + * @param {TranslateService} translate + */ constructor(protected injector: Injector, protected router: Router, - private notificationsService: NotificationsService, - private translate: TranslateService) { - super(ResourceType.PoolTask, injector, router); + protected notificationsService: NotificationsService, + protected translate: TranslateService) { + super(ResourceType.PoolTask, injector, router, notificationsService, translate); } + /** + * Initialize objects + */ ngOnInit() { this.initObjects(this.object); } + /** + * Init the PoolTask and Workflowitem objects + * + * @param {PoolTask} object + */ initObjects(object: PoolTask) { this.object = object; this.workflowitem$ = (this.object.workflowitem as Observable>).pipe( @@ -46,27 +75,15 @@ export class PoolTaskActionsComponent extends MyDSpaceActionsComponent) => rd.payload)); } + /** + * Claim the task. + */ claim() { this.processingClaim$.next(true); this.objectDataService.claimTask(this.object.id) .subscribe((res: ProcessTaskResponse) => { - this.responseHandle(res); + this.handleActionResponse(res.hasSucceeded); + this.processingClaim$.next(false); }); } - - private responseHandle(res: ProcessTaskResponse) { - if (res.hasSucceeded) { - this.processingClaim$.next(false); - this.reload(); - this.notificationsService.success(null, - this.translate.get('submission.workflow.tasks.generic.success'), - new NotificationOptions(5000, false)); - } else { - this.processingClaim$.next(false); - this.notificationsService.error(null, - this.translate.get('submission.workflow.tasks.generic.error'), - new NotificationOptions(20000, true)); - } - } - } diff --git a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.spec.ts b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.spec.ts new file mode 100644 index 0000000000..7533565afe --- /dev/null +++ b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.spec.ts @@ -0,0 +1,98 @@ +import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; + +import { of as observableOf } from 'rxjs'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { MockTranslateLoader } from '../../mocks/mock-translate-loader'; +import { RouterStub } from '../../testing/router-stub'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Item } from '../../../core/shared/item.model'; +import { Workflowitem } from '../../../core/submission/models/workflowitem.model'; +import { WorkflowitemActionsComponent } from './workflowitem-actions.component'; +import { WorkflowitemDataService } from '../../../core/submission/workflowitem-data.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; + +let component: WorkflowitemActionsComponent; +let fixture: ComponentFixture; + +let mockObject: Workflowitem; + +const mockDataService = {}; + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockObject = Object.assign(new Workflowitem(), { item: observableOf(rd), id: '1234', uuid: '1234' }); + +describe('WorkflowitemActionsComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [WorkflowitemActionsComponent], + providers: [ + { provide: Injector, useValue: {} }, + { provide: Router, useValue: new RouterStub() }, + { provide: WorkflowitemDataService, useValue: mockDataService }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkflowitemActionsComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WorkflowitemActionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + }); + + it('should init object properly', () => { + component.initObjects(mockObject); + + expect(component.object).toEqual(mockObject); + }); + +}); diff --git a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts index 04de5da885..a6304bf5d4 100644 --- a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts @@ -1,25 +1,49 @@ import { Component, Injector, Input } from '@angular/core'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; + import { MyDSpaceActionsComponent } from '../mydspace-actions'; -import { ResourceType } from '../../../core/shared/resource-type'; import { Workflowitem } from '../../../core/submission/models/workflowitem.model'; import { WorkflowitemDataService } from '../../../core/submission/workflowitem-data.service'; +import { ResourceType } from '../../../core/shared/resource-type'; +import { NotificationsService } from '../../notifications/notifications.service'; +/** + * This component represents mydspace actions related to Workflowitem object. + */ @Component({ selector: 'ds-workflowitem-actions', styleUrls: ['./workflowitem-actions.component.scss'], templateUrl: './workflowitem-actions.component.html', }) - export class WorkflowitemActionsComponent extends MyDSpaceActionsComponent { + + /** + * The Workflowitem object + */ @Input() object: Workflowitem; + /** + * Initialize instance variables + * + * @param {Injector} injector + * @param {Router} router + * @param {NotificationsService} notificationsService + * @param {TranslateService} translate + */ constructor(protected injector: Injector, - protected router: Router) { - super(ResourceType.Workflowitem, injector, router); + protected router: Router, + protected notificationsService: NotificationsService, + protected translate: TranslateService) { + super(ResourceType.Workflowitem, injector, router, notificationsService, translate); } + /** + * Init the target object + * + * @param {Workflowitem} object + */ initObjects(object: Workflowitem) { this.object = object; } diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts new file mode 100644 index 0000000000..ec8bc4a11c --- /dev/null +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts @@ -0,0 +1,163 @@ +import { ChangeDetectionStrategy, Injector, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; +import { By } from '@angular/platform-browser'; + +import { of as observableOf } from 'rxjs'; +import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { MockTranslateLoader } from '../../mocks/mock-translate-loader'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; +import { RouterStub } from '../../testing/router-stub'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Item } from '../../../core/shared/item.model'; +import { Workspaceitem } from '../../../core/submission/models/workspaceitem.model'; +import { WorkspaceitemActionsComponent } from './workspaceitem-actions.component'; +import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; + +let component: WorkspaceitemActionsComponent; +let fixture: ComponentFixture; + +let mockObject: Workspaceitem; +let notificationsServiceStub: NotificationsServiceStub; + +const mockDataService = jasmine.createSpyObj('WorkspaceitemDataService', { + delete: jasmine.createSpy('delete') +}); + +const item = Object.assign(new Item(), { + bitstreams: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.type': [ + { + language: null, + value: 'Article' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ] + } +}); +const rd = new RemoteData(false, false, true, null, item); +mockObject = Object.assign(new Workspaceitem(), { item: observableOf(rd), id: '1234', uuid: '1234' }); + +describe('WorkspaceitemActionsComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NgbModule.forRoot(), + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [WorkspaceitemActionsComponent], + providers: [ + { provide: Injector, useValue: {} }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: Router, useValue: new RouterStub() }, + { provide: WorkspaceitemDataService, useValue: mockDataService }, + NgbModal + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(WorkspaceitemActionsComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WorkspaceitemActionsComponent); + component = fixture.componentInstance; + component.object = mockObject; + notificationsServiceStub = TestBed.get(NotificationsService); + fixture.detectChanges(); + }); + + afterEach(() => { + fixture = null; + component = null; + }); + + it('should init object properly', () => { + component.object = null; + component.initObjects(mockObject); + + expect(component.object).toEqual(mockObject); + }); + + it('should display edit button', () => { + const btn = fixture.debugElement.query(By.css('.btn-primary')); + + expect(btn).toBeDefined(); + }); + + it('should display delete button', () => { + const btn = fixture.debugElement.query(By.css('.btn-danger')); + + expect(btn).toBeDefined(); + }); + + it('should call confirmDiscard on discard confirmation', fakeAsync(() => { + mockDataService.delete.and.returnValue(observableOf(true)); + spyOn(component, 'reload'); + const btn = fixture.debugElement.query(By.css('.btn-danger')); + btn.nativeElement.click(); + fixture.detectChanges(); + + const confirmBtn: any = ((document as any).querySelector('.modal-footer .btn-danger')); + confirmBtn.click(); + + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(mockDataService.delete).toHaveBeenCalledWith(mockObject); + }); + + })); + + it('should display a success notification on delete success', async(() => { + spyOn((component as any).modalService, 'open').and.returnValue({result: Promise.resolve('ok')}); + mockDataService.delete.and.returnValue(observableOf(true)); + spyOn(component, 'reload'); + + component.confirmDiscard('ok'); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(notificationsServiceStub.success).toHaveBeenCalled(); + }); + })); + + it('should display an error notification on delete failure', async(() => { + spyOn((component as any).modalService, 'open').and.returnValue({result: Promise.resolve('ok')}); + mockDataService.delete.and.returnValue(observableOf(false)); + spyOn(component, 'reload'); + + component.confirmDiscard('ok'); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(notificationsServiceStub.error).toHaveBeenCalled(); + }); + })); +}); diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts index c05eb557d2..cea4c3746e 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts @@ -7,50 +7,71 @@ import { TranslateService } from '@ngx-translate/core'; import { Workspaceitem } from '../../../core/submission/models/workspaceitem.model'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; -import { SubmissionRestService } from '../../../core/submission/submission-rest.service'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; import { ResourceType } from '../../../core/shared/resource-type'; import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationOptions } from '../../notifications/models/notification-options.model'; +/** + * This component represents mydspace actions related to Workspaceitem object. + */ @Component({ selector: 'ds-workspaceitem-actions', styleUrls: ['./workspaceitem-actions.component.scss'], templateUrl: './workspaceitem-actions.component.html', }) - export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent { + + /** + * The workspaceitem object + */ @Input() object: Workspaceitem; + /** + * A boolean representing if a delete operation is pending + * @type {BehaviorSubject} + */ public processingDelete$ = new BehaviorSubject(false); + /** + * Initialize instance variables + * + * @param {Injector} injector + * @param {Router} router + * @param {NgbModal} modalService + * @param {NotificationsService} notificationsService + * @param {TranslateService} translate + */ constructor(protected injector: Injector, protected router: Router, - private modalService: NgbModal, - private notificationsService: NotificationsService, - private restService: SubmissionRestService, - private translate: TranslateService) { - super(ResourceType.Workspaceitem, injector, router); + protected modalService: NgbModal, + protected notificationsService: NotificationsService, + protected translate: TranslateService) { + super(ResourceType.Workspaceitem, injector, router, notificationsService, translate); } + /** + * Delete the target workspaceitem object + */ public confirmDiscard(content) { this.modalService.open(content).result.then( (result) => { if (result === 'ok') { this.processingDelete$.next(true); - this.restService.deleteById(this.object.id) - .subscribe(() => { - this.notificationsService.success(null, - this.translate.get('submission.workflow.tasks.generic.success'), - new NotificationOptions(5000, false)); + this.objectDataService.delete(this.object) + .subscribe((response: boolean) => { this.processingDelete$.next(false); - this.reload(); + this.handleActionResponse(response); }) } } ); } + /** + * Init the target object + * + * @param {Workspaceitem} object + */ initObjects(object: Workspaceitem) { this.object = object; } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index a5a426f1a7..00f357cda6 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -140,6 +140,7 @@ import { MetadataValuesComponent } from '../+item-page/field-components/metadata import { MetadataUriValuesComponent } from '../+item-page/field-components/metadata-uri-values/metadata-uri-values.component'; import { RoleDirective } from './roles/role.directive'; import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component'; +import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -234,6 +235,7 @@ const COMPONENTS = [ ClaimedTaskActionsComponent, ClaimedTaskActionsApproveComponent, ClaimedTaskActionsRejectComponent, + ClaimedTaskActionsReturnToPoolComponent, ItemActionsComponent, PoolTaskActionsComponent, WorkflowitemActionsComponent, diff --git a/src/app/shared/testing/eperson-mock.ts b/src/app/shared/testing/eperson-mock.ts index ef27f4983d..c822fc15d6 100644 --- a/src/app/shared/testing/eperson-mock.ts +++ b/src/app/shared/testing/eperson-mock.ts @@ -13,26 +13,30 @@ export const EPersonMock: EPerson = Object.assign(new EPerson(),{ id: 'testid', uuid: 'testid', type: 'eperson', - metadata: [ - { - key: 'dc.title', - language: null, - value: 'User Test' - }, - { - key: 'eperson.firstname', - language: null, - value: 'User' - }, - { - key: 'eperson.lastname', - language: null, - value: 'Test' - }, - { - key: 'eperson.language', - language: null, - value: 'en' - } - ] + metadata: { + 'dc.title': [ + { + language: null, + value: 'User Test' + } + ], + 'eperson.firstname': [ + { + language: null, + value: 'User' + } + ], + 'eperson.lastname': [ + { + language: null, + value: 'Test' + }, + ], + 'eperson.language': [ + { + language: null, + value: 'en' + }, + ] + } }); diff --git a/src/app/shared/testing/router-stub.ts b/src/app/shared/testing/router-stub.ts index 31c09c41e3..210ee91fdf 100644 --- a/src/app/shared/testing/router-stub.ts +++ b/src/app/shared/testing/router-stub.ts @@ -1,6 +1,7 @@ export class RouterStub { url: string; + routeReuseStrategy = {shouldReuseRoute: {}}; //noinspection TypeScriptUnresolvedFunction navigate = jasmine.createSpy('navigate'); parseUrl = jasmine.createSpy('parseUrl'); diff --git a/src/app/shared/testing/search-configuration-service-stub.ts b/src/app/shared/testing/search-configuration-service-stub.ts index 4c9d94c877..4c9402afb1 100644 --- a/src/app/shared/testing/search-configuration-service-stub.ts +++ b/src/app/shared/testing/search-configuration-service-stub.ts @@ -10,7 +10,10 @@ export class SearchConfigurationServiceStub { } getCurrentScope(a) { - return observableOf('test-id') + return observableOf('test-id'); } + getCurrentConfiguration(a) { + return observableOf(a); + } } From 49aee1898bcae93b2ee5f5f5c17e135ddbc45b0c Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 2 Apr 2019 16:25:50 +0200 Subject: [PATCH 28/70] Added tests and comments --- ...-dspace-result-detail-element.component.ts | 14 +- .../object-detail.component.spec.ts | 181 ++++++++++++++++++ .../object-detail/object-detail.component.ts | 52 ++++- .../wrapper-detail-element.component.spec.ts | 24 ++- .../wrapper-detail-element.component.ts | 22 +++ ...my-dspace-result-list-element.component.ts | 15 +- .../object-list/object-list.component.spec.ts | 2 +- .../shared/pagination/pagination.component.ts | 2 +- 8 files changed, 290 insertions(+), 22 deletions(-) diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts index 3efb668c5a..4017026396 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts @@ -10,12 +10,20 @@ import { Metadata } from '../../../core/shared/metadata.utils'; selector: 'ds-my-dspace-result-detail-element', template: `` }) - export class MyDSpaceResultDetailElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { + + /** + * The result element object + */ dso: K; - public constructor(@Inject('objectElementProvider') public gridable: ListableObject) { - super(gridable); + /** + * Initialize instance variables + * + * @param {ListableObject} detailable + */ + public constructor(@Inject('objectElementProvider') public detailable: ListableObject) { + super(detailable); this.dso = this.object.dspaceObject; } diff --git a/src/app/shared/object-detail/object-detail.component.spec.ts b/src/app/shared/object-detail/object-detail.component.spec.ts index e69de29bb2..9b81f1019f 100644 --- a/src/app/shared/object-detail/object-detail.component.spec.ts +++ b/src/app/shared/object-detail/object-detail.component.spec.ts @@ -0,0 +1,181 @@ +import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { ObjectDetailComponent } from './object-detail.component'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { MockTranslateLoader } from '../mocks/mock-translate-loader'; +import { RemoteData } from '../../core/data/remote-data'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { PageInfo } from '../../core/shared/page-info.model'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +describe('ObjectDetailComponent', () => { + let comp: ObjectDetailComponent; + let fixture: ComponentFixture; + const testEvent = {test: 'test'}; + + const testObjects = [ + { one: 1 }, + { two: 2 }, + { three: 3 }, + { four: 4 }, + { five: 5 }, + { six: 6 }, + { seven: 7 }, + { eight: 8 }, + { nine: 9 }, + { ten: 10 } + ]; + const pageInfo = Object.assign(new PageInfo(), {elementsPerPage: 1, totalElements: 10, totalPages: 10, currentPage: 1}) + const mockRD = new RemoteData(false, false, true, null, new PaginatedList(pageInfo, testObjects)); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NoopAnimationsModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [ObjectDetailComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ObjectDetailComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ObjectDetailComponent); + comp = fixture.componentInstance; // SearchPageComponent test instance + comp.objects = mockRD; + fixture.detectChanges(); + }); + + describe('when the pageChange output on the pagination is triggered', () => { + beforeEach(() => { + spyOn(comp, 'onPageChange'); + const paginationEl = fixture.debugElement.query(By.css('ds-pagination')); + paginationEl.triggerEventHandler('pageChange', testEvent); + }); + + it('should call onPageChange on the component', () => { + expect(comp.onPageChange).toHaveBeenCalledWith(testEvent); + }); + }); + + describe('when the pageSizeChange output on the pagination is triggered', () => { + beforeEach(() => { + spyOn(comp, 'onPageSizeChange'); + const paginationEl = fixture.debugElement.query(By.css('ds-pagination')); + paginationEl.triggerEventHandler('pageSizeChange', testEvent); + }); + + it('should call onPageSizeChange on the component', () => { + expect(comp.onPageSizeChange).toHaveBeenCalledWith(testEvent); + }); + }); + + describe('when the sortDirectionChange output on the pagination is triggered', () => { + beforeEach(() => { + spyOn(comp, 'onSortDirectionChange'); + const paginationEl = fixture.debugElement.query(By.css('ds-pagination')); + paginationEl.triggerEventHandler('sortDirectionChange', testEvent); + }); + + it('should call onSortDirectionChange on the component', () => { + expect(comp.onSortDirectionChange).toHaveBeenCalledWith(testEvent); + }); + }); + + describe('when the sortFieldChange output on the pagination is triggered', () => { + beforeEach(() => { + spyOn(comp, 'onSortFieldChange'); + const paginationEl = fixture.debugElement.query(By.css('ds-pagination')); + paginationEl.triggerEventHandler('sortFieldChange', testEvent); + }); + + it('should call onSortFieldChange on the component', () => { + expect(comp.onSortFieldChange).toHaveBeenCalledWith(testEvent); + }); + }); + + describe('when the paginationChange output on the pagination is triggered', () => { + beforeEach(() => { + spyOn(comp, 'onPaginationChange'); + const paginationEl = fixture.debugElement.query(By.css('ds-pagination')); + paginationEl.triggerEventHandler('paginationChange', testEvent); + }); + + it('should call onPaginationChange on the component', () => { + expect(comp.onPaginationChange).toHaveBeenCalledWith(testEvent); + }); + }); + + describe('when onPageChange is triggered with an event', () => { + beforeEach(() => { + spyOn(comp.pageChange, 'emit'); + comp.onPageChange(testEvent); + }); + + it('should emit the value from the pageChange EventEmitter', fakeAsync(() => { + tick(1); + expect(comp.pageChange.emit).toHaveBeenCalled(); + expect(comp.pageChange.emit).toHaveBeenCalledWith(testEvent); + })); + }); + + describe('when onPageSizeChange is triggered with an event', () => { + beforeEach(() => { + spyOn(comp.pageSizeChange, 'emit'); + comp.onPageSizeChange(testEvent); + }); + + it('should emit the value from the pageSizeChange EventEmitter', fakeAsync(() => { + tick(1); + expect(comp.pageSizeChange.emit).toHaveBeenCalled(); + expect(comp.pageSizeChange.emit).toHaveBeenCalledWith(testEvent); + })); + }); + + describe('when onSortDirectionChange is triggered with an event', () => { + beforeEach(() => { + spyOn(comp.sortDirectionChange, 'emit'); + comp.onSortDirectionChange(testEvent); + }); + + it('should emit the value from the sortDirectionChange EventEmitter', fakeAsync(() => { + tick(1); + expect(comp.sortDirectionChange.emit).toHaveBeenCalled(); + expect(comp.sortDirectionChange.emit).toHaveBeenCalledWith(testEvent); + })); + }); + + describe('when onSortFieldChange is triggered with an event', () => { + beforeEach(() => { + spyOn(comp.sortFieldChange, 'emit'); + comp.onSortFieldChange(testEvent); + }); + + it('should emit the value from the sortFieldChange EventEmitter', fakeAsync(() => { + tick(1); + expect(comp.sortFieldChange.emit).toHaveBeenCalled(); + expect(comp.sortFieldChange.emit).toHaveBeenCalledWith(testEvent); + })); + }); + + describe('when onPaginationChange is triggered with an event', () => { + beforeEach(() => { + spyOn(comp.paginationChange, 'emit'); + comp.onPaginationChange(testEvent); + }); + + it('should emit the value from the paginationChange EventEmitter', fakeAsync(() => { + tick(1); + expect(comp.paginationChange.emit).toHaveBeenCalled(); + expect(comp.paginationChange.emit).toHaveBeenCalledWith(testEvent); + })); + }); +}); diff --git a/src/app/shared/object-detail/object-detail.component.ts b/src/app/shared/object-detail/object-detail.component.ts index bdbb360be6..dad5951e46 100644 --- a/src/app/shared/object-detail/object-detail.component.ts +++ b/src/app/shared/object-detail/object-detail.component.ts @@ -24,17 +24,44 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o templateUrl: './object-detail.component.html', animations: [fadeIn] }) - export class ObjectDetailComponent { + /** + * Pagination options object + */ @Input() config: PaginationComponentOptions; + + /** + * Sort options object + */ @Input() sortConfig: SortOptions; - @Input() hideGear = false; + + /** + * A boolean representing if to hide gear pagination icon + */ + @Input() hideGear = true; + + /** + * A boolean representing if to hide pagination when there is only a page + */ @Input() hidePagerWhenSinglePage = true; + + /** + * The list of objects to paginate + */ private _objects: RemoteData>; + + /** + * Setter for _objects property + * @param objects + */ @Input() set objects(objects: RemoteData>) { this._objects = objects; } + + /** + * Getter for _objects property + */ get objects() { return this._objects; } @@ -69,6 +96,10 @@ export class ObjectDetailComponent { */ @Output() sortDirectionChange: EventEmitter = new EventEmitter(); + /** + * An event fired when the pagination is changed. + * Event's payload equals to the newly selected sort direction. + */ @Output() paginationChange: EventEmitter = new EventEmitter(); /** @@ -76,23 +107,38 @@ export class ObjectDetailComponent { * Event's payload equals to the newly selected sort field. */ @Output() sortFieldChange: EventEmitter = new EventEmitter(); - data: any = {}; + + /** + * Emit pageChange event + */ onPageChange(event) { this.pageChange.emit(event); } + /** + * Emit pageSizeChange event + */ onPageSizeChange(event) { this.pageSizeChange.emit(event); } + /** + * Emit sortDirectionChange event + */ onSortDirectionChange(event) { this.sortDirectionChange.emit(event); } + /** + * Emit sortFieldChange event + */ onSortFieldChange(event) { this.sortFieldChange.emit(event); } + /** + * Emit paginationChange event + */ onPaginationChange(event) { this.paginationChange.emit(event); } diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts index 3f28d5e76b..e54ae58398 100644 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts @@ -1,16 +1,15 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; +import { ActivatedRoute, Router } from '@angular/router'; import { of as observableOf } from 'rxjs'; -import { ActivatedRoute, Router } from '@angular/router'; import { RouterStub } from '../../testing/router-stub'; +import { WrapperDetailElementComponent } from './wrapper-detail-element.component'; -import { WrapperGridElementComponent } from '../../object-grid/wrapper-grid-element/wrapper-grid-element.component'; - -let wrapperGridElementComponent: WrapperGridElementComponent; -let fixture: ComponentFixture; +let wrapperDetailElementComponent: WrapperDetailElementComponent; +let fixture: ComponentFixture; const queryParam = 'test query'; const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; const activatedRouteStub = { @@ -20,14 +19,14 @@ const activatedRouteStub = { }) }; -describe('WrapperGridElementComponent', () => { +describe('WrapperDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ WrapperGridElementComponent ], + declarations: [ WrapperDetailElementComponent ], providers: [ { provide: ActivatedRoute, useValue: activatedRouteStub }, { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useFactory: (wrapperGridElementComponent)} + { provide: 'objectElementProvider', useFactory: (WrapperDetailElementComponent)} ], schemas: [ NO_ERRORS_SCHEMA ] @@ -35,12 +34,11 @@ describe('WrapperGridElementComponent', () => { })); beforeEach(async(() => { - fixture = TestBed.createComponent(WrapperGridElementComponent); - wrapperGridElementComponent = fixture.componentInstance; - + fixture = TestBed.createComponent(WrapperDetailElementComponent); + wrapperDetailElementComponent = fixture.componentInstance; })); - it('should show the wrapper element containing the cards',() => { - expect(fixture.debugElement.query(By.css('ds-collection-grid-element'))).toBeDefined(); + it('should show the wrapper element containing the detail object',() => { + expect(fixture.debugElement.query(By.css('ds-workspaceitem-my-dspace-result-detail-element'))).toBeDefined(); }) }); diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts index 0d3bfef3fe..b959505eea 100644 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts +++ b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts @@ -5,18 +5,37 @@ import { GenericConstructor } from '../../../core/shared/generic-constructor'; import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator'; import { ListableObject } from '../../object-collection/shared/listable-object.model'; +/** + * This component renders a wrapper for an object in the detail view. + */ @Component({ selector: 'ds-wrapper-detail-element', styleUrls: ['./wrapper-detail-element.component.scss'], templateUrl: './wrapper-detail-element.component.html' }) export class WrapperDetailElementComponent implements OnInit { + + /** + * The listable object. + */ @Input() object: ListableObject; + + /** + * The instance of the injector. + */ objectInjector: Injector; + /** + * Initialize instance variables + * + * @param {Injector} injector + */ constructor(private injector: Injector) { } + /** + * Initialize injector + */ ngOnInit(): void { this.objectInjector = Injector.create({ providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }], @@ -25,6 +44,9 @@ export class WrapperDetailElementComponent implements OnInit { } + /** + * Return class name for the object to inject + */ getDetailElement(): string { const f: GenericConstructor = this.object.constructor as GenericConstructor; return rendersDSOType(f, ViewMode.Detail); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts index bddf40d8c2..4fd40e7318 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts @@ -10,11 +10,24 @@ import { Metadata } from '../../../core/shared/metadata.utils'; selector: 'ds-my-dspace-result-list-element', template: `` }) - export class MyDSpaceResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { + + /** + * The result element object + */ dso: K; + + /** + * The array index of the result element + */ dsoIndex: number; + /** + * Initialize instance variables + * + * @param {ListableObject} listable + * @param {number} index + */ public constructor(@Inject('objectElementProvider') public listable: ListableObject, @Inject('indexElementProvider') public index: number) { super(listable); diff --git a/src/app/shared/object-list/object-list.component.spec.ts b/src/app/shared/object-list/object-list.component.spec.ts index 7e0b704a19..12ad032e98 100644 --- a/src/app/shared/object-list/object-list.component.spec.ts +++ b/src/app/shared/object-list/object-list.component.spec.ts @@ -6,7 +6,7 @@ import { By } from '@angular/platform-browser'; describe('ObjectListComponent', () => { let comp: ObjectListComponent; let fixture: ComponentFixture; - const testEvent = {test: 'test'} + const testEvent = {test: 'test'}; beforeEach(async(() => { TestBed.configureTestingModule({ diff --git a/src/app/shared/pagination/pagination.component.ts b/src/app/shared/pagination/pagination.component.ts index 825365c8c1..573c6a94f7 100644 --- a/src/app/shared/pagination/pagination.component.ts +++ b/src/app/shared/pagination/pagination.component.ts @@ -79,7 +79,7 @@ export class PaginationComponent implements OnDestroy, OnInit { @Output() sortFieldChange: EventEmitter = new EventEmitter(); /** - * An event fired when the sort field is changed. + * An event fired when the pagination is changed. * Event's payload equals to the newly selected sort field. */ @Output() paginationChange: EventEmitter = new EventEmitter(); From 080e0bee73b24b292baa80337ff66d47e8d6af63 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 2 Apr 2019 18:29:44 +0200 Subject: [PATCH 29/70] Added tests and comments --- .../tasks/claimed-task-data.service.spec.ts | 108 +++++++++++++++ .../core/tasks/claimed-task-data.service.ts | 57 +++++++- .../tasks/models/claimed-task-object.model.ts | 3 + .../normalized-claimed-task-object.model.ts | 2 +- .../normalized-pool-task-object.model.ts | 2 +- .../models/normalized-task-object.model.ts | 2 +- .../tasks/models/pool-task-object.model.ts | 3 + .../core/tasks/models/task-object.model.ts | 3 + .../core/tasks/pool-task-data.service.spec.ts | 70 ++++++++++ src/app/core/tasks/pool-task-data.service.ts | 35 ++++- .../tasks/task-response-parsing.service.ts | 16 +++ src/app/core/tasks/tasks.service.spec.ts | 130 ++++++++++++++++++ src/app/core/tasks/tasks.service.ts | 56 +++++++- src/app/shared/mocks/mock-request.service.ts | 1 + 14 files changed, 475 insertions(+), 13 deletions(-) create mode 100644 src/app/core/tasks/claimed-task-data.service.spec.ts create mode 100644 src/app/core/tasks/pool-task-data.service.spec.ts create mode 100644 src/app/core/tasks/tasks.service.spec.ts diff --git a/src/app/core/tasks/claimed-task-data.service.spec.ts b/src/app/core/tasks/claimed-task-data.service.spec.ts new file mode 100644 index 0000000000..dbd180b1b3 --- /dev/null +++ b/src/app/core/tasks/claimed-task-data.service.spec.ts @@ -0,0 +1,108 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; + +import { Store } from '@ngrx/store'; + +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { CoreState } from '../core.reducers'; +import { ClaimedTaskDataService } from './claimed-task-data.service'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; + +describe('ClaimedTaskDataService', () => { + let service: ClaimedTaskDataService; + let options: HttpOptions; + const taskEndpoint = 'https://rest.api/task'; + const linkPath = 'claimedtasks'; + const requestService: any = getMockRequestService(); + const halService: any = new HALEndpointServiceStub(taskEndpoint); + const rdbService = {} as RemoteDataBuildService; + const notificationsService = {} as NotificationsService; + const http = {} as HttpClient; + const comparator = {} as any; + const dataBuildService = { + normalize: (object) => object + } as NormalizedObjectBuildService; + const objectCache = { + addPatch: () => { + /* empty */ + }, + getObjectBySelfLink: () => { + /* empty */ + } + } as any; + const store = {} as Store; + + function initTestService(): ClaimedTaskDataService { + return new ClaimedTaskDataService( + requestService, + rdbService, + dataBuildService, + store, + objectCache, + halService, + notificationsService, + http, + comparator + ); + } + + beforeEach(() => { + service = initTestService(); + options = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Content-Type', 'application/x-www-form-urlencoded'); + options.headers = headers; + }); + + describe('approveTask', () => { + + it('should call postToEndpoint method', () => { + const scopeId = '1234'; + const body = { + submit_approve: 'true' + }; + + spyOn(service, 'postToEndpoint'); + requestService.prepareBody.and.returnValue(body); + + service.approveTask(scopeId); + + expect(service.postToEndpoint).toHaveBeenCalledWith(linkPath, body, scopeId, options); + }); + }); + + describe('rejectTask', () => { + + it('should call postToEndpoint method', () => { + const scopeId = '1234'; + const reason = 'test reject'; + const body = { + submit_reject: 'true', + reason + }; + + spyOn(service, 'postToEndpoint'); + requestService.prepareBody.and.returnValue(body); + + service.rejectTask(reason, scopeId); + + expect(service.postToEndpoint).toHaveBeenCalledWith(linkPath, body, scopeId, options); + }); + }); + + describe('returnToPoolTask', () => { + + it('should call deleteById method', () => { + const scopeId = '1234'; + + spyOn(service, 'deleteById'); + + service.returnToPoolTask(scopeId); + + expect(service.deleteById).toHaveBeenCalledWith(linkPath, scopeId, options); + }); + }); +}); diff --git a/src/app/core/tasks/claimed-task-data.service.ts b/src/app/core/tasks/claimed-task-data.service.ts index f1175d1b1c..52d4f0744f 100644 --- a/src/app/core/tasks/claimed-task-data.service.ts +++ b/src/app/core/tasks/claimed-task-data.service.ts @@ -14,12 +14,37 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { ProcessTaskResponse } from './models/process-task-response'; +/** + * The service handling all REST requests for ClaimedTask + */ @Injectable() export class ClaimedTaskDataService extends TasksService { + + /** + * The endpoint link name + */ protected linkPath = 'claimedtasks'; + + /** + * When true, a new request is always dispatched + */ protected forceBypassCache = true; + /** + * Initialize instance variables + * + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {NormalizedObjectBuildService} dataBuildService + * @param {Store} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {DSOChangeAnalyzer { super(); } - public approveTask(scopeId: string): Observable { + /** + * Make a request to approve the given task + * + * @param scopeId + * The task id + * @return {Observable} + * Emit the server response + */ + public approveTask(scopeId: string): Observable { const body = { submit_approve: 'true' }; return this.postToEndpoint(this.linkPath, this.requestService.prepareBody(body), scopeId, this.makeHttpOptions()); } - public rejectTask(reason: string, scopeId: string): Observable { + /** + * Make a request to reject the given task + * + * @param reason + * The reason of reject + * @param scopeId + * The task id + * @return {Observable} + * Emit the server response + */ + public rejectTask(reason: string, scopeId: string): Observable { const body = { submit_reject: 'true', reason @@ -48,7 +91,15 @@ export class ClaimedTaskDataService extends TasksService { return this.postToEndpoint(this.linkPath, this.requestService.prepareBody(body), scopeId, this.makeHttpOptions()); } - public returnToPoolTask(scopeId: string): Observable { + /** + * Make a request to return the given task to the pool + * + * @param scopeId + * The task id + * @return {Observable} + * Emit the server response + */ + public returnToPoolTask(scopeId: string): Observable { return this.deleteById(this.linkPath, scopeId, this.makeHttpOptions()); } diff --git a/src/app/core/tasks/models/claimed-task-object.model.ts b/src/app/core/tasks/models/claimed-task-object.model.ts index d0474a1aa8..212e75ed95 100644 --- a/src/app/core/tasks/models/claimed-task-object.model.ts +++ b/src/app/core/tasks/models/claimed-task-object.model.ts @@ -1,5 +1,8 @@ import { TaskObject } from './task-object.model'; +/** + * A model class for a ClaimedTask. + */ export class ClaimedTask extends TaskObject { } diff --git a/src/app/core/tasks/models/normalized-claimed-task-object.model.ts b/src/app/core/tasks/models/normalized-claimed-task-object.model.ts index e6a9096cb4..c2c3f12bc4 100644 --- a/src/app/core/tasks/models/normalized-claimed-task-object.model.ts +++ b/src/app/core/tasks/models/normalized-claimed-task-object.model.ts @@ -5,7 +5,7 @@ import { ClaimedTask } from './claimed-task-object.model'; import { ResourceType } from '../../shared/resource-type'; /** - * A model class for a NormalizedClaimedTaskObject. + * A normalized model class for a ClaimedTask. */ @mapsTo(ClaimedTask) @inheritSerialization(NormalizedTaskObject) diff --git a/src/app/core/tasks/models/normalized-pool-task-object.model.ts b/src/app/core/tasks/models/normalized-pool-task-object.model.ts index beb2d15e8c..22cda6ff9c 100644 --- a/src/app/core/tasks/models/normalized-pool-task-object.model.ts +++ b/src/app/core/tasks/models/normalized-pool-task-object.model.ts @@ -5,7 +5,7 @@ import { mapsTo, relationship } from '../../cache/builders/build-decorators'; import { ResourceType } from '../../shared/resource-type'; /** - * A model class for a NormalizedPoolTaskObject. + * A normalized model class for a PoolTask. */ @mapsTo(PoolTask) @inheritSerialization(NormalizedTaskObject) diff --git a/src/app/core/tasks/models/normalized-task-object.model.ts b/src/app/core/tasks/models/normalized-task-object.model.ts index 7e0fb3f6bb..52c274e3a8 100644 --- a/src/app/core/tasks/models/normalized-task-object.model.ts +++ b/src/app/core/tasks/models/normalized-task-object.model.ts @@ -6,7 +6,7 @@ import { TaskObject } from './task-object.model'; import { DSpaceObject } from '../../shared/dspace-object.model'; /** - * An abstract model class for a DSpaceObject. + * An abstract normalized model class for a TaskObject. */ @mapsTo(TaskObject) @inheritSerialization(NormalizedDSpaceObject) diff --git a/src/app/core/tasks/models/pool-task-object.model.ts b/src/app/core/tasks/models/pool-task-object.model.ts index fcaf4309a1..8d98d3e1a5 100644 --- a/src/app/core/tasks/models/pool-task-object.model.ts +++ b/src/app/core/tasks/models/pool-task-object.model.ts @@ -1,5 +1,8 @@ import { TaskObject } from './task-object.model'; +/** + * A model class for a PoolTask. + */ export class PoolTask extends TaskObject { } diff --git a/src/app/core/tasks/models/task-object.model.ts b/src/app/core/tasks/models/task-object.model.ts index 1475bdb14a..97a1c9f59e 100644 --- a/src/app/core/tasks/models/task-object.model.ts +++ b/src/app/core/tasks/models/task-object.model.ts @@ -6,6 +6,9 @@ import { ListableObject } from '../../../shared/object-collection/shared/listabl import { RemoteData } from '../../data/remote-data'; import { Workflowitem } from '../../submission/models/workflowitem.model'; +/** + * An abstract model class for a TaskObject. + */ export class TaskObject extends DSpaceObject implements CacheableObject, ListableObject { /** diff --git a/src/app/core/tasks/pool-task-data.service.spec.ts b/src/app/core/tasks/pool-task-data.service.spec.ts new file mode 100644 index 0000000000..7f40c6e89c --- /dev/null +++ b/src/app/core/tasks/pool-task-data.service.spec.ts @@ -0,0 +1,70 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; + +import { Store } from '@ngrx/store'; + +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { CoreState } from '../core.reducers'; +import { PoolTaskDataService } from './pool-task-data.service'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; + +describe('PoolTaskDataService', () => { + let service: PoolTaskDataService; + let options: HttpOptions; + const taskEndpoint = 'https://rest.api/task'; + const linkPath = 'pooltasks'; + const requestService = getMockRequestService(); + const halService: any = new HALEndpointServiceStub(taskEndpoint); + const rdbService = {} as RemoteDataBuildService; + const notificationsService = {} as NotificationsService; + const http = {} as HttpClient; + const comparator = {} as any; + const dataBuildService = { + normalize: (object) => object + } as NormalizedObjectBuildService; + const objectCache = { + addPatch: () => { + /* empty */ + }, + getObjectBySelfLink: () => { + /* empty */ + } + } as any; + const store = {} as Store; + + function initTestService(): PoolTaskDataService { + return new PoolTaskDataService( + requestService, + rdbService, + dataBuildService, + store, + objectCache, + halService, + notificationsService, + http, + comparator + ); + } + + beforeEach(() => { + service = initTestService(); + options = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Content-Type', 'application/x-www-form-urlencoded'); + options.headers = headers; + }); + + describe('claimTask', () => { + + it('should call postToEndpoint method', () => { + spyOn(service, 'postToEndpoint'); + const scopeId = '1234'; + service.claimTask(scopeId); + + expect(service.postToEndpoint).toHaveBeenCalledWith(linkPath, {}, scopeId, options); + }); + }); +}); diff --git a/src/app/core/tasks/pool-task-data.service.ts b/src/app/core/tasks/pool-task-data.service.ts index fb1d53420b..1a93450d4d 100644 --- a/src/app/core/tasks/pool-task-data.service.ts +++ b/src/app/core/tasks/pool-task-data.service.ts @@ -14,12 +14,37 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { ProcessTaskResponse } from './models/process-task-response'; +/** + * The service handling all REST requests for PoolTask + */ @Injectable() export class PoolTaskDataService extends TasksService { + + /** + * The endpoint link name + */ protected linkPath = 'pooltasks'; + + /** + * When true, a new request is always dispatched + */ protected forceBypassCache = true; + /** + * Initialize instance variables + * + * @param {RequestService} requestService + * @param {RemoteDataBuildService} rdbService + * @param {NormalizedObjectBuildService} dataBuildService + * @param {Store} store + * @param {ObjectCacheService} objectCache + * @param {HALEndpointService} halService + * @param {NotificationsService} notificationsService + * @param {HttpClient} http + * @param {DSOChangeAnalyzer { super(); } - public claimTask(scopeId: string): Observable { + /** + * Make a request to claim the given task + * + * @param scopeId + * The task id + * @return {Observable} + * Emit the server response + */ + public claimTask(scopeId: string): Observable { return this.postToEndpoint(this.linkPath, {}, scopeId, this.makeHttpOptions()); } } diff --git a/src/app/core/tasks/task-response-parsing.service.ts b/src/app/core/tasks/task-response-parsing.service.ts index d12b1b22f8..7445f9d267 100644 --- a/src/app/core/tasks/task-response-parsing.service.ts +++ b/src/app/core/tasks/task-response-parsing.service.ts @@ -11,17 +11,33 @@ import { ObjectCacheService } from '../cache/object-cache.service'; import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory'; import { ErrorResponse, RestResponse, TaskResponse } from '../cache/response.models'; +/** + * Provides methods to parse response for a task request. + */ @Injectable() export class TaskResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { protected objectFactory = NormalizedObjectFactory; protected toCache = false; + /** + * Initialize instance variables + * + * @param {GlobalConfig} EnvConfig + * @param {ObjectCacheService} objectCache + */ constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected objectCache: ObjectCacheService,) { super(); } + /** + * Parses data from the tasks endpoints + * + * @param {RestRequest} request + * @param {DSpaceRESTV2Response} data + * @returns {RestResponse} + */ parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (this.isSuccessStatus(data.statusCode)) { return new TaskResponse( data.statusCode, data.statusText); diff --git a/src/app/core/tasks/tasks.service.spec.ts b/src/app/core/tasks/tasks.service.spec.ts new file mode 100644 index 0000000000..207a09225b --- /dev/null +++ b/src/app/core/tasks/tasks.service.spec.ts @@ -0,0 +1,130 @@ +import { getTestScheduler } from 'jasmine-marbles'; +import { TestScheduler } from 'rxjs/testing'; + +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { TasksService } from './tasks.service'; +import { RequestService } from '../data/request.service'; +import { TaskDeleteRequest, TaskPostRequest } from '../data/request.models'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { TaskObject } from './models/task-object.model'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { ChangeAnalyzer } from '../data/change-analyzer'; +import { compare, Operation } from 'fast-json-patch'; +import { NormalizedTaskObject } from './models/normalized-task-object.model'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; + +const LINK_NAME = 'test'; + +/* tslint:disable:max-classes-per-file */ +class TestTask extends TaskObject { +} + +class TestService extends TasksService { + protected linkPath = LINK_NAME; + protected forceBypassCache = true; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected dataBuildService: NormalizedObjectBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DSOChangeAnalyzer) { + super(); + } +} + +class NormalizedTestTaskObject extends NormalizedTaskObject { +} + +class DummyChangeAnalyzer implements ChangeAnalyzer { + diff(object1: NormalizedTestTaskObject, object2: NormalizedTestTaskObject): Operation[] { + return compare((object1 as any).metadata, (object2 as any).metadata); + } + +} +/* tslint:enable:max-classes-per-file */ + +describe('TasksService', () => { + let scheduler: TestScheduler; + let service: TestService; + const taskEndpoint = 'https://rest.api/task'; + const linkPath = 'testTask'; + const requestService = getMockRequestService(); + const halService: any = new HALEndpointServiceStub(taskEndpoint); + const rdbService = {} as RemoteDataBuildService; + const notificationsService = {} as NotificationsService; + const http = {} as HttpClient; + const comparator = new DummyChangeAnalyzer() as any; + const dataBuildService = { + normalize: (object) => object + } as NormalizedObjectBuildService; + const objectCache = { + addPatch: () => { + /* empty */ + }, + getObjectBySelfLink: () => { + /* empty */ + } + } as any; + const store = {} as Store; + + function initTestService(): TestService { + return new TestService( + requestService, + rdbService, + dataBuildService, + store, + objectCache, + halService, + notificationsService, + http, + comparator + ); + } + + beforeEach(() => { + scheduler = getTestScheduler(); + service = initTestService(); + const options: HttpOptions = Object.create({}); + let headers = new HttpHeaders(); + headers = headers.append('Content-Type', 'application/x-www-form-urlencoded'); + options.headers = headers; + + }); + + describe('postToEndpoint', () => { + + it('should configure a new TaskPostRequest', () => { + const expected = new TaskPostRequest(requestService.generateRequestId(), `${taskEndpoint}/${linkPath}`, {}); + scheduler.schedule(() => service.postToEndpoint('testTask', {}).subscribe()); + scheduler.flush(); + + expect(requestService.configure).toHaveBeenCalledWith(expected); + }); + }); + + describe('deleteById', () => { + + it('should configure a new TaskPostRequest', () => { + const scopeId = '1234'; + const expected = new TaskDeleteRequest(requestService.generateRequestId(), `${taskEndpoint}/${linkPath}/${scopeId}`, null); + scheduler.schedule(() => service.deleteById('testTask', scopeId).subscribe()); + scheduler.flush(); + + expect(requestService.configure).toHaveBeenCalledWith(expected); + }); + }); + +}); diff --git a/src/app/core/tasks/tasks.service.ts b/src/app/core/tasks/tasks.service.ts index 19ef81bd19..f39b144c6a 100644 --- a/src/app/core/tasks/tasks.service.ts +++ b/src/app/core/tasks/tasks.service.ts @@ -13,12 +13,23 @@ import { getResponseFromEntry } from '../shared/operators'; import { ErrorResponse, MessageResponse, RestResponse } from '../cache/response.models'; import { CacheableObject } from '../cache/object-cache.reducer'; +/** + * An abstract class that provides methods to handle task requests. + */ export abstract class TasksService extends DataService { public getBrowseEndpoint(options: FindAllOptions): Observable { return this.halService.getEndpoint(this.linkPath); } + /** + * Fetch a RestRequest + * + * @param requestId + * The base endpoint for the type of object + * @return Observable + * server response + */ protected fetchRequest(requestId: string): Observable { const responses = this.requestService.getByUUID(requestId).pipe( getResponseFromEntry() @@ -39,14 +50,32 @@ export abstract class TasksService extends DataServic return observableMerge(errorResponses, successResponses); } + /** + * Create the HREF for a specific submission object based on its identifier + * + * @param endpoint + * The base endpoint for the type of object + * @param resourceID + * The identifier for the object + */ protected getEndpointByIDHref(endpoint, resourceID): string { return isNotEmpty(resourceID) ? `${endpoint}/${resourceID}` : `${endpoint}`; } - protected getEndpointByMethod(endpoint: string, method: string): string { - return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`; - } - + /** + * Make a new post request + * + * @param linkPath + * The endpoint link name + * @param body + * The request body + * @param scopeId + * The task id to be removed + * @param options + * The HttpOptions object + * @return Observable + * server response + */ public postToEndpoint(linkPath: string, body: any, scopeId?: string, options?: HttpOptions): Observable { const requestId = this.requestService.generateRequestId(); return this.halService.getEndpoint(linkPath).pipe( @@ -59,9 +88,21 @@ export abstract class TasksService extends DataServic distinctUntilChanged()); } - public deleteById(linkName: string, scopeId: string, options?: HttpOptions): Observable { + /** + * Delete an existing task on the server + * + * @param linkPath + * The endpoint link name + * @param scopeId + * The task id to be removed + * @param options + * The HttpOptions object + * @return Observable + * server response + */ + public deleteById(linkPath: string, scopeId: string, options?: HttpOptions): Observable { const requestId = this.requestService.generateRequestId(); - return this.halService.getEndpoint(linkName || this.linkPath).pipe( + return this.halService.getEndpoint(linkPath || this.linkPath).pipe( filter((href: string) => isNotEmpty(href)), distinctUntilChanged(), map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId)), @@ -71,6 +112,9 @@ export abstract class TasksService extends DataServic distinctUntilChanged()); } + /** + * Create a new HttpOptions + */ protected makeHttpOptions() { const options: HttpOptions = Object.create({}); let headers = new HttpHeaders(); diff --git a/src/app/shared/mocks/mock-request.service.ts b/src/app/shared/mocks/mock-request.service.ts index ce09f6d85e..ae19c00a30 100644 --- a/src/app/shared/mocks/mock-request.service.ts +++ b/src/app/shared/mocks/mock-request.service.ts @@ -8,6 +8,7 @@ export function getMockRequestService(requestEntry$: Observable = generateRequestId: 'clients/b186e8ce-e99c-4183-bc9a-42b4821bdb78', getByHref: requestEntry$, getByUUID: requestEntry$, + prepareBody: jasmine.createSpy('prepareBody'), /* tslint:disable:no-empty */ removeByHrefSubstring: () => {} /* tslint:enable:no-empty */ From 25d955c8046d80b59fb617944961545143936649 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 2 Apr 2019 19:21:00 +0200 Subject: [PATCH 30/70] Added tests and comments --- .../my-dspace-item-status.component.spec.ts | 96 +++++++++++++++++++ .../my-dspace-item-status.component.ts | 18 +++- .../item-submitter.component.html | 2 +- .../item-submitter.component.spec.ts | 68 +++++++++++++ .../item-submitter.component.ts | 18 +++- 5 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts create mode 100644 src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.spec.ts diff --git a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts new file mode 100644 index 0000000000..f3b58665f5 --- /dev/null +++ b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.spec.ts @@ -0,0 +1,96 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { of as observableOf } from 'rxjs'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; + +import { RemoteData } from '../../../../core/data/remote-data'; + +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; +import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; +import { EPersonMock } from '../../../testing/eperson-mock'; +import { MyDSpaceItemStatusComponent } from './my-dspace-item-status.component'; +import { MyDspaceItemStatusType } from './my-dspace-item-status-type'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; +import { By } from '@angular/platform-browser'; + +let component: MyDSpaceItemStatusComponent; +let fixture: ComponentFixture; + +let mockResultObject: PoolTask; + +const rdSumbitter = new RemoteData(false, false, true, null, EPersonMock); +const workflowitem = Object.assign(new Workflowitem(), { submitter: observableOf(rdSumbitter) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('MyDSpaceItemStatusComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [MyDSpaceItemStatusComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(MyDSpaceItemStatusComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MyDSpaceItemStatusComponent); + component = fixture.componentInstance; + }); + + it('should display badge', () => { + const badge = fixture.debugElement.query(By.css('span')); + expect(badge).toBeDefined(); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.REJECTED; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.REJECTED); + expect(component.badgeClass).toBe('text-light badge badge-danger'); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.VALIDATION; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.VALIDATION); + expect(component.badgeClass).toBe('text-light badge badge-warning'); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.WAITING_CONTROLLER; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.WAITING_CONTROLLER); + expect(component.badgeClass).toBe('text-light badge badge-info'); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.IN_PROGRESS; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.IN_PROGRESS); + expect(component.badgeClass).toBe('text-light badge badge-primary'); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.ACCEPTED; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.ACCEPTED); + expect(component.badgeClass).toBe('text-light badge badge-success'); + }); + + it('should init badge content and class', () => { + component.status = MyDspaceItemStatusType.WORKFLOW; + fixture.detectChanges(); + expect(component.badgeContent).toBe(MyDspaceItemStatusType.WORKFLOW); + expect(component.badgeClass).toBe('text-light badge badge-info'); + }); +}); diff --git a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts index 2ae1bc2ef5..87bb95ebb5 100644 --- a/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts +++ b/src/app/shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component.ts @@ -1,18 +1,34 @@ import { Component, Input, OnInit } from '@angular/core'; import { MyDspaceItemStatusType } from './my-dspace-item-status-type'; +/** + * This component represents a badge with mydspace item status + */ @Component({ selector: 'ds-mydspace-item-status', styleUrls: ['./my-dspace-item-status.component.scss'], templateUrl: './my-dspace-item-status.component.html' }) - export class MyDSpaceItemStatusComponent implements OnInit { + /** + * This mydspace item status + */ @Input() status: MyDspaceItemStatusType; + + /** + * This badge class + */ public badgeClass: string; + + /** + * This badge content + */ public badgeContent: string; + /** + * Initialize badge content and class + */ ngOnInit() { this.badgeContent = this.status; this.badgeClass = 'text-light badge '; diff --git a/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.html b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.html index 1f13fbfa2c..35ebb5f1bf 100644 --- a/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.html +++ b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.html @@ -1,3 +1,3 @@
    - {{'submission.workflow.tasks.generic.submitter' | translate}} : {{(submitter | async)?.name}} + {{'submission.workflow.tasks.generic.submitter' | translate}} : {{(submitter$ | async)?.name}}
    diff --git a/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.spec.ts b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.spec.ts new file mode 100644 index 0000000000..77460a3674 --- /dev/null +++ b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.spec.ts @@ -0,0 +1,68 @@ +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { of as observableOf } from 'rxjs'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { cold } from 'jasmine-marbles'; + +import { RemoteData } from '../../../../core/data/remote-data'; +import { ItemSubmitterComponent } from './item-submitter.component'; +import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; +import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; +import { EPersonMock } from '../../../testing/eperson-mock'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; +import { By } from '@angular/platform-browser'; + +let component: ItemSubmitterComponent; +let fixture: ComponentFixture; + +const compIndex = 1; + +let mockResultObject: PoolTask; + +const rdSumbitter = new RemoteData(false, false, true, null, EPersonMock); +const workflowitem = Object.assign(new Workflowitem(), { submitter: observableOf(rdSumbitter) }); +const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); +mockResultObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); + +describe('ItemSubmitterComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + declarations: [ItemSubmitterComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ItemSubmitterComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemSubmitterComponent); + component = fixture.componentInstance; + })); + + beforeEach(() => { + component.object = mockResultObject; + fixture.detectChanges(); + }); + + it('should init submitter properly', () => { + expect(component.submitter$).toBeObservable(cold('(b|)', { + b: EPersonMock + })); + }); + + it('should show a badge with submitter name', () => { + const badge = fixture.debugElement.query(By.css('.badge')); + + expect(badge).toBeDefined(); + expect(badge.nativeElement.innerHTML).toBe(EPersonMock.name); + }); +}); diff --git a/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.ts b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.ts index b800686714..f752fa6f04 100644 --- a/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.ts +++ b/src/app/shared/object-collection/shared/mydspace-item-submitter/item-submitter.component.ts @@ -8,19 +8,31 @@ import { RemoteData } from '../../../../core/data/remote-data'; import { isNotEmpty, isNotUndefined } from '../../../empty.util'; import { Workflowitem } from '../../../../core/submission/models/workflowitem.model'; +/** + * This component represents a badge with submitter information. + */ @Component({ selector: 'ds-item-submitter', styleUrls: ['./item-submitter.component.scss'], templateUrl: './item-submitter.component.html' }) - export class ItemSubmitterComponent implements OnInit { + + /** + * The target object + */ @Input() object: any; - submitter: Observable; + /** + * The Eperson object + */ + submitter$: Observable; + /** + * Initialize submitter object + */ ngOnInit() { - this.submitter = (this.object.workflowitem as Observable>).pipe( + this.submitter$ = (this.object.workflowitem as Observable>).pipe( filter((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))), flatMap((rd: RemoteData) => rd.payload.submitter as Observable>), find((rd: RemoteData) => rd.hasSucceeded && isNotEmpty(rd.payload)), From af2a995e24503ca293def41d557118f6233900af Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 14:26:06 +0200 Subject: [PATCH 31/70] Fixed build error --- .../claimed-task-actions-return-to-pool.component.html | 2 +- .../claimed-task-actions-return-to-pool.component.spec.ts | 2 +- .../claimed-task-actions-return-to-pool.component.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html index 2002c55528..702ce75e7f 100644 --- a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.html @@ -2,7 +2,7 @@ [className]="'btn btn-secondary ' + wrapperClass" ngbTooltip="{{'submission.workflow.tasks.claimed.return_help' | translate}}" [disabled]="processingReturnToPool" - (click)="returnToPool()"> + (click)="confirmReturnToPool()"> {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.claimed.return' | translate}} diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts index fcb370595a..d461d9e055 100644 --- a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.spec.ts @@ -56,7 +56,7 @@ describe('ClaimedTaskActionsReturnToPoolComponent', () => { it('should emit return to pool event', () => { spyOn(component.returnToPool, 'emit'); - component.confirmApprove(); + component.confirmReturnToPool(); fixture.detectChanges(); expect(component.returnToPool.emit).toHaveBeenCalled(); diff --git a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts index 381b8f1afe..1dfe91eb5b 100644 --- a/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts +++ b/src/app/shared/mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component.ts @@ -24,9 +24,9 @@ export class ClaimedTaskActionsReturnToPoolComponent { @Output() returnToPool: EventEmitter = new EventEmitter(); /** - * Emit approve event + * Emit returnToPool event */ - confirmApprove() { + confirmReturnToPool() { this.returnToPool.emit(); } } From 7c48504c8224e2583f0e027a5ef9e0d4dfe6f596 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 15:27:08 +0200 Subject: [PATCH 32/70] renamed dspaceObject to indexableObject --- src/app/+my-dspace-page/my-dspace-result.model.ts | 2 +- .../+search-page/normalized-search-result.model.ts | 4 ++-- src/app/+search-page/search-result.model.ts | 2 +- .../+search-page/search-service/search.service.ts | 6 +++--- .../core/data/mydspace-response-parsing.service.ts | 12 ++++++------ src/app/core/shared/operators.ts | 2 +- .../dso-selector/dso-selector.component.html | 4 ++-- .../dso-selector/dso-selector.component.spec.ts | 2 +- ...my-dspace-result-detail-element.component.spec.ts | 4 ++-- .../item-detail-preview.component.html | 2 +- ...my-dspace-result-detail-element.component.spec.ts | 4 ++-- .../my-dspace-result-detail-element.component.ts | 2 +- ...my-dspace-result-detail-element.component.spec.ts | 4 ++-- ...my-dspace-result-detail-element.component.spec.ts | 4 ++-- ...my-dspace-result-detail-element.component.spec.ts | 4 ++-- ...tion-search-result-grid-element.component.spec.ts | 8 ++++---- ...nity-search-result-grid-element.component.spec.ts | 8 ++++---- ...item-search-result-grid-element.component.spec.ts | 12 ++++++------ .../search-result-grid-element.component.ts | 2 +- ...d-my-dspace-result-list-element.component.spec.ts | 4 ++-- .../item-list-preview.component.html | 2 +- ...m-my-dspace-result-list-element.component.spec.ts | 4 ++-- .../my-dspace-result-list-element.component.ts | 2 +- ...l-my-dspace-result-list-element.component.spec.ts | 4 ++-- ...m-my-dspace-result-list-element.component.spec.ts | 4 ++-- ...m-my-dspace-result-list-element.component.spec.ts | 4 ++-- ...tion-search-result-list-element.component.spec.ts | 8 ++++---- ...nity-search-result-list-element.component.spec.ts | 8 ++++---- ...item-search-result-list-element.component.spec.ts | 12 ++++++------ .../search-result-list-element.component.ts | 2 +- 30 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/app/+my-dspace-page/my-dspace-result.model.ts b/src/app/+my-dspace-page/my-dspace-result.model.ts index 5605c746e8..d300ed0bc8 100644 --- a/src/app/+my-dspace-page/my-dspace-result.model.ts +++ b/src/app/+my-dspace-page/my-dspace-result.model.ts @@ -9,7 +9,7 @@ export class MyDSpaceResult implements ListableObject { /** * The DSpaceObject that was found */ - dspaceObject: T; + indexableObject: T; /** * The metadata that was used to find this item, hithighlighted diff --git a/src/app/+search-page/normalized-search-result.model.ts b/src/app/+search-page/normalized-search-result.model.ts index cb1238936a..32f3217b54 100644 --- a/src/app/+search-page/normalized-search-result.model.ts +++ b/src/app/+search-page/normalized-search-result.model.ts @@ -9,8 +9,8 @@ export class NormalizedSearchResult implements ListableObject { /** * The UUID of the DSpaceObject that was found */ - @autoserializeAs(String, 'resultObject') - dspaceObject: string; + @autoserialize + indexableObject: string; /** * The metadata that was used to find this item, hithighlighted diff --git a/src/app/+search-page/search-result.model.ts b/src/app/+search-page/search-result.model.ts index ff865610c6..0354edbc6b 100644 --- a/src/app/+search-page/search-result.model.ts +++ b/src/app/+search-page/search-result.model.ts @@ -9,7 +9,7 @@ export class SearchResult implements ListableObject { /** * The DSpaceObject that was found */ - dspaceObject: T; + indexableObject: T; /** * The metadata that was used to find this item, hithighlighted diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index ed19f1df68..568bf0fed9 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -133,9 +133,9 @@ export class SearchService implements OnDestroy { const dsoObs: Observable> = sqrObs.pipe( map((sqr: SearchQueryResponse) => { return sqr.objects - .filter((nsr: NormalizedSearchResult) => isNotUndefined(nsr.dspaceObject)) + .filter((nsr: NormalizedSearchResult) => isNotUndefined(nsr.indexableObject)) .map((nsr: NormalizedSearchResult) => { - return this.rdb.buildSingle(nsr.dspaceObject); + return this.rdb.buildSingle(nsr.indexableObject); }) }), switchMap((input: Array>>) => this.rdb.aggregate(input)), @@ -150,7 +150,7 @@ export class SearchService implements OnDestroy { const constructor: GenericConstructor = dsos.payload[index].constructor as GenericConstructor; co = getSearchResultFor(constructor, searchOptions.configuration); return Object.assign(new co(), object, { - dspaceObject: dsos.payload[index] + indexableObject: dsos.payload[index] }); } else { return undefined; diff --git a/src/app/core/data/mydspace-response-parsing.service.ts b/src/app/core/data/mydspace-response-parsing.service.ts index 076103158f..a6945e27b4 100644 --- a/src/app/core/data/mydspace-response-parsing.service.ts +++ b/src/app/core/data/mydspace-response-parsing.service.ts @@ -40,7 +40,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { const dsoSelfLinks = payload._embedded.objects .filter((object) => hasValue(object._embedded)) - .map((object) => object._embedded.resultObject) + .map((object) => object._embedded.indexableObject) .map((dso) => this.dsoParser.parse(request, { payload: dso, statusCode: data.statusCode, @@ -52,7 +52,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { const objects = payload._embedded.objects .filter((object) => hasValue(object._embedded)) .map((object, index) => Object.assign({}, object, { - resultObject: dsoSelfLinks[index], + indexableObject: dsoSelfLinks[index], hitHighlights: hitHighlights[index], _embedded: this.filterEmbeddedObjects(object) })); @@ -63,13 +63,13 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { protected filterEmbeddedObjects(object) { const allowedEmbeddedKeys = ['submitter', 'item', 'workspaceitem', 'workflowitem']; - if (object._embedded.resultObject && object._embedded.resultObject._embedded) { + if (object._embedded.indexableObject && object._embedded.indexableObject._embedded) { return Object.assign({}, object._embedded, { - resultObject: Object.assign({}, object._embedded.resultObject, { - _embedded: Object.keys(object._embedded.resultObject._embedded) + indexableObject: Object.assign({}, object._embedded.indexableObject, { + _embedded: Object.keys(object._embedded.indexableObject._embedded) .filter((key) => allowedEmbeddedKeys.includes(key)) .reduce((obj, key) => { - obj[key] = object._embedded.resultObject._embedded[key]; + obj[key] = object._embedded.indexableObject._embedded[key]; return obj; }, {}) }) diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index ce9740a0fc..29bb2f6b7d 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -75,7 +75,7 @@ export const toDSpaceObjectListRD = () => source.pipe( filter((rd: RemoteData>>) => rd.hasSucceeded), map((rd: RemoteData>>) => { - const dsoPage: T[] = rd.payload.page.map((searchResult: SearchResult) => searchResult.dspaceObject); + const dsoPage: T[] = rd.payload.page.map((searchResult: SearchResult) => searchResult.indexableObject); const payload = Object.assign(rd.payload, { page: dsoPage }) as PaginatedList; return Object.assign(rd, { payload: payload }); }) diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html index da6bfa40ba..662144823d 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html @@ -13,8 +13,8 @@
  • diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts index f9d1567245..5ec553222b 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts @@ -27,7 +27,7 @@ describe('DSOSelectorComponent', () => { language: undefined })] }; - searchResult.dspaceObject = item; + searchResult.indexableObject = item; searchResult.hitHighlights = {}; const searchService = jasmine.createSpyObj('searchService', { search: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(undefined, [searchResult]))) diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts index 38c4f461cd..d3307721ff 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts @@ -52,7 +52,7 @@ const item = Object.assign(new Item(), { const rdItem = new RemoteData(false, false, true, null, item); const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); -mockResultObject.dspaceObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); +mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); describe('ClaimedMyDSpaceResultDetailElementComponent', () => { beforeEach(async(() => { @@ -75,7 +75,7 @@ describe('ClaimedMyDSpaceResultDetailElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html index 3cb4665884..10e7e98d87 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html @@ -24,4 +24,4 @@
    - + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts index c48d755d61..b757879aac 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts @@ -17,7 +17,7 @@ const compIndex = 1; const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); mockResultObject.hitHighlights = {}; -mockResultObject.dspaceObject = Object.assign(new Item(), { +mockResultObject.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.title': [ @@ -68,7 +68,7 @@ describe('ItemMyDSpaceResultDetailElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts index 4017026396..47a44d3132 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts @@ -24,7 +24,7 @@ export class MyDSpaceResultDetailElementComponent, K */ public constructor(@Inject('objectElementProvider') public detailable: ListableObject) { super(detailable); - this.dso = this.object.dspaceObject; + this.dso = this.object.indexableObject; } /** diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts index b108d48c33..0eea01aa1c 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts @@ -52,7 +52,7 @@ const item = Object.assign(new Item(), { const rdItem = new RemoteData(false, false, true, null, item); const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); -mockResultObject.dspaceObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); +mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); describe('PoolMyDSpaceResultDetailElementComponent', () => { beforeEach(async(() => { @@ -75,7 +75,7 @@ describe('PoolMyDSpaceResultDetailElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts index 3c6505218e..f8bdbf9fd6 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts @@ -49,7 +49,7 @@ const item = Object.assign(new Item(), { } }); const rd = new RemoteData(false, false, true, null, item); -mockResultObject.dspaceObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); +mockResultObject.indexableObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); describe('WorkflowitemMyDSpaceResultDetailElementComponent', () => { beforeEach(async(() => { @@ -72,7 +72,7 @@ describe('WorkflowitemMyDSpaceResultDetailElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts index 830ab80cf1..301181e65c 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts @@ -49,7 +49,7 @@ const item = Object.assign(new Item(), { } }); const rd = new RemoteData(false, false, true, null, item); -mockResultObject.dspaceObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); +mockResultObject.indexableObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); describe('WorkspaceitemMyDSpaceResultDetailElementComponent', () => { beforeEach(async(() => { @@ -72,7 +72,7 @@ describe('WorkspaceitemMyDSpaceResultDetailElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts index e8f8b1330e..07f3960d55 100644 --- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts @@ -17,7 +17,7 @@ const truncatableServiceStub: any = { const mockCollectionWithAbstract: CollectionSearchResult = new CollectionSearchResult(); mockCollectionWithAbstract.hitHighlights = {}; -mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), { +mockCollectionWithAbstract.indexableObject = Object.assign(new Collection(), { metadata: { 'dc.description.abstract': [ { @@ -30,7 +30,7 @@ mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), { const mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult(); mockCollectionWithoutAbstract.hitHighlights = {}; -mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), { +mockCollectionWithoutAbstract.indexableObject = Object.assign(new Collection(), { metadata: { 'dc.title': [ { @@ -63,7 +63,7 @@ describe('CollectionSearchResultGridElementComponent', () => { describe('When the collection has an abstract', () => { beforeEach(() => { - collectionSearchResultGridElementComponent.dso = mockCollectionWithAbstract.dspaceObject; + collectionSearchResultGridElementComponent.dso = mockCollectionWithAbstract.indexableObject; fixture.detectChanges(); }); @@ -75,7 +75,7 @@ describe('CollectionSearchResultGridElementComponent', () => { describe('When the collection has no abstract', () => { beforeEach(() => { - collectionSearchResultGridElementComponent.dso = mockCollectionWithoutAbstract.dspaceObject; + collectionSearchResultGridElementComponent.dso = mockCollectionWithoutAbstract.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts index e111e624c5..567b2e1d0e 100644 --- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts @@ -17,7 +17,7 @@ const truncatableServiceStub: any = { const mockCommunityWithAbstract: CommunitySearchResult = new CommunitySearchResult(); mockCommunityWithAbstract.hitHighlights = {}; -mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), { +mockCommunityWithAbstract.indexableObject = Object.assign(new Community(), { metadata: { 'dc.description.abstract': [ { @@ -30,7 +30,7 @@ mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), { const mockCommunityWithoutAbstract: CommunitySearchResult = new CommunitySearchResult(); mockCommunityWithoutAbstract.hitHighlights = {}; -mockCommunityWithoutAbstract.dspaceObject = Object.assign(new Community(), { +mockCommunityWithoutAbstract.indexableObject = Object.assign(new Community(), { metadata: { 'dc.title': [ { @@ -63,7 +63,7 @@ describe('CommunitySearchResultGridElementComponent', () => { describe('When the community has an abstract', () => { beforeEach(() => { - communitySearchResultGridElementComponent.dso = mockCommunityWithAbstract.dspaceObject; + communitySearchResultGridElementComponent.dso = mockCommunityWithAbstract.indexableObject; fixture.detectChanges(); }); @@ -75,7 +75,7 @@ describe('CommunitySearchResultGridElementComponent', () => { describe('When the community has no abstract', () => { beforeEach(() => { - communitySearchResultGridElementComponent.dso = mockCommunityWithoutAbstract.dspaceObject; + communitySearchResultGridElementComponent.dso = mockCommunityWithoutAbstract.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts index 0103fa5c49..655fd268a7 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts @@ -18,7 +18,7 @@ const truncatableServiceStub: any = { const mockItemWithAuthorAndDate: ItemSearchResult = new ItemSearchResult(); mockItemWithAuthorAndDate.hitHighlights = {}; -mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), { +mockItemWithAuthorAndDate.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.contributor.author': [ @@ -38,7 +38,7 @@ mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), { const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult(); mockItemWithoutAuthorAndDate.hitHighlights = {}; -mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), { +mockItemWithoutAuthorAndDate.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.title': [ @@ -78,7 +78,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has an author', () => { beforeEach(() => { - itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; + itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -90,7 +90,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has no author', () => { beforeEach(() => { - itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -102,7 +102,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has an issuedate', () => { beforeEach(() => { - itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; + itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -114,7 +114,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has no issuedate', () => { beforeEach(() => { - itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts index 844d0bc165..0961dc96ee 100644 --- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts @@ -18,7 +18,7 @@ export class SearchResultGridElementComponent, K exten public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, private truncatableService: TruncatableService) { super(listableObject); - this.dso = this.object.dspaceObject; + this.dso = this.object.indexableObject; } /** diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts index c79812d10b..7c30b2ef8c 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts @@ -52,7 +52,7 @@ const item = Object.assign(new Item(), { const rdItem = new RemoteData(false, false, true, null, item); const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); -mockResultObject.dspaceObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); +mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); describe('ClaimedMyDSpaceResultListElementComponent', () => { beforeEach(async(() => { @@ -75,7 +75,7 @@ describe('ClaimedMyDSpaceResultListElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html index 0aa93ab711..b2fc3812cd 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html @@ -28,5 +28,5 @@ - + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts index bcd323ae2a..1ffb1b5c13 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts @@ -17,7 +17,7 @@ const compIndex = 1; const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); mockResultObject.hitHighlights = {}; -mockResultObject.dspaceObject = Object.assign(new Item(), { +mockResultObject.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.title': [ @@ -68,7 +68,7 @@ describe('ItemMyDSpaceResultListElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts index 4fd40e7318..b2a5bf14fd 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts @@ -31,7 +31,7 @@ export class MyDSpaceResultListElementComponent, K e public constructor(@Inject('objectElementProvider') public listable: ListableObject, @Inject('indexElementProvider') public index: number) { super(listable); - this.dso = this.object.dspaceObject; + this.dso = this.object.indexableObject; this.dsoIndex = this.index; } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts index 3b2545e069..36eb8f253a 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts @@ -52,7 +52,7 @@ const item = Object.assign(new Item(), { const rdItem = new RemoteData(false, false, true, null, item); const workflowitem = Object.assign(new Workflowitem(), { item: observableOf(rdItem) }); const rdWorkflowitem = new RemoteData(false, false, true, null, workflowitem); -mockResultObject.dspaceObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); +mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); describe('PoolMyDSpaceResultListElementComponent', () => { beforeEach(async(() => { @@ -75,7 +75,7 @@ describe('PoolMyDSpaceResultListElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts index de2dfd73f4..2bcd4d46b0 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts @@ -49,7 +49,7 @@ const item = Object.assign(new Item(), { } }); const rd = new RemoteData(false, false, true, null, item); -mockResultObject.dspaceObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); +mockResultObject.indexableObject = Object.assign(new Workflowitem(), { item: observableOf(rd) }); describe('WorkflowitemMyDSpaceResultListElementComponent', () => { beforeEach(async(() => { @@ -72,7 +72,7 @@ describe('WorkflowitemMyDSpaceResultListElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts index f47c05c9e9..56ee33ddae 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts @@ -49,7 +49,7 @@ const item = Object.assign(new Item(), { } }); const rd = new RemoteData(false, false, true, null, item); -mockResultObject.dspaceObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); +mockResultObject.indexableObject = Object.assign(new Workspaceitem(), { item: observableOf(rd) }); describe('WorkspaceitemMyDSpaceResultListElementComponent', () => { beforeEach(async(() => { @@ -72,7 +72,7 @@ describe('WorkspaceitemMyDSpaceResultListElementComponent', () => { })); beforeEach(() => { - component.dso = mockResultObject.dspaceObject; + component.dso = mockResultObject.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts index e897071a00..7f5aaf5d9c 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts @@ -17,7 +17,7 @@ const truncatableServiceStub: any = { const mockCollectionWithAbstract: CollectionSearchResult = new CollectionSearchResult(); mockCollectionWithAbstract.hitHighlights = {}; -mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), { +mockCollectionWithAbstract.indexableObject = Object.assign(new Collection(), { metadata: { 'dc.description.abstract': [ { @@ -30,7 +30,7 @@ mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), { const mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult(); mockCollectionWithoutAbstract.hitHighlights = {}; -mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), { +mockCollectionWithoutAbstract.indexableObject = Object.assign(new Collection(), { metadata: { 'dc.title': [ { @@ -63,7 +63,7 @@ describe('CollectionSearchResultListElementComponent', () => { describe('When the collection has an abstract', () => { beforeEach(() => { - collectionSearchResultListElementComponent.dso = mockCollectionWithAbstract.dspaceObject; + collectionSearchResultListElementComponent.dso = mockCollectionWithAbstract.indexableObject; fixture.detectChanges(); }); @@ -75,7 +75,7 @@ describe('CollectionSearchResultListElementComponent', () => { describe('When the collection has no abstract', () => { beforeEach(() => { - collectionSearchResultListElementComponent.dso = mockCollectionWithoutAbstract.dspaceObject; + collectionSearchResultListElementComponent.dso = mockCollectionWithoutAbstract.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts index 75d5966767..691a69dde4 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts @@ -17,7 +17,7 @@ const truncatableServiceStub: any = { const mockCommunityWithAbstract: CommunitySearchResult = new CommunitySearchResult(); mockCommunityWithAbstract.hitHighlights = {}; -mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), { +mockCommunityWithAbstract.indexableObject = Object.assign(new Community(), { metadata: { 'dc.description.abstract': [ { @@ -30,7 +30,7 @@ mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), { const mockCommunityWithoutAbstract: CommunitySearchResult = new CommunitySearchResult(); mockCommunityWithoutAbstract.hitHighlights = {}; -mockCommunityWithoutAbstract.dspaceObject = Object.assign(new Community(), { +mockCommunityWithoutAbstract.indexableObject = Object.assign(new Community(), { metadata: { 'dc.title': [ { @@ -63,7 +63,7 @@ describe('CommunitySearchResultListElementComponent', () => { describe('When the community has an abstract', () => { beforeEach(() => { - communitySearchResultListElementComponent.dso = mockCommunityWithAbstract.dspaceObject; + communitySearchResultListElementComponent.dso = mockCommunityWithAbstract.indexableObject; fixture.detectChanges(); }); @@ -75,7 +75,7 @@ describe('CommunitySearchResultListElementComponent', () => { describe('When the community has no abstract', () => { beforeEach(() => { - communitySearchResultListElementComponent.dso = mockCommunityWithoutAbstract.dspaceObject; + communitySearchResultListElementComponent.dso = mockCommunityWithoutAbstract.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts index 8567fc1782..8bbb621312 100644 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts @@ -18,7 +18,7 @@ const truncatableServiceStub: any = { const mockItemWithAuthorAndDate: ItemSearchResult = new ItemSearchResult(); mockItemWithAuthorAndDate.hitHighlights = {}; -mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), { +mockItemWithAuthorAndDate.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.contributor.author': [ @@ -38,7 +38,7 @@ mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), { const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult(); mockItemWithoutAuthorAndDate.hitHighlights = {}; -mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), { +mockItemWithoutAuthorAndDate.indexableObject = Object.assign(new Item(), { bitstreams: observableOf({}), metadata: { 'dc.title': [ @@ -78,7 +78,7 @@ describe('ItemSearchResultListElementComponent', () => { describe('When the item has an author', () => { beforeEach(() => { - itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; + itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -90,7 +90,7 @@ describe('ItemSearchResultListElementComponent', () => { describe('When the item has no author', () => { beforeEach(() => { - itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -102,7 +102,7 @@ describe('ItemSearchResultListElementComponent', () => { describe('When the item has an issuedate', () => { beforeEach(() => { - itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; + itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.indexableObject; fixture.detectChanges(); }); @@ -114,7 +114,7 @@ describe('ItemSearchResultListElementComponent', () => { describe('When the item has no issuedate', () => { beforeEach(() => { - itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.indexableObject; fixture.detectChanges(); }); diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index 525d39e798..4194f2ae3e 100644 --- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts @@ -18,7 +18,7 @@ export class SearchResultListElementComponent, K exten public constructor(@Inject('objectElementProvider') public listable: ListableObject, private truncatableService: TruncatableService) { super(listable); - this.dso = this.object.dspaceObject; + this.dso = this.object.indexableObject; } /** From ceb0e7eeb48b70b747d0cfbfd56027d86df0644a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 15:33:59 +0200 Subject: [PATCH 33/70] Fixed unexpected error exception during test --- src/app/core/shared/item.model.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 6cd5634fd0..c527fe0357 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -5,7 +5,7 @@ import { DSpaceObject } from './dspace-object.model'; import { Collection } from './collection.model'; import { RemoteData } from '../data/remote-data'; import { Bitstream } from './bitstream.model'; -import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; import { PaginatedList } from '../data/paginated-list'; export class Item extends DSpaceObject { @@ -90,7 +90,7 @@ export class Item extends DSpaceObject { */ getBitstreamsByBundleName(bundleName: string): Observable { return this.bitstreams.pipe( - filter((rd: RemoteData>) => !rd.isResponsePending), + filter((rd: RemoteData>) => !rd.isResponsePending && isNotUndefined(rd.payload)), map((rd: RemoteData>) => rd.payload.page), filter((bitstreams: Bitstream[]) => hasValue(bitstreams)), take(1), From 589b0ea63fcfd5c4bb898e1fe8c7901aeadcdc80 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 17:17:15 +0200 Subject: [PATCH 34/70] renamed dspaceObject to indexableObject --- src/app/core/data/search-response-parsing.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index 790df0624b..9ab0104393 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -37,7 +37,7 @@ export class SearchResponseParsingService implements ResponseParsingService { const dsoSelfLinks = payload._embedded.objects .filter((object) => hasValue(object._embedded)) - .map((object) => object._embedded.resultObject) + .map((object) => object._embedded.indexableObject) // we don't need embedded collections, bitstreamformats, etc for search results. // And parsing them all takes up a lot of time. Throw them away to improve performance // until objs until partial results are supported by the rest api @@ -53,7 +53,7 @@ export class SearchResponseParsingService implements ResponseParsingService { const objects = payload._embedded.objects .filter((object) => hasValue(object._embedded)) .map((object, index) => Object.assign({}, object, { - resultObject: dsoSelfLinks[index], + indexableObject: dsoSelfLinks[index], hitHighlights: hitHighlights[index], // we don't need embedded collections, bitstreamformats, etc for search results. // And parsing them all takes up a lot of time. Throw them away to improve performance From 42fa67361af29dc7996ba3bc0e4efc84318f166f Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 18:13:55 +0200 Subject: [PATCH 35/70] Use search link to retrieve filter values --- .../search-facet-option.component.ts | 19 +++++++++++++++++-- .../search-facet-range-option.component.html | 4 ++-- ...earch-facet-selected-option.component.html | 4 ++-- .../search-facet-selected-option.component.ts | 11 +++++++++++ .../search-labels.component.html | 6 +++--- .../search-labels/search-labels.component.ts | 11 +++++++++++ src/app/+search-page/search-options.model.ts | 5 ++++- 7 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index c4b339f464..fc08788c4b 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -70,7 +70,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { * Checks if a value for this filter is currently active */ private isChecked(): Observable { - return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.filterValue.value); + return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.getFacetValueFromSearchLink()); } /** @@ -86,11 +86,26 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { */ private updateAddParams(selectedValues: string[]): void { this.addQueryParams = { - [this.filterConfig.paramName]: [...selectedValues, this.filterValue.value], + [this.filterConfig.paramName]: [...selectedValues, this.getFacetValueFromSearchLink()], page: 1 }; } + /** + * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved + * Retrieve facet value from search link + */ + private getFacetValueFromSearchLink(): string { + const search = this.filterValue.search; + const hashes = search.slice(search.indexOf('?') + 1).split('&'); + const params = {}; + hashes.map((hash) => { + const [key, val] = hash.split('='); + params[key] = decodeURIComponent(val) + }); + + return params[this.filterConfig.paramName]; + } /** * Make sure the subscription is unsubscribed from when this component is destroyed */ diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html index b485fe0fd0..8e8ad9b4e3 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html @@ -1,8 +1,8 @@ - {{filterValue.value}} + {{filterValue.label}} {{filterValue.count}} - \ No newline at end of file + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html index ba43bae100..5abd0810c7 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html @@ -2,5 +2,5 @@ [routerLink]="[getSearchLink()]" [queryParams]="removeQueryParams" queryParamsHandling="merge"> - {{selectedValue}} - \ No newline at end of file + {{normalizeFilterValue(selectedValue)}} + diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts index 5137bf8ffc..8b56c61c83 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -76,6 +76,17 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy { }; } + /** + * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved + * Strips operator from filter value + * e.g. 'test ,operator' => 'test' + * + * @param value + */ + normalizeFilterValue(value: string) { + return value.replace(/,[^,]*$/g, ''); + } + /** * Make sure the subscription is unsubscribed from when this component is destroyed */ diff --git a/src/app/+search-page/search-labels/search-labels.component.html b/src/app/+search-page/search-labels/search-labels.component.html index 61a5618dad..cac81e8717 100644 --- a/src/app/+search-page/search-labels/search-labels.component.html +++ b/src/app/+search-page/search-labels/search-labels.component.html @@ -2,11 +2,11 @@ diff --git a/src/app/+search-page/search-labels/search-labels.component.ts b/src/app/+search-page/search-labels/search-labels.component.ts index fd82de326c..c7ad9790ad 100644 --- a/src/app/+search-page/search-labels/search-labels.component.ts +++ b/src/app/+search-page/search-labels/search-labels.component.ts @@ -56,4 +56,15 @@ export class SearchLabelsComponent { getSearchLink() { return this.searchService.getSearchLink(); } + + /** + * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved + * Strips operator from filter value + * e.g. 'test ,operator' => 'test' + * + * @param value + */ + normalizeFilterValue(value: string) { + return value.replace(/,[^,]*$/g, ''); + } } diff --git a/src/app/+search-page/search-options.model.ts b/src/app/+search-page/search-options.model.ts index e56cec1724..59a6f0f93d 100644 --- a/src/app/+search-page/search-options.model.ts +++ b/src/app/+search-page/search-options.model.ts @@ -44,7 +44,10 @@ export class SearchOptions { } if (isNotEmpty(this.filters)) { this.filters.forEach((filter: SearchFilter) => { - filter.values.forEach((value) => args.push(`${filter.key}=${value},${filter.operator}`)); + filter.values.forEach((value) => { + const filterValue = value.includes(',') ? `${value}` : `${value},${filter.operator}`; + args.push(`${filter.key}=${filterValue}`) + }); }); } if (isNotEmpty(args)) { From 030dd20631bc023073637a0d96b322cd821f47e8 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 18:16:58 +0200 Subject: [PATCH 36/70] Fixed visualization of pagination info div --- src/app/shared/pagination/pagination.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/pagination/pagination.component.html b/src/app/shared/pagination/pagination.component.html index 7336866e5c..cfdb95c8b9 100644 --- a/src/app/shared/pagination/pagination.component.html +++ b/src/app/shared/pagination/pagination.component.html @@ -1,7 +1,7 @@
    -
    +
    {{ 'pagination.showing.label' | translate }} {{ 'pagination.showing.detail' | translate:getShowingDetails(collectionSize)}}
    From f9b96dc6d57729c765afacb80985c1bf4b6b13d6 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 18:41:26 +0200 Subject: [PATCH 37/70] fixed test --- .../search-facet-option.component.spec.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index 279ce0f97a..f44dc0f69f 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -19,9 +19,10 @@ import { By } from '@angular/platform-browser'; describe('SearchFacetOptionComponent', () => { let comp: SearchFacetOptionComponent; let fixture: ComponentFixture; - const filterName1 = 'test name'; + const filterName1 = 'testname'; const value1 = 'testvalue1'; const value2 = 'test2'; + const operator = 'equals'; const value3 = 'another value3'; const mockFilterConfig = Object.assign(new SearchFilterConfig(), { name: filterName1, @@ -36,7 +37,7 @@ describe('SearchFacetOptionComponent', () => { label: value2, value: value2, count: 20, - search: '' + search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2},${operator}` }; const searchLink = '/search'; @@ -91,12 +92,12 @@ describe('SearchFacetOptionComponent', () => { fixture.detectChanges(); }); - describe('when the updateAddParams method is called wih a value', () => { + describe('when the updateAddParams method is called with a value', () => { it('should update the addQueryParams with the new parameter values', () => { comp.addQueryParams = {}; (comp as any).updateAddParams(selectedValues); expect(comp.addQueryParams).toEqual({ - [mockFilterConfig.paramName]: [value1, value.value], + [mockFilterConfig.paramName]: [value1, `${value2},${operator}`], page: 1 }); }); From bbc27febdd27208feff0b607451ef455ecf03b46 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Wed, 3 Apr 2019 18:42:36 +0200 Subject: [PATCH 38/70] refactored ItemDetailPreviewComponent --- src/app/+item-page/item-page.module.ts | 18 ++++++++ .../item-detail-preview.component.html | 41 +++++++++++++++---- .../item-detail-preview.component.ts | 11 +++++ src/app/shared/shared.module.ts | 18 -------- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/app/+item-page/item-page.module.ts b/src/app/+item-page/item-page.module.ts index f56f45d753..06b4ecf1e4 100644 --- a/src/app/+item-page/item-page.module.ts +++ b/src/app/+item-page/item-page.module.ts @@ -5,6 +5,15 @@ import { SharedModule } from '../shared/shared.module'; import { ItemPageComponent } from './simple/item-page.component'; import { ItemPageRoutingModule } from './item-page-routing.module'; +import { MetadataUriValuesComponent } from './field-components/metadata-uri-values/metadata-uri-values.component'; +import { ItemPageAuthorFieldComponent } from './simple/field-components/specific-field/author/item-page-author-field.component'; +import { ItemPageDateFieldComponent } from './simple/field-components/specific-field/date/item-page-date-field.component'; +import { ItemPageAbstractFieldComponent } from './simple/field-components/specific-field/abstract/item-page-abstract-field.component'; +import { ItemPageUriFieldComponent } from './simple/field-components/specific-field/uri/item-page-uri-field.component'; +import { ItemPageTitleFieldComponent } from './simple/field-components/specific-field/title/item-page-title-field.component'; +import { ItemPageSpecificFieldComponent } from './simple/field-components/specific-field/item-page-specific-field.component'; +import { FileSectionComponent } from './simple/field-components/file-section/file-section.component'; +import { CollectionsComponent } from './field-components/collections/collections.component'; import { FullItemPageComponent } from './full/full-item-page.component'; import { FullFileSectionComponent } from './full/field-components/file-section/full-file-section.component'; import { EditItemPageModule } from './edit-item-page/edit-item-page.module'; @@ -19,6 +28,15 @@ import { EditItemPageModule } from './edit-item-page/edit-item-page.module'; declarations: [ ItemPageComponent, FullItemPageComponent, + MetadataUriValuesComponent, + ItemPageAuthorFieldComponent, + ItemPageDateFieldComponent, + ItemPageAbstractFieldComponent, + ItemPageUriFieldComponent, + ItemPageTitleFieldComponent, + ItemPageSpecificFieldComponent, + FileSectionComponent, + CollectionsComponent, FullFileSectionComponent ] }) diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html index 10e7e98d87..e7d960599e 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html @@ -3,20 +3,47 @@
    - +

    + + {{('mydspace.results.no-title' | translate)}} +

    - - - + + + + {{mdValue.value}} + + + + {{('mydspace.results.no-date' | translate)}} + + + + + + {{mdValue.value}} + + + + {{('mydspace.results.no-authors' | translate)}} + +
    - - - + + + + {{mdValue.value}} + + + + {{('mydspace.results.no-abstract' | translate)}} + +
    diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts index 9f92f79859..d4244f2760 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts @@ -6,6 +6,7 @@ import { Item } from '../../../../core/shared/item.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { fadeInOut } from '../../../animations/fade'; import { Bitstream } from '../../../../core/shared/bitstream.model'; +import { Metadata } from '../../../../core/shared/metadata.utils'; /** * This component show metadata for the given item object in the detail view. @@ -43,6 +44,16 @@ export class ItemDetailPreviewComponent { */ public thumbnail$: Observable; + /** + * Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. + * + * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @returns {string[]} the matching string values or an empty array. + */ + allMetadataValues(keyOrKeys: string | string[]): string[] { + return Metadata.allValues([this.object.hitHighlights, this.item.metadata], keyOrKeys); + } + /** * Initialize all instance variables */ diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 00f357cda6..8ef7e7723e 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -127,17 +127,8 @@ import { EditItemSelectorComponent } from './dso-selector/modal-wrappers/edit-it import { EditCommunitySelectorComponent } from './dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component'; import { EditCollectionSelectorComponent } from './dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component'; import { ItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component'; -import { ItemPageAuthorFieldComponent } from '../+item-page/simple/field-components/specific-field/author/item-page-author-field.component'; -import { ItemPageDateFieldComponent } from '../+item-page/simple/field-components/specific-field/date/item-page-date-field.component'; -import { ItemPageAbstractFieldComponent } from '../+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component'; -import { ItemPageUriFieldComponent } from '../+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component'; -import { ItemPageTitleFieldComponent } from '../+item-page/simple/field-components/specific-field/title/item-page-title-field.component'; -import { ItemPageSpecificFieldComponent } from '../+item-page/simple/field-components/specific-field/item-page-specific-field.component'; -import { FileSectionComponent } from '../+item-page/simple/field-components/file-section/file-section.component'; import { MetadataFieldWrapperComponent } from '../+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component'; -import { CollectionsComponent } from '../+item-page/field-components/collections/collections.component'; import { MetadataValuesComponent } from '../+item-page/field-components/metadata-values/metadata-values.component'; -import { MetadataUriValuesComponent } from '../+item-page/field-components/metadata-uri-values/metadata-uri-values.component'; import { RoleDirective } from './roles/role.directive'; import { UserMenuComponent } from './auth-nav-menu/user-menu/user-menu.component'; import { ClaimedTaskActionsReturnToPoolComponent } from './mydspace-actions/claimed-task/return-to-pool/claimed-task-actions-return-to-pool.component'; @@ -296,17 +287,8 @@ const ENTRY_COMPONENTS = [ ]; const SHARED_ITEM_PAGE_COMPONENTS = [ - CollectionsComponent, - FileSectionComponent, - ItemPageAuthorFieldComponent, - ItemPageDateFieldComponent, - ItemPageAbstractFieldComponent, - ItemPageUriFieldComponent, - ItemPageTitleFieldComponent, - ItemPageSpecificFieldComponent, MetadataFieldWrapperComponent, MetadataValuesComponent, - MetadataUriValuesComponent ]; const PROVIDERS = [ From 71c0c1b52c5999f4b26f39cfc009cc745f6be5ec Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Thu, 4 Apr 2019 12:43:17 +0200 Subject: [PATCH 39/70] Fixed an issue with place property removal from object that represent metadata section field on rest side --- .../submission-response-parsing.service.ts | 14 +++++++------- .../models/tag/dynamic-tag.component.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts index 20dfb43cbd..f5481ec274 100644 --- a/src/app/core/submission/submission-response-parsing.service.ts +++ b/src/app/core/submission/submission-response-parsing.service.ts @@ -27,16 +27,16 @@ export function isServerFormValue(obj: any): boolean { && obj.hasOwnProperty('value') && obj.hasOwnProperty('language') && obj.hasOwnProperty('authority') - && obj.hasOwnProperty('confidence') - && obj.hasOwnProperty('place')) + && obj.hasOwnProperty('confidence')) } /** * Export a function to normalize sections object of the server response * * @param obj + * @param objIndex */ -export function normalizeSectionData(obj: any) { +export function normalizeSectionData(obj: any, objIndex?: number) { let result: any = obj; if (isNotNull(obj)) { // If is an Instance of FormFieldMetadataValueObject normalize it @@ -49,14 +49,14 @@ export function normalizeSectionData(obj: any) { obj.language, obj.authority, (obj.display || obj.value), - obj.place, + obj.place || objIndex, obj.confidence, obj.otherInformation ); } else if (Array.isArray(obj)) { result = []; obj.forEach((item, index) => { - result[index] = normalizeSectionData(item); + result[index] = normalizeSectionData(item, index); }); } else if (typeof obj === 'object') { result = Object.create({}); @@ -141,9 +141,9 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService // If entry is not an array, for sure is not a section of type form if (Array.isArray(entry)) { normalizedSectionData[metdadataId] = []; - entry.forEach((valueItem) => { + entry.forEach((valueItem, index) => { // Parse value and normalize it - const normValue = normalizeSectionData(valueItem); + const normValue = normalizeSectionData(valueItem, index); if (isNotEmpty(normValue)) { normalizedSectionData[metdadataId].push(normValue); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts index d61134347a..a44a20d4bd 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.ts @@ -168,7 +168,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement } private addTagsToChips() { - if (!this.hasAuthority || !this.model.authorityOptions.closed) { + if (hasValue(this.currentValue) && (!this.hasAuthority || !this.model.authorityOptions.closed)) { let res: string[] = []; res = this.currentValue.split(','); From 174c4f63980aad705f4a1ee06a0bff271ce9da69 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 5 Apr 2019 12:34:35 +0200 Subject: [PATCH 40/70] Implemented authority facet Retrieve selected facet values as FacetValue objects fixed tests --- .../search-authority-filter.component.html | 27 +++++++++++++ .../search-authority-filter.component.scss | 23 +++++++++++ .../search-authority-filter.component.ts | 37 ++++++++++++++++++ .../search-facet-option.component.spec.ts | 39 +++++++++++++++++-- .../search-facet-option.component.ts | 28 +++++++------ ...earch-facet-selected-option.component.html | 2 +- ...ch-facet-selected-option.component.spec.ts | 8 +++- .../search-facet-selected-option.component.ts | 16 ++------ .../search-facet-filter.component.ts | 36 ++++++++++++----- .../search-labels.component.spec.ts | 18 ++++++++- .../search-labels/search-labels.component.ts | 8 ++-- src/app/+search-page/search-page.module.ts | 7 +++- .../search-service/filter-type.model.ts | 5 +++ 13 files changed, 209 insertions(+), 45 deletions(-) create mode 100644 src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html create mode 100644 src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.scss create mode 100644 src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts diff --git a/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html new file mode 100644 index 0000000000..6958c422e1 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.html @@ -0,0 +1,27 @@ + diff --git a/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.scss b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.scss new file mode 100644 index 0000000000..33e354f2d8 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.scss @@ -0,0 +1,23 @@ +@import '../../../../../styles/variables.scss'; +@import '../../../../../styles/mixins.scss'; + +.filters { + a { + color: $body-color; + &:hover, &focus { + text-decoration: none; + } + span.badge { + vertical-align: text-top; + } + } + .toggle-more-filters a { + color: $link-color; + text-decoration: underline; + cursor: pointer; + } +} +::ng-deep em { + font-weight: bold; + font-style: normal; +} diff --git a/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts new file mode 100644 index 0000000000..eaa73aba26 --- /dev/null +++ b/src/app/+search-page/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit } from '@angular/core'; + +import { FilterType } from '../../../search-service/filter-type.model'; +import { facetLoad, SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component'; +import { renderFacetFor } from '../search-filter-type-decorator'; +import { FacetValue } from '../../../search-service/facet-value.model'; + +@Component({ + selector: 'ds-search-authority-filter', + styleUrls: ['./search-authority-filter.component.scss'], + templateUrl: './search-authority-filter.component.html', + animations: [facetLoad] +}) + +/** + * Component that represents an authority facet for a specific filter configuration + */ +@renderFacetFor(FilterType.authority) +export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent implements OnInit { + + /** + * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved + * Retrieve facet value from search link + */ + protected getFacetValue(facet: FacetValue): string { + const search = facet.search; + const hashes = search.slice(search.indexOf('?') + 1).split('&'); + const params = {}; + hashes.map((hash) => { + const [key, val] = hash.split('='); + params[key] = decodeURIComponent(val) + }); + + return params[this.filterConfig.paramName]; + } + +} diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index f44dc0f69f..dda72ed970 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -20,10 +20,12 @@ describe('SearchFacetOptionComponent', () => { let comp: SearchFacetOptionComponent; let fixture: ComponentFixture; const filterName1 = 'testname'; + const filterName2 = 'testAuthorityname'; const value1 = 'testvalue1'; const value2 = 'test2'; - const operator = 'equals'; + const operator = 'authority'; const value3 = 'another value3'; + const mockFilterConfig = Object.assign(new SearchFilterConfig(), { name: filterName1, type: FilterType.range, @@ -33,11 +35,27 @@ describe('SearchFacetOptionComponent', () => { minValue: 200, maxValue: 3000, }); + + const mockAuthorityFilterConfig = Object.assign(new SearchFilterConfig(), { + name: filterName2, + type: FilterType.authority, + hasFacets: false, + isOpenByDefault: false, + pageSize: 2 + }); + const value: FacetValue = { label: value2, value: value2, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2},${operator}` + search: `` + }; + + const authorityValue: FacetValue = { + label: value2, + value: value2, + count: 20, + search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` }; const searchLink = '/search'; @@ -97,7 +115,22 @@ describe('SearchFacetOptionComponent', () => { comp.addQueryParams = {}; (comp as any).updateAddParams(selectedValues); expect(comp.addQueryParams).toEqual({ - [mockFilterConfig.paramName]: [value1, `${value2},${operator}`], + [mockFilterConfig.paramName]: [value1, value.value], + page: 1 + }); + }); + }); + + describe('when filter type is authority and the updateAddParams method is called with a value', () => { + it('should update the addQueryParams with the new parameter values', () => { + comp.filterValue = authorityValue; + comp.filterConfig = mockAuthorityFilterConfig; + fixture.detectChanges(); + + comp.addQueryParams = {}; + (comp as any).updateAddParams(selectedValues); + expect(comp.addQueryParams).toEqual({ + [mockAuthorityFilterConfig.paramName]: [value1, `${value2},${operator}`], page: 1 }); }); diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index fc08788c4b..3b0e346cd6 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -8,6 +8,7 @@ import { SearchService } from '../../../../search-service/search.service'; import { SearchFilterService } from '../../search-filter.service'; import { SearchConfigurationService } from '../../../../search-service/search-configuration.service'; import { hasValue } from '../../../../../shared/empty.util'; +import { FilterType } from '../../../../search-service/filter-type.model'; @Component({ selector: 'ds-search-facet-option', @@ -70,7 +71,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { * Checks if a value for this filter is currently active */ private isChecked(): Observable { - return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.getFacetValueFromSearchLink()); + return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.getFacetValue()); } /** @@ -86,7 +87,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { */ private updateAddParams(selectedValues: string[]): void { this.addQueryParams = { - [this.filterConfig.paramName]: [...selectedValues, this.getFacetValueFromSearchLink()], + [this.filterConfig.paramName]: [...selectedValues, this.getFacetValue()], page: 1 }; } @@ -95,17 +96,22 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved * Retrieve facet value from search link */ - private getFacetValueFromSearchLink(): string { - const search = this.filterValue.search; - const hashes = search.slice(search.indexOf('?') + 1).split('&'); - const params = {}; - hashes.map((hash) => { - const [key, val] = hash.split('='); - params[key] = decodeURIComponent(val) - }); + private getFacetValue(): string { + if (this.filterConfig.type === FilterType.authority) { + const search = this.filterValue.search; + const hashes = search.slice(search.indexOf('?') + 1).split('&'); + const params = {}; + hashes.map((hash) => { + const [key, val] = hash.split('='); + params[key] = decodeURIComponent(val) + }); - return params[this.filterConfig.paramName]; + return params[this.filterConfig.paramName]; + } else { + return this.filterValue.value; + } } + /** * Make sure the subscription is unsubscribed from when this component is destroyed */ diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html index 5abd0810c7..5657bd224e 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html @@ -2,5 +2,5 @@ [routerLink]="[getSearchLink()]" [queryParams]="removeQueryParams" queryParamsHandling="merge"> - {{normalizeFilterValue(selectedValue)}} + {{selectedValue.label}} diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts index 545ba1d66b..f4b7ea1466 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts @@ -32,6 +32,12 @@ describe('SearchFacetSelectedOptionComponent', () => { const searchLink = '/search'; const selectedValues = [value1, value2]; + const facetValue = { + label: value2, + value: value2, + count: 1, + search: '' + }; const selectedValues$ = observableOf(selectedValues); let filterService; let searchService; @@ -76,7 +82,7 @@ describe('SearchFacetSelectedOptionComponent', () => { filterService = (comp as any).filterService; searchService = (comp as any).searchService; router = (comp as any).router; - comp.selectedValue = value2; + comp.selectedValue = facetValue; comp.selectedValues$ = selectedValues$; comp.filterConfig = mockFilterConfig; fixture.detectChanges(); diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts index 8b56c61c83..d713696550 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -6,6 +6,7 @@ import { SearchService } from '../../../../search-service/search.service'; import { SearchFilterService } from '../../search-filter.service'; import { hasValue } from '../../../../../shared/empty.util'; import { SearchConfigurationService } from '../../../../search-service/search-configuration.service'; +import { FacetValue } from '../../../../search-service/facet-value.model'; @Component({ selector: 'ds-search-facet-selected-option', @@ -19,7 +20,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy { /** * The value for this component */ - @Input() selectedValue: string; + @Input() selectedValue: FacetValue; /** * The filter configuration for this facet option @@ -71,22 +72,11 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy { */ private updateRemoveParams(selectedValues: string[]): void { this.removeQueryParams = { - [this.filterConfig.paramName]: selectedValues.filter((v) => v !== this.selectedValue), + [this.filterConfig.paramName]: selectedValues.filter((v) => v !== this.selectedValue.label), page: 1 }; } - /** - * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved - * Strips operator from filter value - * e.g. 'test ,operator' => 'test' - * - * @param value - */ - normalizeFilterValue(value: string) { - return value.replace(/,[^,]*$/g, ''); - } - /** * Make sure the subscription is unsubscribed from when this component is destroyed */ diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index 8bdf36bf9d..5959a2331e 100644 --- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -6,7 +6,7 @@ import { Subject, Subscription } from 'rxjs'; -import { switchMap, distinctUntilChanged, map, take } from 'rxjs/operators'; +import { switchMap, distinctUntilChanged, map, take, flatMap } from 'rxjs/operators'; import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; @@ -57,7 +57,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { /** * List of subscriptions to unsubscribe from */ - private subs: Subscription[] = []; + protected subs: Subscription[] = []; /** * Emits the result values for this filter found by the current filter query @@ -67,8 +67,8 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { /** * Emits the active values for this filter */ - selectedValues$: Observable; - private collapseNextUpdate = true; + selectedValues$: Observable; + protected collapseNextUpdate = true; /** * State of the requested facets used to time the animation @@ -95,10 +95,9 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined)); this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged()); - this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig); this.searchOptions$ = this.searchConfigService.searchOptions; this.subs.push(this.searchOptions$.subscribe(() => this.updateFilterValueList())); - const facetValues = observableCombineLatest(this.searchOptions$, this.currentPage).pipe( + const facetValues$ = observableCombineLatest(this.searchOptions$, this.currentPage).pipe( map(([options, page]) => { return { options, page } }), @@ -116,8 +115,17 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { ) }) ); + + this.selectedValues$ = observableCombineLatest( + this.filterService.getSelectedValuesForFilter(this.filterConfig), + facetValues$.pipe(flatMap((facetValues) => facetValues.values))).pipe( + map(([selectedValues, facetValues]) => { + return facetValues.payload.page.filter((facetValue) => selectedValues.includes(this.getFacetValue(facetValue))) + }) + ); + let filterValues = []; - this.subs.push(facetValues.subscribe((facetOutcome) => { + this.subs.push(facetValues$.subscribe((facetOutcome) => { const newValues$ = facetOutcome.values; if (this.collapseNextUpdate) { @@ -202,7 +210,10 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { if (isNotEmpty(data)) { this.router.navigate([this.getSearchLink()], { queryParams: - { [this.filterConfig.paramName]: [...selectedValues, data] }, + { [this.filterConfig.paramName]: [ + ...selectedValues.map((facet) => this.getFacetValue(facet)), + data + ] }, queryParamsHandling: 'merge' }); this.filter = ''; @@ -253,7 +264,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { return rd.payload.page.map((facet) => { return { displayValue: this.getDisplayValue(facet, data), - value: facet.value + value: this.getFacetValue(facet) } }) } @@ -265,6 +276,13 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { } } + /** + * Retrieve facet value + */ + protected getFacetValue(facet: FacetValue): string { + return facet.value; + } + /** * Transforms the facet value string, so if the query matches part of the value, it's emphasized in the value * @param {FacetValue} facet The value of the facet as returned by the server diff --git a/src/app/+search-page/search-labels/search-labels.component.spec.ts b/src/app/+search-page/search-labels/search-labels.component.spec.ts index aada73673e..d28698764c 100644 --- a/src/app/+search-page/search-labels/search-labels.component.spec.ts +++ b/src/app/+search-page/search-labels/search-labels.component.spec.ts @@ -9,7 +9,6 @@ import { SearchServiceStub } from '../../shared/testing/search-service-stub'; import { Observable, of as observableOf } from 'rxjs'; import { Params } from '@angular/router'; import { ObjectKeysPipe } from '../../shared/utils/object-keys-pipe'; -import { SearchConfigurationService } from '../search-service/search-configuration.service'; import { SEARCH_CONFIG_SERVICE } from '../../+my-dspace-page/my-dspace-page.component'; import { SearchConfigurationServiceStub } from '../../shared/testing/search-configuration-service-stub'; @@ -22,8 +21,11 @@ describe('SearchLabelsComponent', () => { const field1 = 'author'; const field2 = 'subject'; - const value1 = 'TestAuthor'; + 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 = [ @@ -68,4 +70,16 @@ describe('SearchLabelsComponent', () => { }); }) }); + + 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); + }) + }); }); diff --git a/src/app/+search-page/search-labels/search-labels.component.ts b/src/app/+search-page/search-labels/search-labels.component.ts index c7ad9790ad..1f12311210 100644 --- a/src/app/+search-page/search-labels/search-labels.component.ts +++ b/src/app/+search-page/search-labels/search-labels.component.ts @@ -59,12 +59,14 @@ export class SearchLabelsComponent { /** * TODO to review after https://github.com/DSpace/dspace-angular/issues/368 is resolved - * Strips operator from filter value - * e.g. 'test ,operator' => 'test' + * Strips authority operator from filter value + * e.g. 'test ,authority' => 'test' * * @param value */ normalizeFilterValue(value: string) { - return value.replace(/,[^,]*$/g, ''); + // const pattern = /,[^,]*$/g; + const pattern = /,authority*$/g; + return value.replace(pattern, ''); } } diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 482d2db8c1..f5e91c954d 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -28,6 +28,7 @@ import { SearchFacetOptionComponent } from './search-filters/search-filter/searc import { SearchFacetSelectedOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component'; 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'; const effects = [ SearchSidebarEffects @@ -54,7 +55,8 @@ const components = [ SearchFacetOptionComponent, SearchFacetSelectedOptionComponent, SearchFacetRangeOptionComponent, - SearchSwitchConfigurationComponent + SearchSwitchConfigurationComponent, + SearchAuthorityFilterComponent ]; @NgModule({ @@ -82,7 +84,8 @@ const components = [ SearchBooleanFilterComponent, SearchFacetOptionComponent, SearchFacetSelectedOptionComponent, - SearchFacetRangeOptionComponent + SearchFacetRangeOptionComponent, + SearchAuthorityFilterComponent ], exports: components }) diff --git a/src/app/+search-page/search-service/filter-type.model.ts b/src/app/+search-page/search-service/filter-type.model.ts index d9b9629347..d5a338de6d 100644 --- a/src/app/+search-page/search-service/filter-type.model.ts +++ b/src/app/+search-page/search-service/filter-type.model.ts @@ -2,6 +2,11 @@ * Enumeration containing all possible types for filters */ export enum FilterType { + /** + * Represents authority facets + */ + authority = 'authority', + /** * Represents simple text facets */ From 5491534ff8754f0a032b9bc84aae73ee571d8de3 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 5 Apr 2019 12:45:49 +0200 Subject: [PATCH 41/70] Removed message board components --- .../message-board.component.html | 67 ----- .../message-board.component.scss | 56 ----- .../message-board/message-board.component.ts | 238 ------------------ .../message/message.component.html | 56 ----- .../message/message.component.scss | 54 ---- .../message/message.component.ts | 83 ------ .../claimed-task-actions.component.html | 6 - .../pool-task-actions.component.html | 7 - .../workflowitem-actions.component.html | 5 - .../workspaceitem-actions.component.html | 6 - src/app/shared/shared.module.ts | 4 - 11 files changed, 582 deletions(-) delete mode 100644 src/app/shared/message-board/message-board.component.html delete mode 100644 src/app/shared/message-board/message-board.component.scss delete mode 100644 src/app/shared/message-board/message-board.component.ts delete mode 100644 src/app/shared/message-board/message/message.component.html delete mode 100644 src/app/shared/message-board/message/message.component.scss delete mode 100644 src/app/shared/message-board/message/message.component.ts diff --git a/src/app/shared/message-board/message-board.component.html b/src/app/shared/message-board/message-board.component.html deleted file mode 100644 index 80a37d8d48..0000000000 --- a/src/app/shared/message-board/message-board.component.html +++ /dev/null @@ -1,67 +0,0 @@ - - - New - - - - - - - - - diff --git a/src/app/shared/message-board/message-board.component.scss b/src/app/shared/message-board/message-board.component.scss deleted file mode 100644 index b38edffbad..0000000000 --- a/src/app/shared/message-board/message-board.component.scss +++ /dev/null @@ -1,56 +0,0 @@ -@import '../../../styles/variables'; - -.modal-header { - background-color: #2B4E72; - color: white; -} - -.modal-footer { - width: 100%; - display: block; -} - -.modal-footer :not(:first-child){ - margin: 0 auto !important; -} - -.close { - position: relative; - top: 0; - right:0; -} - -textarea { - //resize: none; - margin-bottom: 15px; -} - -.chat -{ - list-style: none; - margin: 10px; - padding: 0; -} - -::-webkit-scrollbar-track -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); - background-color: #FAF5F5; -} - -::-webkit-scrollbar -{ - width: 12px; - background-color: #F5F5FC; -} - -::-webkit-scrollbar-thumb -{ - -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); - background-color: #555; -} - -.notification { - left: -20px; - top: -25px -} diff --git a/src/app/shared/message-board/message-board.component.ts b/src/app/shared/message-board/message-board.component.ts deleted file mode 100644 index e05db8a9d6..0000000000 --- a/src/app/shared/message-board/message-board.component.ts +++ /dev/null @@ -1,238 +0,0 @@ -import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; - -import { combineLatest, Observable, of as observableOf, Subscription } from 'rxjs'; -import { - distinctUntilChanged, - filter, - find, - first, - flatMap, - map, - mergeMap, - reduce, - startWith, - withLatestFrom -} from 'rxjs/operators'; -import { select, Store } from '@ngrx/store'; -import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; -import { TranslateService } from '@ngx-translate/core'; - -import { Bitstream } from '../../core/shared/bitstream.model'; -import { MessageService } from '../../core/message/message.service'; -import { NotificationsService } from '../notifications/notifications.service'; -import { hasValue, isNotEmpty } from '../empty.util'; -import { Item } from '../../core/shared/item.model'; -import { RemoteData } from '../../core/data/remote-data'; -import { MessageDataResponse } from '../../core/message/message-data-response'; -import { AppState } from '../../app.reducer'; -import { getAuthenticatedUser } from '../../core/auth/selectors'; -import { EPerson } from '../../core/eperson/models/eperson.model'; - -@Component({ - selector: 'ds-message-board', - styleUrls: ['./message-board.component.scss'], - templateUrl: './message-board.component.html', - providers: [ - NgbActiveModal, - ] -}) - -export class MessageBoardComponent implements OnDestroy { - @Input() dso: any; - @Input() tooltipMessage: string; - @Output() refresh = new EventEmitter(); - - public item$: Observable; - public submitter$: Observable; - public user$: Observable; - public unreadMessages$: Observable = observableOf([]); - public modalRef: NgbModalRef; - public itemUUID$: Observable; - public messages$: Observable = observableOf([]); - public isSubmitter$: Observable; - public messageForm: FormGroup; - public processingMessage = false; - - private subs: Subscription[] = []; - private rememberEmitUnread = false; - private rememberEmitRead = false; - - constructor(private formBuilder: FormBuilder, - public msgService: MessageService, - private modalService: NgbModal, - private notificationsService: NotificationsService, - private store: Store, - private translate: TranslateService) { - } - - ngOnInit() { - // set formGroup - this.messageForm = this.formBuilder.group({ - textSubject: ['', Validators.required], - textDescription: ['', Validators.required] - }); - - this.user$ = this.store.pipe( - select(getAuthenticatedUser), - find((user: EPerson) => isNotEmpty(user)), - map((user: EPerson) => user)); - - this.item$ = this.dso.item.pipe( - find((rd: RemoteData) => (rd.hasSucceeded && isNotEmpty(rd.payload))), - map((rd: RemoteData) => rd.payload)); - - this.submitter$ = (this.dso.submitter as Observable>).pipe( - find((rd: RemoteData) => rd.hasSucceeded && isNotEmpty(rd.payload)), - map((rd: RemoteData) => rd.payload)); - - this.isSubmitter$ = combineLatest(this.user$, this.submitter$).pipe( - filter(([user, submitter]) => isNotEmpty(user) && isNotEmpty(submitter)), - map(([user, submitter]) => user.uuid === submitter.uuid)); - - this.messages$ = this.item$.pipe( - find((item: Item) => isNotEmpty(item)), - flatMap((item: Item) => item.getBitstreamsByBundleName('MESSAGE')), - filter((bitStreams: Bitstream[]) => isNotEmpty(bitStreams)), - startWith([]), - distinctUntilChanged()); - - this.unreadMessages$ = this.messages$.pipe( - filter((messages: Bitstream[]) => isNotEmpty(messages)), - flatMap((bitStream: Bitstream) => - observableOf(bitStream).pipe( - withLatestFrom(this.isUnread(bitStream)) - ) - ), - filter(([bitStream, isUnread]) => isUnread), - map(([bitStream, isUnread]) => bitStream), - reduce((acc: any, value: any) => [...acc, ...value], []), - startWith([]) - ); - - this.itemUUID$ = this.item$.pipe( - find((item: Item) => isNotEmpty(item)), - map((item: Item) => item.uuid)); - - } - - sendMessage(itemUUID) { - this.processingMessage = true; - const subject: string = this.messageForm.get('textSubject').value; - const description: string = this.messageForm.get('textDescription').value; - const body = { - uuid: itemUUID, - subject, - description - }; - this.subs.push( - this.msgService.createMessage(body).pipe( - first() - ).subscribe((res: MessageDataResponse) => { - this.processingMessage = false; - this.modalRef.dismiss('Send Message'); - if (res.hasSucceeded) { - // Refresh event - this.refresh.emit('read'); - this.notificationsService.success(null, - this.translate.get('submission.workflow.tasks.generic.success')); - } else { - this.notificationsService.error(null, - this.translate.get('submission.workflow.tasks.generic.error')); - } - }) - ); - } - - markAsUnread(msgUUID: string) { - if (msgUUID) { - const body = { - uuid: msgUUID - }; - this.subs.push( - this.msgService.markAsUnread(body).pipe( - find((res) => res.hasSucceeded) - ).subscribe((res) => { - if (!res.error) { - this.rememberEmitUnread = true; - this.rememberEmitRead = false; - } else { - this.notificationsService.error(null, this.translate.get('submission.workflow.tasks.generic.error')); - } - }) - ); - } - } - - emitRefresh() { - if (this.rememberEmitUnread && !this.rememberEmitRead) { - // Refresh event for Unread - this.refresh.emit('unread'); - } else if (!this.rememberEmitUnread && this.rememberEmitRead) { - // Refresh event for Read - this.refresh.emit('read'); - } - } - - markAsRead(msgUUID?: string) { - let ids$: Observable; - if (msgUUID) { - ids$ = observableOf([msgUUID]); - } else { - ids$ = this.unreadMessages$.pipe( - filter((messages: Bitstream[]) => isNotEmpty(messages)), - flatMap((message: Bitstream) => message.uuid), - reduce((acc: any, value: any) => [...acc, ...value], []), - startWith([]) - ) - } - - this.subs.push( - ids$.pipe( - filter((uuids) => isNotEmpty(uuids)), - mergeMap((uuid: any) => { - const body = { uuid }; - return this.msgService.markAsRead(body) - }) - ).subscribe((res: MessageDataResponse) => { - if (res.hasSucceeded) { - this.rememberEmitRead = true; - this.rememberEmitUnread = false; - } else { - this.notificationsService.error(null, this.translate.get('submission.workflow.tasks.generic.error')); - } - }) - ); - - } - - isUnread(m: Bitstream): Observable { - const accessioned = m.firstMetadataValue('dc.date.accessioned'); - const type = m.firstMetadataValue('dc.type'); - return this.isSubmitter$.pipe( - filter((isSubmitter) => isNotEmpty(isSubmitter)), - map((isSubmitter) => (!accessioned && - ((isSubmitter && type === 'outbound') || (!isSubmitter && type === 'inbound'))) - ), - startWith(false)); - } - - openMessageBoard(content) { - this.rememberEmitUnread = false; - this.rememberEmitRead = false; - this.markAsRead(); - this.modalRef = this.modalService.open(content, { size: 'lg' }); - this.modalRef.result.then((result) => { - this.emitRefresh(); - }, (reason) => { - this.emitRefresh(); - }); - } - - ngOnDestroy() { - this.subs - .filter((sub) => hasValue(sub)) - .forEach((sub) => sub.unsubscribe()); - } - -} diff --git a/src/app/shared/message-board/message/message.component.html b/src/app/shared/message-board/message/message.component.html deleted file mode 100644 index e6dfe7dcb5..0000000000 --- a/src/app/shared/message-board/message/message.component.html +++ /dev/null @@ -1,56 +0,0 @@ -
  • - -
    -
    - - - {{m.firstMetadataValue('dc.date.issued') | date: 'dd/MM/yyyy HH:mm'}} - - - - {{'mydspace.messages.mark-as-unread' | translate}} - - - - {{'mydspace.messages.mark-as-read' | translate}} - - -
    - - - - - -
    - -
    - - - - - -
    - -
    - - - -
    - {{messageContent | async}} - -
    -
    - -
  • diff --git a/src/app/shared/message-board/message/message.component.scss b/src/app/shared/message-board/message/message.component.scss deleted file mode 100644 index f7812e795f..0000000000 --- a/src/app/shared/message-board/message/message.component.scss +++ /dev/null @@ -1,54 +0,0 @@ -$user_bg: #e6f2ff; -$other_bg: #EFEFEF; - -li { - margin-bottom: 10px; - padding-bottom: 5px; - width: 80%; -} - -.chat-body { - padding: 5px; - border-radius: 5px; -} - -li.float-left .chat-body { - background: $other_bg; -} - -li.float-right .chat-body { - background: $user_bg; -} - -li .chat-body p { - margin: 0; - color: #777777; -} - -.description { - color: #666666; - font-style: italic; - padding: 0 15px; -} - -.pointer { - cursor: pointer; -} - -.max250 { - max-width: 250px; -} - -/deep/ .float-right div[class^="clamp-"] -.content:after { - background: linear-gradient(to right, rgba(255, 255, 255, 0), $user_bg 70%) !important; -} - -/deep/ .float-left div[class^="clamp-"] -.content:after { - background: linear-gradient(to right, rgba(255, 255, 255, 0), $other_bg 70%) !important; -} - -.truncatable { - clear: both; -} diff --git a/src/app/shared/message-board/message/message.component.ts b/src/app/shared/message-board/message/message.component.ts deleted file mode 100644 index 0119b662ab..0000000000 --- a/src/app/shared/message-board/message/message.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; - -import { Observable, of as observableOf } from 'rxjs'; -import { first, flatMap } from 'rxjs/operators'; -import { TranslateService } from '@ngx-translate/core'; - -import { Bitstream } from '../../../core/shared/bitstream.model'; -import { MessageService } from '../../../core/message/message.service'; -import { isNull } from '../../empty.util'; - -@Component({ - selector: 'ds-message', - styleUrls: ['./message.component.scss'], - templateUrl: './message.component.html' -}) - -export class MessageComponent implements OnInit { - @Input() m: Bitstream; - @Input() isLast: boolean; - @Input() isSubmitter: boolean; - - @Output() emitUnread = new EventEmitter(); - @Output() emitRead = new EventEmitter(); - - public showUnread: boolean; - public showRead: boolean; - public showMessage = false; - - private _messageContent: Observable = null; - private loadingDescription = false; - - constructor(private cdr: ChangeDetectorRef, - private msgService: MessageService, - private translate: TranslateService) { - } - - ngOnInit() { - const type = this.m.firstMetadataValue('dc.type'); - - if (this.isLast) { - if ((this.isSubmitter && type === 'outbound') - || (!this.isSubmitter && type === 'inbound')) { - this.showUnread = true; - this.showRead = false; - } - } else { - this.showUnread = false; - this.showRead = false; - } - } - - toggleDescription() { - this.showMessage = !this.showMessage; - this.cdr.detectChanges(); - } - - get messageContent(): Observable { - if (isNull(this._messageContent) && !this.loadingDescription) { - this.loadingDescription = true; - this._messageContent = this.msgService.getMessageContent(this.m.content).pipe( - first(), - flatMap((res) => { - this._messageContent = res.payload ? observableOf(res.payload) : this.translate.get('mydspace.messages.no-content'); - this.loadingDescription = false; - return this._messageContent; - })); - } - return this._messageContent; - } - - markAsRead() { - this.emitRead.emit(true); - this.showUnread = true; - this.showRead = false; - } - - markAsUnread() { - this.emitUnread.emit(true); - this.showUnread = false; - this.showRead = true; - } - -} diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html index 6ebec7d1ae..4b9b93e7e3 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html @@ -18,9 +18,3 @@ - - - diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html index 7ab3c12ea4..6f4ffffad3 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.html @@ -6,10 +6,3 @@ {{'submission.workflow.tasks.generic.processing' | translate}} {{'submission.workflow.tasks.pool.claim' | translate}} - - - - diff --git a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.html b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.html index b19299e164..e69de29bb2 100644 --- a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.html +++ b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.html @@ -1,5 +0,0 @@ - - diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.html b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.html index 02c3384fcd..6c3a047f73 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.html +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.html @@ -13,12 +13,6 @@ {{'submission.workflow.generic.delete' | translate}} - - -