diff --git a/src/app/+login-page/login-page.component.ts b/src/app/+login-page/login-page.component.ts index 0c6f0a62bc..1f1cf7cf04 100644 --- a/src/app/+login-page/login-page.component.ts +++ b/src/app/+login-page/login-page.component.ts @@ -1,5 +1,8 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs'; +import { filter, take } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '../app.reducer'; @@ -9,11 +12,8 @@ import { AuthenticationSuccessAction, ResetAuthenticationMessagesAction } from '../core/auth/auth.actions'; -import { Subscription } from 'rxjs/Subscription'; import { hasValue, isNotEmpty } from '../shared/empty.util'; -import { ActivatedRoute } from '@angular/router'; import { AuthTokenInfo } from '../core/auth/models/auth-token-info.model'; -import { Observable } from 'rxjs/Observable'; import { isAuthenticated } from '../core/auth/selectors'; @Component({ @@ -30,26 +30,26 @@ export class LoginPageComponent implements OnDestroy, OnInit { ngOnInit() { const queryParamsObs = this.route.queryParams; const authenticated = this.store.select(isAuthenticated); - this.sub = Observable.combineLatest(queryParamsObs, authenticated) - .filter(([params, auth]) => isNotEmpty(params.token) || isNotEmpty(params.expired)) - .take(1) - .subscribe(([params, auth]) => { - const token = params.token; - let authToken: AuthTokenInfo; - if (!auth) { - if (isNotEmpty(token)) { - authToken = new AuthTokenInfo(token); - this.store.dispatch(new AuthenticatedAction(authToken)); - } else if (isNotEmpty(params.expired)) { - this.store.dispatch(new AddAuthenticationMessageAction('auth.messages.expired')); - } - } else { - if (isNotEmpty(token)) { - authToken = new AuthTokenInfo(token); - this.store.dispatch(new AuthenticationSuccessAction(authToken)); - } + this.sub = observableCombineLatest(queryParamsObs, authenticated).pipe( + filter(([params, auth]) => isNotEmpty(params.token) || isNotEmpty(params.expired)), + take(1) + ).subscribe(([params, auth]) => { + const token = params.token; + let authToken: AuthTokenInfo; + if (!auth) { + if (isNotEmpty(token)) { + authToken = new AuthTokenInfo(token); + this.store.dispatch(new AuthenticatedAction(authToken)); + } else if (isNotEmpty(params.expired)) { + this.store.dispatch(new AddAuthenticationMessageAction('auth.messages.expired')); } - }) + } else { + if (isNotEmpty(token)) { + authToken = new AuthTokenInfo(token); + this.store.dispatch(new AuthenticationSuccessAction(authToken)); + } + } + }) } ngOnDestroy() { diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index a286a6a8e1..23daa69fd8 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -1,6 +1,7 @@ -import { distinctUntilChanged, filter, take, first, map } from 'rxjs/operators'; +import { distinctUntilChanged, filter, take, first, map, flatMap } from 'rxjs/operators'; import { of as observableOf, Observable } from 'rxjs'; import { Store } from '@ngrx/store'; + import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ResponseCacheService } from '../cache/response-cache.service'; @@ -60,7 +61,7 @@ export abstract class DataService let result: Observable; const args = []; - result = Observable.of(`${endpoint}/search/${searchByLink}`); + result = observableOf(`${endpoint}/search/${searchByLink}`); if (hasValue(options.searchParams)) { options.searchParams.forEach((param: SearchParam) => { @@ -86,7 +87,7 @@ export abstract class DataService } if (isNotEmpty(args)) { - return result.map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString()); + return result.pipe(map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString())); } else { return result; } @@ -131,11 +132,13 @@ export abstract class DataService protected searchBy(searchMethod: string, options: FindAllOptions = {}): Observable>> { - const hrefObs = this.halService.getEndpoint(this.linkPath).filter((href: string) => isNotEmpty(href)) - .flatMap((endpoint: string) => this.getSearchByHref(endpoint, searchMethod, options)); - hrefObs - .filter((href: string) => hasValue(href)) - .take(1) + const hrefObs = this.halService.getEndpoint(this.linkPath).pipe( + filter((href: string) => isNotEmpty(href)), + flatMap((endpoint: string) => this.getSearchByHref(endpoint, searchMethod, options))); + + hrefObs.pipe( + filter((href: string) => hasValue(href)), + take(1)) .subscribe((href: string) => { const request = new FindAllRequest(this.requestService.generateRequestId(), href, options); this.requestService.configure(request, true); diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index 9fbf4cab36..16a3a2ce51 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -1,14 +1,14 @@ import { Injectable } from '@angular/core'; import { remove } from 'lodash'; -import { Observable, merge as observableMerge } from 'rxjs'; -import { filter, first, map, mergeMap, partition, take } from 'rxjs/operators'; +import { merge as observableMerge, Observable } from 'rxjs'; +import { filter, map, mergeMap, take } from 'rxjs/operators'; import { MemoizedSelector, select, Store } from '@ngrx/store'; import { hasValue } from '../../shared/empty.util'; import { CacheableObject } from '../cache/object-cache.reducer'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { DSOSuccessResponse, RestResponse } from '../cache/response-cache.models'; +import { DSOSuccessResponse } from '../cache/response-cache.models'; import { ResponseCacheEntry } from '../cache/response-cache.reducer'; import { ResponseCacheService } from '../cache/response-cache.service'; import { coreSelector, CoreState } from '../core.reducers'; diff --git a/src/app/core/eperson/eperson.service.ts b/src/app/core/eperson/eperson.service.ts index c431af0692..2ad0686a22 100644 --- a/src/app/core/eperson/eperson.service.ts +++ b/src/app/core/eperson/eperson.service.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable'; +import { Observable } from 'rxjs'; import { RequestService } from '../data/request.service'; import { ResponseCacheService } from '../cache/response-cache.service'; import { EpersonRequest, FindAllOptions } from '../data/request.models'; diff --git a/src/app/core/eperson/group-eperson.service.ts b/src/app/core/eperson/group-eperson.service.ts index 2524ec83eb..a7f24c1ab8 100644 --- a/src/app/core/eperson/group-eperson.service.ts +++ b/src/app/core/eperson/group-eperson.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs/Observable'; +import { Observable } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; import { EpersonService } from './eperson.service'; diff --git a/src/app/core/integration/integration.service.ts b/src/app/core/integration/integration.service.ts index ada4925317..7b1e3cf203 100644 --- a/src/app/core/integration/integration.service.ts +++ b/src/app/core/integration/integration.service.ts @@ -2,7 +2,7 @@ import { Observable, of as observableOf, throwError as observableThrowError } fr import { distinctUntilChanged, filter, map, mergeMap, tap } from 'rxjs/operators'; import { RequestService } from '../data/request.service'; import { ResponseCacheService } from '../cache/response-cache.service'; -import { IntegrationSuccessResponse } from '../cache/response-cache.models'; +import { IntegrationSuccessResponse, RestResponse } from '../cache/response-cache.models'; import { GetRequest, IntegrationRequest } from '../data/request.models'; import { ResponseCacheEntry } from '../cache/response-cache.reducer'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; @@ -24,9 +24,8 @@ export abstract class IntegrationService { protected getData(request: GetRequest): Observable { return this.responseCache.get(request.href).pipe( map((entry: ResponseCacheEntry) => entry.response), - mergeMap((response) => { + mergeMap((response: IntegrationSuccessResponse) => { if (response.isSuccessful && isNotEmpty(response)) { - const dataResponse = response as IntegrationSuccessResponse; return observableOf(new IntegrationData( response.pageInfo, (response.dataDefinition) ? response.dataDefinition.page : [] diff --git a/src/app/core/json-patch/json-patch-operations.service.ts b/src/app/core/json-patch/json-patch-operations.service.ts index 8328a6d4a7..2fe9c8cea2 100644 --- a/src/app/core/json-patch/json-patch-operations.service.ts +++ b/src/app/core/json-patch/json-patch-operations.service.ts @@ -1,7 +1,15 @@ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; + +import { Observable, of as observableOf, throwError as observableThrowError, merge as observableMerge } from 'rxjs'; +import { distinctUntilChanged, filter, flatMap, map, mergeMap, partition, take, tap } from 'rxjs/operators'; + import { hasValue, isEmpty, isNotEmpty, isNotUndefined, isUndefined } from '../../shared/empty.util'; -import { ErrorResponse, PostPatchSuccessResponse, RestResponse } from '../cache/response-cache.models'; +import { + ConfigSuccessResponse, + ErrorResponse, + PostPatchSuccessResponse, + RestResponse +} from '../cache/response-cache.models'; import { ResponseCacheEntry } from '../cache/response-cache.reducer'; import { ResponseCacheService } from '../cache/response-cache.service'; import { PatchRequest, RestRequest, SubmissionPatchRequest } from '../data/request.models'; @@ -29,27 +37,27 @@ export class JsonPatchOperationsService { } protected submitData(request: RestRequest): Observable { - const [successResponse, errorResponse] = this.responseCache.get(request.href) - .map((entry: ResponseCacheEntry) => entry.response) - .partition((response: RestResponse) => response.isSuccessful); - return Observable.merge( - errorResponse.flatMap((response: ErrorResponse) => - Observable.throw(new Error(`Couldn't send data to server`))), - successResponse - .filter((response: PostPatchSuccessResponse) => isNotEmpty(response)) - .map((response: PostPatchSuccessResponse) => response.dataDefinition) - .distinctUntilChanged()); + const responses = this.responseCache.get(request.href).pipe(map((entry: ResponseCacheEntry) => entry.response)); + const errorResponses = responses.pipe( + filter((response) => !response.isSuccessful), + mergeMap(() => observableThrowError(new Error(`Couldn't send data to server`))) + ); + const successResponses = responses.pipe( + filter((response: PostPatchSuccessResponse) => isNotEmpty(response)), + map((response: PostPatchSuccessResponse) => response.dataDefinition) + ); + return observableMerge(errorResponses, successResponses); } protected submitJsonPatchOperations(hrefObs: Observable, resourceType: string, resourceId?: string) { let startTransactionTime = null; - const [patchRequestObs, emptyRequestObs] = hrefObs - .flatMap((endpointURL: string) => { - return this.store.select(jsonPatchOperationsByResourceType(resourceType)) - .take(1) - .filter((operationsList: JsonPatchOperationsResourceEntry) => isUndefined(operationsList) || !(operationsList.commitPending)) - .do(() => startTransactionTime = new Date().getTime()) - .map((operationsList: JsonPatchOperationsResourceEntry) => { + const [patchRequest$, emptyRequest$] = partition((request: PatchRequest) => isNotEmpty(request.body))(hrefObs.pipe( + flatMap((endpointURL: string) => { + return this.store.select(jsonPatchOperationsByResourceType(resourceType)).pipe( + take(1), + filter((operationsList: JsonPatchOperationsResourceEntry) => isUndefined(operationsList) || !(operationsList.commitPending)), + tap(() => startTransactionTime = new Date().getTime()), + map((operationsList: JsonPatchOperationsResourceEntry) => { const body: JsonPatchOperationModel[] = []; if (isNotEmpty(operationsList)) { if (isNotEmpty(resourceId)) { @@ -71,35 +79,34 @@ export class JsonPatchOperationsService { } } return new SubmissionPatchRequest(this.requestService.generateRequestId(), endpointURL, body); - }); - }) - .partition((request: PatchRequest) => isNotEmpty(request.body)); + })); + }))); - return Observable.merge( - emptyRequestObs - .filter((request: PatchRequest) => isEmpty(request.body)) - .do(() => startTransactionTime = null) - .map(() => null), - patchRequestObs - .filter((request: PatchRequest) => isNotEmpty(request.body)) - .do(() => this.store.dispatch(new StartTransactionPatchOperationsAction(resourceType, resourceId, startTransactionTime))) - .do((request: PatchRequest) => this.requestService.configure(request, true)) - .flatMap((request: PatchRequest) => { - const [successResponse, errorResponse] = this.responseCache.get(request.href) - .filter((entry: ResponseCacheEntry) => startTransactionTime < entry.timeAdded) - .take(1) - .map((entry: ResponseCacheEntry) => entry.response) - .partition((response: RestResponse) => response.isSuccessful); - return Observable.merge( - errorResponse - .do(() => this.store.dispatch(new RollbacktPatchOperationsAction(resourceType, resourceId))) - .flatMap((response: ErrorResponse) => Observable.of(new Error(`Couldn't patch operations`))), - successResponse - .filter((response: PostPatchSuccessResponse) => isNotEmpty(response)) - .do(() => this.store.dispatch(new CommitPatchOperationsAction(resourceType, resourceId))) - .map((response: PostPatchSuccessResponse) => response.dataDefinition) - .distinctUntilChanged()); - }) + return observableMerge( + emptyRequest$.pipe( + filter((request: PatchRequest) => isEmpty(request.body)), + tap(() => startTransactionTime = null), + map(() => null)), + patchRequest$.pipe( + filter((request: PatchRequest) => isNotEmpty(request.body)), + tap(() => this.store.dispatch(new StartTransactionPatchOperationsAction(resourceType, resourceId, startTransactionTime))), + tap((request: PatchRequest) => this.requestService.configure(request, true)), + flatMap((request: PatchRequest) => { + const [successResponse$, errorResponse$] = partition((response: RestResponse) => response.isSuccessful)(this.responseCache.get(request.href).pipe( + filter((entry: ResponseCacheEntry) => startTransactionTime < entry.timeAdded), + take(1), + map((entry: ResponseCacheEntry) => entry.response) + )); + return observableMerge( + errorResponse$.pipe( + tap(() => this.store.dispatch(new RollbacktPatchOperationsAction(resourceType, resourceId))), + flatMap((response: ErrorResponse) => observableOf(new Error(`Couldn't patch operations`)))), + successResponse$.pipe( + filter((response: PostPatchSuccessResponse) => isNotEmpty(response)), + tap(() => this.store.dispatch(new CommitPatchOperationsAction(resourceType, resourceId))), + map((response: PostPatchSuccessResponse) => response.dataDefinition), + distinctUntilChanged())); + })) ); } @@ -108,19 +115,19 @@ export class JsonPatchOperationsService { } public jsonPatchByResourceType(linkName: string, scopeId: string, resourceType: string,) { - const hrefObs = this.halService.getEndpoint(linkName) - .filter((href: string) => isNotEmpty(href)) - .distinctUntilChanged() - .map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId)); + const href$ = this.halService.getEndpoint(linkName).pipe( + filter((href: string) => isNotEmpty(href)), + distinctUntilChanged(), + map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId))); - return this.submitJsonPatchOperations(hrefObs, resourceType); + return this.submitJsonPatchOperations(href$, resourceType); } public jsonPatchByResourceID(linkName: string, scopeId: string, resourceType: string, resourceId: string) { - const hrefObs = this.halService.getEndpoint(linkName) - .filter((href: string) => isNotEmpty(href)) - .distinctUntilChanged() - .map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId)); + const hrefObs = this.halService.getEndpoint(linkName).pipe( + filter((href: string) => isNotEmpty(href)), + distinctUntilChanged(), + map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId))); return this.submitJsonPatchOperations(hrefObs, resourceType, resourceId); } diff --git a/yarn.lock b/yarn.lock index ffe2adb3c4..275f8efb74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -324,6 +324,11 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/file-saver@^1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-1.3.1.tgz#55d76b3c78b5fcc8a7588ead428dce0822464120" + integrity sha512-A+lNc0nnhtX3iTLEYd/DisKTZdNKTf1bN0aSfQD/fG8bQ6SfUe5u8Fm2ab8qQHaMY5GVZumAXLnYptwX+mmQgg== + "@types/fs-extra@4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.0.tgz#1dd742ad5c9bce308f7a52d02ebc01421bc9102f" @@ -3530,6 +3535,11 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +file-saver@^1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8" + integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg== + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"