From d154caf0393d922bfa53c2a91bea6c54ae2df4c6 Mon Sep 17 00:00:00 2001 From: lotte Date: Fri, 12 Oct 2018 15:06:10 +0200 Subject: [PATCH 1/8] 56119: fixed issue where facets could not be changed when you are logged on --- src/app/core/auth/auth.service.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 5f113b0262..1105abe3c7 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -340,14 +340,10 @@ export class AuthService { this.getRedirectUrl() .first() .subscribe((redirectUrl) => { + if (isNotEmpty(redirectUrl)) { this.clearRedirectUrl(); - - // override the route reuse strategy - this.router.routeReuseStrategy.shouldReuseRoute = () => { - return false; - }; - this.router.navigated = false; + this.router.onSameUrlNavigation = 'reload'; const url = decodeURIComponent(redirectUrl); this.router.navigateByUrl(url); /* TODO Reenable hard redirect when REST API can handle x-forwarded-for, see https://github.com/DSpace/DSpace/pull/2207 */ From 54dad64ab49f89dabe88404897cb8b5830351b08 Mon Sep 17 00:00:00 2001 From: lotte Date: Wed, 31 Oct 2018 15:28:50 +0100 Subject: [PATCH 2/8] resolved lint error --- src/app/shared/testing/query-params-directive-stub.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/testing/query-params-directive-stub.ts b/src/app/shared/testing/query-params-directive-stub.ts index c19c5e6a5f..34216bb53c 100644 --- a/src/app/shared/testing/query-params-directive-stub.ts +++ b/src/app/shared/testing/query-params-directive-stub.ts @@ -6,5 +6,5 @@ import { Directive, Input } from '@angular/core'; selector: '[queryParams]', }) export class QueryParamsDirectiveStub { - @Input('queryParams') queryParams: any; + @Input() queryParams: any; } From 8800f238eb7fb77757bcb2e27646d634d0316fb3 Mon Sep 17 00:00:00 2001 From: Antoine Snyers Date: Mon, 12 Nov 2018 10:23:28 +0100 Subject: [PATCH 3/8] Hide the wrapper component when there is no text content --- .../metadata-field-wrapper.component.html | 6 ++-- .../metadata-field-wrapper.component.spec.ts | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html index 084232edf4..bbe6d8d95b 100644 --- a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html +++ b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.html @@ -1,7 +1,5 @@ -
- -
{{ label }}
-
+
+
{{ label }}
diff --git a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts index 47e7d6c34e..6778204f43 100644 --- a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts +++ b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts @@ -7,7 +7,7 @@ import { MetadataFieldWrapperComponent } from './metadata-field-wrapper.componen @Component({ selector: 'ds-component-with-content', template: '\n' + - '
\n' + + '
\n' + '
\n' + '' }) @@ -30,25 +30,37 @@ describe('MetadataFieldWrapperComponent', () => { const wrapperSelector = '.simple-view-element'; const labelSelector = '.simple-view-element-header'; + const contentSelector = '.my-content'; it('should create', () => { expect(component).toBeDefined(); }); - it('should not show a label when there is no content', () => { + it('should not show the component when there is no content', () => { component.label = 'test label'; fixture.detectChanges(); - const debugLabel = fixture.debugElement.query(By.css(labelSelector)); - expect(debugLabel).toBeNull(); + const parentNative = fixture.nativeElement; + const nativeWrapper = parentNative.querySelector(wrapperSelector); + expect(nativeWrapper.classList.contains('d-none')).toBe(true); }); - it('should show a label when there is content', () => { + it('should not show the component when there is DOM content but no text', () => { const parentFixture = TestBed.createComponent(ContentComponent); parentFixture.detectChanges(); - const parentComponent = parentFixture.componentInstance; const parentNative = parentFixture.nativeElement; - const nativeLabel = parentNative.querySelector(labelSelector); - expect(nativeLabel.textContent).toContain('test label'); + const nativeWrapper = parentNative.querySelector(wrapperSelector); + expect(nativeWrapper.classList.contains('d-none')).toBe(true); + }); + + it('should show the component when there is text content', () => { + const parentFixture = TestBed.createComponent(ContentComponent); + parentFixture.detectChanges(); + const parentNative = parentFixture.nativeElement; + const nativeContent = parentNative.querySelector(contentSelector); + nativeContent.textContent = 'lorem ipsum'; + const nativeWrapper = parentNative.querySelector(wrapperSelector); + parentFixture.detectChanges(); + expect(nativeWrapper.classList.contains('d-none')).toBe(false); }); }); From 5cbe8ffb883d617251ebfb9e66115a355af165c5 Mon Sep 17 00:00:00 2001 From: lotte Date: Tue, 20 Nov 2018 15:53:40 +0100 Subject: [PATCH 4/8] resolved PR feedback --- package.json | 2 +- src/app/core/cache/response-cache.models.ts | 2 +- src/app/core/data/comcol-data.service.ts | 19 +------- src/app/shared/form/form.service.spec.ts | 54 +++++++++++---------- webpack.config.js | 2 +- 5 files changed, 33 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index 0c2c0a776c..91117723d1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "prebuild:prod": "yarn run prebuild", "build": "webpack --progress --mode development", "build:aot": "webpack --env.aot --env.server --mode development && webpack --env.aot --env.client --mode development", - "build:prod": "webpack --env.aot --env.server --env.production && webpack --env.aot --env.client --env.production", + "build:prod": "webpack --env.aot --env.server --mode production && webpack --env.aot --env.client --mode production", "postbuild:prod": "yarn run rollup", "rollup": "rollup -c rollup.config.js", "prestart": "yarn run build:prod", diff --git a/src/app/core/cache/response-cache.models.ts b/src/app/core/cache/response-cache.models.ts index 9566dcdc3c..9b1b5b89eb 100644 --- a/src/app/core/cache/response-cache.models.ts +++ b/src/app/core/cache/response-cache.models.ts @@ -140,7 +140,7 @@ export class ErrorResponse extends RestResponse { constructor(error: RequestError) { super(false, error.statusText); - // console.error(error); + console.error(error); this.errorMessage = error.message; } } diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index c589c5bdc8..95cfce6c70 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -37,25 +37,8 @@ export abstract class ComColDataService { const request = new FindByIDRequest(this.requestService.generateRequestId(), href, options.scopeID); this.requestService.configure(request); - }),); + })); - // return scopeCommunityHrefObs.pipe( - // mergeMap((href: string) => this.responseCache.get(href)), - // map((entry: ResponseCacheEntry) => entry.response), - // mergeMap((response) => { - // if (response.isSuccessful) { - // const community$: Observable = this.objectCache.getByUUID(scopeID); - // return community$.pipe( - // map((community) => community._links[this.linkPath]), - // filter((href) => isNotEmpty(href)), - // distinctUntilChanged() - // ); - // } else if (!response.isSuccessful) { - // return observableThrowError(new Error(`The Community with scope ${scopeID} couldn't be retrieved`)) - // } - // }), - // distinctUntilChanged() - // ); const responses = scopeCommunityHrefObs.pipe( mergeMap((href: string) => this.responseCache.get(href)), map((entry: ResponseCacheEntry) => entry.response)); diff --git a/src/app/shared/form/form.service.spec.ts b/src/app/shared/form/form.service.spec.ts index 1c13039e3c..80dfa01d1b 100644 --- a/src/app/shared/form/form.service.spec.ts +++ b/src/app/shared/form/form.service.spec.ts @@ -2,7 +2,11 @@ import { Store, StoreModule } from '@ngrx/store'; import { async, inject, TestBed } from '@angular/core/testing'; import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; -import { DynamicFormControlModel, DynamicInputModel } from '@ng-dynamic-forms/core'; +import { + DynamicFormControlModel, + DynamicFormGroupModel, + DynamicInputModel +} from '@ng-dynamic-forms/core'; import { FormService } from './form.service'; import { FormBuilderService } from './builder/form-builder.service'; @@ -37,30 +41,30 @@ describe('FormService test suite', () => { }), new DynamicInputModel({ id: 'date' }), new DynamicInputModel({ id: 'description' }), - // new DynamicFormGroupModel({ - // - // id: 'addressLocation', - // group: [ - // new DynamicInputModel({ - // - // id: 'zipCode', - // label: 'Zip Code', - // placeholder: 'ZIP' - // }), - // new DynamicInputModel({ - // - // id: 'state', - // label: 'State', - // placeholder: 'State' - // }), - // new DynamicInputModel({ - // - // id: 'city', - // label: 'City', - // placeholder: 'City' - // }) - // ] - // }), + new DynamicFormGroupModel({ + + id: 'addressLocation', + group: [ + new DynamicInputModel({ + + id: 'zipCode', + label: 'Zip Code', + placeholder: 'ZIP' + }), + new DynamicInputModel({ + + id: 'state', + label: 'State', + placeholder: 'State' + }), + new DynamicInputModel({ + + id: 'city', + label: 'City', + placeholder: 'City' + }) + ] + }), ]; let controls; diff --git a/webpack.config.js b/webpack.config.js index 8f02f3ce8a..6312cf3605 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -27,7 +27,7 @@ module.exports = function(env, options) { getAotPlugin('client', !!env.aot) ] }); - if (env.production) { + if (options.mode === 'production') { serverConfig = webpackMerge({}, serverConfig, prodPartial); clientConfig = webpackMerge({}, clientConfig, prodPartial); } From 86830263ddf60a20888299383f94e82883f43332 Mon Sep 17 00:00:00 2001 From: Antoine Snyers Date: Wed, 21 Nov 2018 15:02:42 +0100 Subject: [PATCH 5/8] Add an empty span in the test case --- .../metadata-field-wrapper.component.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts index 6778204f43..c997431711 100644 --- a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts +++ b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts @@ -8,12 +8,13 @@ import { MetadataFieldWrapperComponent } from './metadata-field-wrapper.componen selector: 'ds-component-with-content', template: '\n' + '
\n' + + ' \n' + '
\n' + '
' }) class ContentComponent {} -describe('MetadataFieldWrapperComponent', () => { +fdescribe('MetadataFieldWrapperComponent', () => { let component: MetadataFieldWrapperComponent; let fixture: ComponentFixture; From 9bf96d11df0453e9ef733ef1267eda7e843c48f3 Mon Sep 17 00:00:00 2001 From: Antoine Snyers Date: Wed, 21 Nov 2018 15:23:05 +0100 Subject: [PATCH 6/8] Remove fdescribe --- .../metadata-field-wrapper.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts index c997431711..cce54edf64 100644 --- a/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts +++ b/src/app/+item-page/field-components/metadata-field-wrapper/metadata-field-wrapper.component.spec.ts @@ -14,7 +14,7 @@ import { MetadataFieldWrapperComponent } from './metadata-field-wrapper.componen }) class ContentComponent {} -fdescribe('MetadataFieldWrapperComponent', () => { +describe('MetadataFieldWrapperComponent', () => { let component: MetadataFieldWrapperComponent; let fixture: ComponentFixture; From afa3a03d2c65bcc9aee5772d1cbbd3695174a92f Mon Sep 17 00:00:00 2001 From: lotte Date: Tue, 27 Nov 2018 11:45:35 +0100 Subject: [PATCH 7/8] fix for 401 requests --- src/app/core/auth/auth.service.spec.ts | 4 ++-- src/app/core/auth/auth.service.ts | 9 +++++++-- src/server.ts | 25 ++++++++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/app/core/auth/auth.service.spec.ts b/src/app/core/auth/auth.service.spec.ts index 187db93f3c..d39c0a4590 100644 --- a/src/app/core/auth/auth.service.spec.ts +++ b/src/app/core/auth/auth.service.spec.ts @@ -148,7 +148,7 @@ describe('AuthService test', () => { (state as any).core = Object.create({}); (state as any).core.auth = authenticatedState; }); - authService = new AuthService({}, window, authReqService, router, cookieService, store, rdbService); + authService = new AuthService({}, window, undefined, authReqService, router, cookieService, store, rdbService); })); it('should return true when user is logged in', () => { @@ -207,7 +207,7 @@ describe('AuthService test', () => { (state as any).core = Object.create({}); (state as any).core.auth = authenticatedState; }); - authService = new AuthService({}, window, authReqService, router, cookieService, store, rdbService); + authService = new AuthService({}, window, undefined, authReqService, router, cookieService, store, rdbService); storage = (authService as any).storage; spyOn(storage, 'get'); spyOn(storage, 'remove'); diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 5d8d13131a..67f533d4ad 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -9,10 +9,10 @@ import { take, withLatestFrom } from 'rxjs/operators'; -import { Inject, Injectable } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; import { PRIMARY_OUTLET, Router, UrlSegmentGroup, UrlTree } from '@angular/router'; import { HttpHeaders } from '@angular/common/http'; -import { REQUEST } from '@nguniversal/express-engine/tokens'; +import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens'; import { RouterReducerState } from '@ngrx/router-store'; import { select, Store } from '@ngrx/store'; @@ -59,6 +59,7 @@ export class AuthService { constructor(@Inject(REQUEST) protected req: any, @Inject(NativeWindowService) protected _window: NativeWindowRef, protected authRequestService: AuthRequestService, + @Optional() @Inject(RESPONSE) private response: any, protected router: Router, protected storage: CookieService, protected store: Store, @@ -345,6 +346,10 @@ export class AuthService { if (this._window.nativeWindow.location) { // Hard redirect to login page, so that all state is definitely lost this._window.nativeWindow.location.href = redirectUrl; + } else if (this.response) { + if (!this.response._headerSent) { + this.response.redirect(302, redirectUrl); + } } else { this.router.navigateByUrl(redirectUrl); } diff --git a/src/server.ts b/src/server.ts index 0e68e4f139..0526f196ba 100644 --- a/src/server.ts +++ b/src/server.ts @@ -17,6 +17,7 @@ import { ngExpressEngine } from '@nguniversal/express-engine'; import { ROUTES } from './routes'; import { ENV_CONFIG } from './config'; +import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens'; export function startServer(bootstrap: Type<{}> | NgModuleFactory<{}>) { const app = express(); @@ -31,9 +32,21 @@ export function startServer(bootstrap: Type<{}> | NgModuleFactory<{}>) { app.use(cookieParser()); app.use(bodyParser.json()); - app.engine('html', ngExpressEngine({ - bootstrap: bootstrap - })); + app.engine('html', (_, options, callback) => + ngExpressEngine({ + bootstrap: bootstrap, + providers: [ + { + provide: REQUEST, + useValue: options.req, + }, + { + provide: RESPONSE, + useValue: options.req.res, + }, + ], + })(_, options, callback) + ); app.set('view engine', 'html'); app.set('views', 'src'); @@ -53,8 +66,10 @@ export function startServer(bootstrap: Type<{}> | NgModuleFactory<{}>) { function ngApp(req, res) { function onHandleError(parentZoneDelegate, currentZone, targetZone, error) { - console.warn('Error in SSR, serving for direct CSR'); - res.sendFile('index.csr.html', { root: './src' }); + if (!res._headerSent) { + console.warn('Error in SSR, serving for direct CSR'); + res.sendFile('index.csr.html', { root: './src' }); + } } if (ENV_CONFIG.universal.preboot) { From 9911578bcc760463df17a71869f5f2064000ab9d Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Wed, 19 Dec 2018 14:53:11 +0100 Subject: [PATCH 8/8] remove all instances of first as it can cause an error if it's never triggered --- .../search-facet-filter.component.ts | 8 ++++---- .../search-filter/search-filter.component.ts | 4 ++-- src/app/app.component.ts | 2 +- src/app/core/auth/auth.effects.ts | 4 ++-- src/app/core/auth/auth.service.ts | 4 ++-- src/app/core/auth/server-auth.service.ts | 4 ++-- .../cache/builders/remote-data-build.service.ts | 12 ++++++++++-- src/app/core/cache/object-cache.service.ts | 6 +++--- src/app/core/cache/server-sync-buffer.effects.ts | 6 +++--- src/app/core/data/data.service.ts | 4 ++-- src/app/core/metadata/metadata.service.ts | 14 +++++++++++--- src/app/core/shared/operators.ts | 4 ++-- 12 files changed, 44 insertions(+), 28 deletions(-) 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 4a171a3f3a..faaf3b9fb5 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, first, map } from 'rxjs/operators'; +import { switchMap, distinctUntilChanged, first, map, take } 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'; @@ -126,7 +126,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { this.animationState = 'ready'; this.filterValues$.next(rd); })); - this.subs.push(newValues$.pipe(first()).subscribe((rd) => { + this.subs.push(newValues$.pipe(take(1)).subscribe((rd) => { this.isLastPage$.next(hasNoValue(rd.payload.next)) })); })); @@ -189,7 +189,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * @param data The string from the input field */ onSubmit(data: any) { - this.selectedValues.pipe(first()).subscribe((selectedValues) => { + this.selectedValues.pipe(take(1)).subscribe((selectedValues) => { if (isNotEmpty(data)) { this.router.navigate([this.getSearchLink()], { queryParams: @@ -258,7 +258,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { */ findSuggestions(data): void { if (isNotEmpty(data)) { - this.searchConfigService.searchOptions.pipe(first()).subscribe( + this.searchConfigService.searchOptions.pipe(take(1)).subscribe( (options) => { this.filterSearchResults = this.searchService.getFacetValuesFor(this.filterConfig, 1, options, data.toLowerCase()) .pipe( 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 87f8edc1ea..ec239e3628 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,5 +1,5 @@ -import {first} from 'rxjs/operators'; +import { first, take } from 'rxjs/operators'; import { Component, Input, OnInit } from '@angular/core'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { SearchFilterService } from './search-filter.service'; @@ -37,7 +37,7 @@ export class SearchFilterComponent implements OnInit { * Else, the filter should initially be collapsed */ ngOnInit() { - this.getSelectedValues().pipe(first()).subscribe((isActive) => { + this.getSelectedValues().pipe(take(1)).subscribe((isActive) => { if (this.filter.isOpenByDefault || isNotEmpty(isActive)) { this.initialExpand(); } else { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7d4bfe4f33..32ba6e752f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -64,7 +64,7 @@ export class AppComponent implements OnInit, AfterViewInit { // Whether is not authenticathed try to retrieve a possible stored auth token this.store.pipe(select(isAuthenticated), - first(), + take(1), filter((authenticated) => !authenticated) ).subscribe((authenticated) => this.authService.checkAuthenticationToken()); diff --git a/src/app/core/auth/auth.effects.ts b/src/app/core/auth/auth.effects.ts index c57fa3f70e..56a5411ef2 100644 --- a/src/app/core/auth/auth.effects.ts +++ b/src/app/core/auth/auth.effects.ts @@ -47,7 +47,7 @@ export class AuthEffects { ofType(AuthActionTypes.AUTHENTICATE), switchMap((action: AuthenticateAction) => { return this.authService.authenticate(action.payload.email, action.payload.password).pipe( - first(), + take(1), map((response: AuthStatus) => new AuthenticationSuccessAction(response.token)), catchError((error) => observableOf(new AuthenticationErrorAction(error))) ); @@ -127,7 +127,7 @@ export class AuthEffects { switchMap(() => { return this.store.pipe( select(isAuthenticated), - first(), + take(1), filter((authenticated) => !authenticated), tap(() => this.authService.removeToken()), tap(() => this.authService.resetAuthenticationError()) diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 67f533d4ad..66fe65a22e 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -277,7 +277,7 @@ export class AuthService { public isTokenExpiring(): Observable { return this.store.pipe( select(isTokenRefreshing), - first(), + take(1), map((isRefreshing: boolean) => { if (this.isTokenExpired() || isRefreshing) { return false; @@ -360,7 +360,7 @@ export class AuthService { */ public redirectToPreviousUrl() { this.getRedirectUrl().pipe( - first()) + take(1)) .subscribe((redirectUrl) => { if (isNotEmpty(redirectUrl)) { diff --git a/src/app/core/auth/server-auth.service.ts b/src/app/core/auth/server-auth.service.ts index c83410f6e3..903926fbcf 100644 --- a/src/app/core/auth/server-auth.service.ts +++ b/src/app/core/auth/server-auth.service.ts @@ -1,4 +1,4 @@ -import { first, map, switchMap } from 'rxjs/operators'; +import { first, map, switchMap, take } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @@ -62,7 +62,7 @@ export class ServerAuthService extends AuthService { */ public redirectToPreviousUrl() { this.getRedirectUrl().pipe( - first()) + take(1)) .subscribe((redirectUrl) => { if (isNotEmpty(redirectUrl)) { // override the route reuse strategy diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index 52ec4382ae..1dc255f26e 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -5,7 +5,15 @@ import { race as observableRace } from 'rxjs'; import { Injectable } from '@angular/core'; -import { distinctUntilChanged, first, flatMap, map, startWith, switchMap } from 'rxjs/operators'; +import { + distinctUntilChanged, + first, + flatMap, + map, + startWith, + switchMap, + take +} from 'rxjs/operators'; import { hasValue, hasValueOperator, isEmpty, isNotEmpty } from '../../../shared/empty.util'; import { PaginatedList } from '../../data/paginated-list'; import { RemoteData } from '../../data/remote-data'; @@ -44,7 +52,7 @@ export class RemoteDataBuildService { href$.pipe(getRequestFromRequestHref(this.requestService)), requestUUID$.pipe(getRequestFromRequestUUID(this.requestService)), ).pipe( - first() + take(1) ); // always use self link if that is cached, only if it isn't, get it via the response. diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index 44297d6f61..40f41be14d 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -1,6 +1,6 @@ import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; -import { distinctUntilChanged, filter, first, map, mergeMap, } from 'rxjs/operators'; +import { distinctUntilChanged, filter, first, map, mergeMap, take, } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { MemoizedSelector, select, Store } from '@ngrx/store'; import { IndexName } from '../index/index.reducer'; @@ -165,7 +165,7 @@ export class ObjectCacheService { this.store.pipe( select(selfLinkFromUuidSelector(uuid)), - first() + take(1) ).subscribe((selfLink: string) => result = this.hasBySelfLink(selfLink)); return result; @@ -184,7 +184,7 @@ export class ObjectCacheService { let result = false; this.store.pipe(select(entryFromSelfLinkSelector(selfLink)), - first() + take(1) ).subscribe((entry: ObjectCacheEntry) => result = this.isValid(entry)); return result; diff --git a/src/app/core/cache/server-sync-buffer.effects.ts b/src/app/core/cache/server-sync-buffer.effects.ts index 5a0a5527d1..d0a194705b 100644 --- a/src/app/core/cache/server-sync-buffer.effects.ts +++ b/src/app/core/cache/server-sync-buffer.effects.ts @@ -1,4 +1,4 @@ -import { delay, exhaustMap, first, map, switchMap, tap } from 'rxjs/operators'; +import { delay, exhaustMap, first, map, switchMap, take, tap } from 'rxjs/operators'; import { Inject, Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { @@ -56,7 +56,7 @@ export class ServerSyncBufferEffects { switchMap((action: CommitSSBAction) => { return this.store.pipe( select(serverSyncBufferSelector()), - first(), /* necessary, otherwise delay will not have any effect after the first run */ + take(1), /* necessary, otherwise delay will not have any effect after the first run */ switchMap((bufferState: ServerSyncBufferState) => { const actions: Array> = bufferState.buffer .filter((entry: ServerSyncBufferEntry) => { @@ -95,7 +95,7 @@ export class ServerSyncBufferEffects { * @returns {Observable} ApplyPatchObjectCacheAction to be dispatched */ private applyPatch(href: string): Observable { - const patchObject = this.objectCache.getBySelfLink(href).pipe(first()); + const patchObject = this.objectCache.getBySelfLink(href).pipe(take(1)); return patchObject.pipe( map((object) => { diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 6a7916854b..6afc84df5a 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -1,4 +1,4 @@ -import { delay, distinctUntilChanged, filter, first, map, take, tap } from 'rxjs/operators'; +import { delay, distinctUntilChanged, filter, find, first, map, take, tap } from 'rxjs/operators'; import { Observable } from 'rxjs'; import { Store } from '@ngrx/store'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; @@ -74,7 +74,7 @@ export abstract class DataService map((endpoint: string) => this.getFindByIDHref(endpoint, id))); hrefObs.pipe( - first((href: string) => hasValue(href))) + find((href: string) => hasValue(href))) .subscribe((href: string) => { const request = new FindByIDRequest(this.requestService.generateRequestId(), href, id); this.requestService.configure(request); diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts index 8bec058d08..e73613fddb 100644 --- a/src/app/core/metadata/metadata.service.ts +++ b/src/app/core/metadata/metadata.service.ts @@ -1,4 +1,12 @@ -import { catchError, distinctUntilKeyChanged, filter, first, map, take } from 'rxjs/operators'; +import { + catchError, + distinctUntilKeyChanged, + filter, + find, + first, + map, + take +} from 'rxjs/operators'; import { Inject, Injectable } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; @@ -261,7 +269,7 @@ export class MetadataService { const item = this.currentObject.value as Item; item.getFiles() .pipe( - first((files) => isNotEmpty(files)), + find((files) => isNotEmpty(files)), catchError((error) => { console.debug(error.message); return [] @@ -269,7 +277,7 @@ export class MetadataService { .subscribe((bitstreams: Bitstream[]) => { for (const bitstream of bitstreams) { bitstream.format.pipe( - first(), + take(1), catchError((error: Error) => { console.debug(error.message); return [] diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 4e6a95ff11..388c4289e2 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -1,5 +1,5 @@ import { Observable } from 'rxjs'; -import { filter, first, flatMap, map, tap } from 'rxjs/operators'; +import { filter, find, first, flatMap, map, tap } from 'rxjs/operators'; import { hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util'; import { DSOSuccessResponse, RestResponse } from '../cache/response.models'; import { RemoteData } from '../data/remote-data'; @@ -60,7 +60,7 @@ export const getRemoteDataPayload = () => export const getSucceededRemoteData = () => (source: Observable>): Observable> => - source.pipe(first((rd: RemoteData) => rd.hasSucceeded)); + source.pipe(find((rd: RemoteData) => rd.hasSucceeded)); export const toDSpaceObjectListRD = () => (source: Observable>>>): Observable>> =>