-
+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 2141b06a77..4e029af8ca 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -19,7 +19,7 @@ import variables from '../styles/_exposed_variables.scss'; import { CSSVariableService } from './shared/sass-helper/sass-helper.service'; import { MenuService } from './shared/menu/menu.service'; import { MenuID } from './shared/menu/initial-menus-state'; -import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs'; +import { BehaviorSubject, combineLatest as combineLatestObservable, Observable, of } from 'rxjs'; import { slideSidebarPadding } from './shared/animations/slide'; import { HostWindowService } from './shared/host-window.service'; import { Theme } from '../config/theme.inferface'; @@ -38,7 +38,7 @@ export const LANG_COOKIE = 'language_cookie'; animations: [slideSidebarPadding] }) export class AppComponent implements OnInit, AfterViewInit { - isLoading = true; + isLoading$: BehaviorSubject = new BehaviorSubject(true); sidebarVisible: Observable; slideSidebarOver: Observable; collapsedSidebarWidth: Observable; @@ -131,12 +131,12 @@ export class AppComponent implements OnInit, AfterViewInit { delay(0) ).subscribe((event) => { if (event instanceof NavigationStart) { - this.isLoading = true; + this.isLoading$.next(true); } else if ( event instanceof NavigationEnd || event instanceof NavigationCancel ) { - this.isLoading = false; + this.isLoading$.next(false); } }); } diff --git a/src/app/app.metareducers.ts b/src/app/app.metareducers.ts index 4d94c899d7..131d240b79 100644 --- a/src/app/app.metareducers.ts +++ b/src/app/app.metareducers.ts @@ -1,4 +1,3 @@ -import { isNotEmpty } from './shared/empty.util'; import { StoreActionTypes } from './store.actions'; // fallback ngrx debugger diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4b803608f3..7bc4ee1c5a 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -6,14 +6,12 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { EffectsModule } from '@ngrx/effects'; import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store'; -import { META_REDUCERS, MetaReducer, StoreModule } from '@ngrx/store'; +import { META_REDUCERS, MetaReducer, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { TranslateModule } from '@ngx-translate/core'; import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to'; -import { storeFreeze } from 'ngrx-store-freeze'; - import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../config'; import { AdminSidebarSectionComponent } from './+admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component'; import { AdminSidebarComponent } from './+admin/admin-sidebar/admin-sidebar.component'; @@ -23,7 +21,7 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { appEffects } from './app.effects'; -import { appMetaReducers, debugMetaReducers } from './app.metareducers'; +import { appMetaReducers, debugMetaReducers, universalMetaReducer } from './app.metareducers'; import { appReducers, AppState } from './app.reducer'; import { CoreModule } from './core/core.module'; @@ -51,8 +49,7 @@ export function getBase() { } export function getMetaReducers(config: GlobalConfig): Array> { - const metaReducers: Array> = config.production ? appMetaReducers : [...appMetaReducers, storeFreeze]; - return config.debug ? [...metaReducers, ...debugMetaReducers] : metaReducers; + return config.debug ? [...appMetaReducers, ...debugMetaReducers] : appMetaReducers; } const IMPORTS = [ @@ -63,11 +60,11 @@ const IMPORTS = [ AppRoutingModule, CoreModule.forRoot(), ScrollToModule.forRoot(), - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot(), EffectsModule.forRoot(appEffects), StoreModule.forRoot(appReducers), - StoreRouterConnectingModule, + StoreRouterConnectingModule.forRoot(), ]; const ENTITY_IMPORTS = [ @@ -92,7 +89,7 @@ const PROVIDERS = [ useFactory: (getBase) }, { - provide: META_REDUCERS, + provide: USER_PROVIDED_META_REDUCERS, useFactory: getMetaReducers, deps: [GLOBAL_CONFIG] }, diff --git a/src/app/community-list-page/community-list-service.spec.ts b/src/app/community-list-page/community-list-service.spec.ts index a150277d20..c3cfef35a0 100644 --- a/src/app/community-list-page/community-list-service.spec.ts +++ b/src/app/community-list-page/community-list-service.spec.ts @@ -190,8 +190,6 @@ describe('CommunityListService', () => { service = new CommunityListService(communityDataServiceStub, collectionDataServiceStub, store); })); - afterAll(() => service = new CommunityListService(communityDataServiceStub, collectionDataServiceStub, store)); - it('should create', inject([CommunityListService], (serviceIn: CommunityListService) => { expect(serviceIn).toBeTruthy(); })); diff --git a/src/app/core/auth/auth-request.service.ts b/src/app/core/auth/auth-request.service.ts index e5c9210769..28854f3916 100644 --- a/src/app/core/auth/auth-request.service.ts +++ b/src/app/core/auth/auth-request.service.ts @@ -1,6 +1,7 @@ import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs'; import { distinctUntilChanged, filter, map, mergeMap, tap } from 'rxjs/operators'; import { Inject, Injectable } from '@angular/core'; +import { EPersonDataService } from '../eperson/eperson-data.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { RequestService } from '../data/request.service'; import { GLOBAL_CONFIG } from '../../../config'; diff --git a/src/app/core/auth/auth-response-parsing.service.spec.ts b/src/app/core/auth/auth-response-parsing.service.spec.ts index 112d60b8d2..3b18d925bf 100644 --- a/src/app/core/auth/auth-response-parsing.service.spec.ts +++ b/src/app/core/auth/auth-response-parsing.service.spec.ts @@ -3,15 +3,16 @@ import { async, TestBed } from '@angular/core/testing'; import { Store, StoreModule } from '@ngrx/store'; import { GlobalConfig } from '../../../config/global-config.interface'; -import { AuthStatusResponse } from '../cache/response.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { AuthStatus } from './models/auth-status.model'; -import { AuthResponseParsingService } from './auth-response-parsing.service'; -import { AuthGetRequest, AuthPostRequest } from '../data/request.models'; import { MockStore } from '../../shared/testing/mock-store'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { AuthStatusResponse } from '../cache/response.models'; +import { AuthGetRequest, AuthPostRequest } from '../data/request.models'; +import { AuthResponseParsingService } from './auth-response-parsing.service'; +import { AuthStatus } from './models/auth-status.model'; describe('AuthResponseParsingService', () => { let service: AuthResponseParsingService; + let linkServiceStub: any; const EnvConfig: GlobalConfig = { cache: { msToLive: 1000 } } as any; let store: any; @@ -30,7 +31,10 @@ describe('AuthResponseParsingService', () => { beforeEach(() => { store = TestBed.get(Store); - objectCacheService = new ObjectCacheService(store as any); + linkServiceStub = jasmine.createSpyObj({ + removeResolvedLinks: {} + }); + objectCacheService = new ObjectCacheService(store as any, linkServiceStub); service = new AuthResponseParsingService(EnvConfig, objectCacheService); }); @@ -141,6 +145,7 @@ describe('AuthResponseParsingService', () => { it('should return a AuthStatusResponse if data contains a valid endpoint response', () => { const response = service.parse(validRequest2, validResponse2); expect(response.constructor).toBe(AuthStatusResponse); + expect(linkServiceStub.removeResolvedLinks).toHaveBeenCalled(); }); it('should return a AuthStatusResponse if data contains an empty 404 endpoint response', () => { diff --git a/src/app/core/auth/auth-response-parsing.service.ts b/src/app/core/auth/auth-response-parsing.service.ts index 8137734c49..9ef523ca14 100644 --- a/src/app/core/auth/auth-response-parsing.service.ts +++ b/src/app/core/auth/auth-response-parsing.service.ts @@ -10,8 +10,6 @@ import { ObjectCacheService } from '../cache/object-cache.service'; import { ResponseParsingService } from '../data/parsing.service'; import { RestRequest } from '../data/request.models'; import { AuthStatus } from './models/auth-status.model'; -import { NormalizedAuthStatus } from './models/normalized-auth-status.model'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; @Injectable() export class AuthResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { @@ -25,10 +23,10 @@ export class AuthResponseParsingService extends BaseResponseParsingService imple parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === 200)) { - const response = this.process>(data.payload, request); + const response = this.process(data.payload, request); return new AuthStatusResponse(response, data.statusCode, data.statusText); } else { - return new AuthStatusResponse(data.payload as NormalizedAuthStatus, data.statusCode, data.statusText); + return new AuthStatusResponse(data.payload as AuthStatus, data.statusCode, data.statusText); } } } diff --git a/src/app/core/auth/auth.service.spec.ts b/src/app/core/auth/auth.service.spec.ts index 1ead3e4f7e..1a34d02e9c 100644 --- a/src/app/core/auth/auth.service.spec.ts +++ b/src/app/core/auth/auth.service.spec.ts @@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { Store, StoreModule } from '@ngrx/store'; import { REQUEST } from '@nguniversal/express-engine/tokens'; import { of as observableOf } from 'rxjs'; +import { LinkService } from '../cache/builders/link.service'; import { authReducer, AuthState } from './auth.reducer'; import { NativeWindowRef, NativeWindowService } from '../services/window.service'; @@ -40,7 +41,7 @@ describe('AuthService test', () => { let storage: CookieService; let token: AuthTokenInfo; let authenticatedState; - let rdbService; + let linkService; function init() { mockStore = jasmine.createSpyObj('store', { @@ -60,8 +61,10 @@ describe('AuthService test', () => { }; authRequest = new AuthRequestServiceStub(); routeStub = new ActivatedRouteStub(); - rdbService = getMockRemoteDataBuildService(); - spyOn(rdbService, 'build').and.returnValue({authenticated: true, eperson: observableOf({payload: {}})}); + linkService = { + resolveLinks: {} + }; + spyOn(linkService, 'resolveLinks').and.returnValue({authenticated: true, eperson: observableOf({payload: {}})}); } @@ -82,7 +85,7 @@ describe('AuthService test', () => { { provide: RouteService, useValue: routeServiceStub }, { provide: ActivatedRoute, useValue: routeStub }, { provide: Store, useValue: mockStore }, - { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: LinkService, useValue: linkService }, CookieService, AuthService ], @@ -165,7 +168,7 @@ describe('AuthService test', () => { { provide: REQUEST, useValue: {} }, { provide: Router, useValue: routerStub }, { provide: RouteService, useValue: routeServiceStub }, - { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: RemoteDataBuildService, useValue: linkService }, CookieService, AuthService ] @@ -178,7 +181,7 @@ describe('AuthService test', () => { (state as any).core = Object.create({}); (state as any).core.auth = authenticatedState; }); - authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, rdbService); + authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, linkService); })); it('should return true when user is logged in', () => { @@ -217,7 +220,7 @@ describe('AuthService test', () => { { provide: REQUEST, useValue: {} }, { provide: Router, useValue: routerStub }, { provide: RouteService, useValue: routeServiceStub }, - { provide: RemoteDataBuildService, useValue: rdbService }, + { provide: RemoteDataBuildService, useValue: linkService }, ClientCookieService, CookieService, AuthService @@ -240,7 +243,7 @@ describe('AuthService test', () => { (state as any).core = Object.create({}); (state as any).core.auth = authenticatedState; }); - authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, rdbService); + authService = new AuthService({}, window, undefined, authReqService, router, routeService, cookieService, store, linkService); storage = (authService as any).storage; routeServiceMock = TestBed.get(RouteService); routerStub = TestBed.get(Router); diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index cb0ba6a595..eed641cbf3 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -8,6 +8,8 @@ import { distinctUntilChanged, filter, map, startWith, switchMap, take, withLate import { RouterReducerState } from '@ngrx/router-store'; import { select, Store } from '@ngrx/store'; import { CookieAttributes } from 'js-cookie'; +import { followLink } from '../../shared/utils/follow-link-config.model'; +import { LinkService } from '../cache/builders/link.service'; import { EPerson } from '../eperson/models/eperson.model'; import { AuthRequestService } from './auth-request.service'; @@ -55,7 +57,7 @@ export class AuthService { protected routeService: RouteService, protected storage: CookieService, protected store: Store, - protected rdbService: RemoteDataBuildService + protected linkService: LinkService ) { this.store.pipe( select(isAuthenticated), @@ -154,7 +156,7 @@ export class AuthService { headers = headers.append('Authorization', `Bearer ${token.accessToken}`); options.headers = headers; return this.authRequestService.getRequest('status', options).pipe( - map((status) => this.rdbService.build(status)), + map((status) => this.linkService.resolveLinks(status, followLink('eperson'))), switchMap((status: AuthStatus) => { if (status.authenticated) { return status.eperson.pipe(map((eperson) => eperson.payload)); diff --git a/src/app/core/auth/models/auth-status.model.ts b/src/app/core/auth/models/auth-status.model.ts index 9e5b27be95..9daeef34f8 100644 --- a/src/app/core/auth/models/auth-status.model.ts +++ b/src/app/core/auth/models/auth-status.model.ts @@ -1,57 +1,86 @@ -import { AuthError } from './auth-error.model'; -import { AuthTokenInfo } from './auth-token-info.model'; -import { EPerson } from '../../eperson/models/eperson.model'; -import { RemoteData } from '../../data/remote-data'; +import { autoserialize, deserialize, deserializeAs } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; import { CacheableObject } from '../../cache/object-cache.reducer'; +import { RemoteData } from '../../data/remote-data'; +import { EPerson } from '../../eperson/models/eperson.model'; +import { EPERSON } from '../../eperson/models/eperson.resource-type'; +import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { AuthError } from './auth-error.model'; +import { AUTH_STATUS } from './auth-status.resource-type'; +import { AuthTokenInfo } from './auth-token-info.model'; import { AuthMethod } from './auth.method'; /** * Object that represents the authenticated status of a user */ +@typedObject export class AuthStatus implements CacheableObject { - static type = new ResourceType('status'); + static type = AUTH_STATUS; /** * The unique identifier of this auth status */ + @autoserialize id: string; /** - * The unique uuid of this auth status + * The type for this AuthStatus */ + @excludeFromEquals + @autoserialize + type: ResourceType; + + /** + * The UUID of this auth status + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. + */ + @deserializeAs(new IDToUUIDSerializer('auth-status'), 'id') uuid: string; /** * True if REST API is up and running, should never return false */ + @autoserialize okay: boolean; /** * If the auth status represents an authenticated state */ + @autoserialize authenticated: boolean; /** - * Authentication error if there was one for this status + * The {@link HALLink}s for this AuthStatus */ - error?: AuthError; + @deserialize + _links: { + self: HALLink; + eperson: HALLink; + }; /** - * The eperson of this auth status + * The EPerson of this auth status + * Will be undefined unless the eperson {@link HALLink} has been resolved. */ - eperson: Observable>; + @link(EPERSON) + eperson?: Observable>; /** * True if the token is valid, false if there was no token or the token wasn't valid */ + @autoserialize token?: AuthTokenInfo; /** - * The self link of this auth status' REST object + * Authentication error if there was one for this status */ - self: string; + // TODO should be refactored to use the RemoteData error + error?: AuthError; /** * All authentication methods enabled at the backend diff --git a/src/app/core/auth/models/auth-status.resource-type.ts b/src/app/core/auth/models/auth-status.resource-type.ts new file mode 100644 index 0000000000..2b7c7252fc --- /dev/null +++ b/src/app/core/auth/models/auth-status.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for AuthStatus + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const AUTH_STATUS = new ResourceType('status'); diff --git a/src/app/core/auth/models/normalized-auth-status.model.ts b/src/app/core/auth/models/normalized-auth-status.model.ts index 6af98bb22f..e69de29bb2 100644 --- a/src/app/core/auth/models/normalized-auth-status.model.ts +++ b/src/app/core/auth/models/normalized-auth-status.model.ts @@ -1,48 +0,0 @@ -import { AuthStatus } from './auth-status.model'; -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { NormalizedObject } from '../../cache/models/normalized-object.model'; -import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; -import { EPerson } from '../../eperson/models/eperson.model'; -import { AuthMethod } from './auth.method'; - -@mapsTo(AuthStatus) -@inheritSerialization(NormalizedObject) -export class NormalizedAuthStatus extends NormalizedObject { - /** - * The unique identifier of this auth status - */ - @autoserialize - id: string; - - /** - * The unique generated uuid of this auth status - */ - @autoserializeAs(new IDToUUIDSerializer('auth-status'), 'id') - uuid: string; - - /** - * True if REST API is up and running, should never return false - */ - @autoserialize - okay: boolean; - - /** - * True if the token is valid, false if there was no token or the token wasn't valid - */ - @autoserialize - authenticated: boolean; - - /** - * The self link to the eperson of this auth status - */ - @relationship(EPerson, false) - @autoserialize - eperson: string; - - /** - * All authentication methods enabled at the backend - */ - @autoserialize - authMethods: AuthMethod[]; -} diff --git a/src/app/core/auth/server-auth.service.ts b/src/app/core/auth/server-auth.service.ts index f6ff454a7b..e2f80b2962 100644 --- a/src/app/core/auth/server-auth.service.ts +++ b/src/app/core/auth/server-auth.service.ts @@ -4,13 +4,13 @@ import { HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { filter, map, switchMap, take } from 'rxjs/operators'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { AuthStatus } from './models/auth-status.model'; import { isNotEmpty } from '../../shared/empty.util'; -import { AuthService } from './auth.service'; -import { AuthTokenInfo } from './models/auth-token-info.model'; +import { followLink } from '../../shared/utils/follow-link-config.model'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; import { EPerson } from '../eperson/models/eperson.model'; -import { NormalizedAuthStatus } from './models/normalized-auth-status.model'; +import { AuthService } from './auth.service'; +import { AuthStatus } from './models/auth-status.model'; +import { AuthTokenInfo } from './models/auth-token-info.model'; /** * The auth service. @@ -35,7 +35,7 @@ export class ServerAuthService extends AuthService { options.headers = headers; return this.authRequestService.getRequest('status', options).pipe( - map((status) => this.rdbService.build(status)), + map((status) => this.linkService.resolveLinks(status, followLink('eperson'))), switchMap((status: AuthStatus) => { if (status.authenticated) { return status.eperson.pipe(map((eperson) => eperson.payload)); @@ -61,7 +61,7 @@ export class ServerAuthService extends AuthService { options.headers = headers; options.withCredentials = true; return this.authRequestService.getRequest('status', options).pipe( - map((status: NormalizedAuthStatus) => Object.assign(new AuthStatus(), status)) + map((status: AuthStatus) => Object.assign(new AuthStatus(), status)) ); } diff --git a/src/app/core/browse/browse.service.spec.ts b/src/app/core/browse/browse.service.spec.ts index 55ff7a090e..6dafa4cf0a 100644 --- a/src/app/core/browse/browse.service.spec.ts +++ b/src/app/core/browse/browse.service.spec.ts @@ -1,16 +1,16 @@ import { cold, getTestScheduler, hot } from 'jasmine-marbles'; +import { of as observableOf } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service'; 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 { BrowseEndpointRequest, BrowseEntriesRequest, BrowseItemsRequest } from '../data/request.models'; +import { RequestEntry } from '../data/request.reducer'; import { RequestService } from '../data/request.service'; import { BrowseDefinition } from '../shared/browse-definition.model'; -import { BrowseService } from './browse.service'; import { BrowseEntrySearchOptions } from './browse-entry-search-options.model'; -import { RequestEntry } from '../data/request.reducer'; -import { of as observableOf } from 'rxjs'; +import { BrowseService } from './browse.service'; describe('BrowseService', () => { let scheduler: TestScheduler; @@ -44,8 +44,8 @@ describe('BrowseService', () => { 'dc.date.issued' ], _links: { - self: 'https://rest.api/discover/browses/dateissued', - items: 'https://rest.api/discover/browses/dateissued/items' + self: { href: 'https://rest.api/discover/browses/dateissued' }, + items: { href: 'https://rest.api/discover/browses/dateissued/items' } } }), Object.assign(new BrowseDefinition(), { @@ -72,9 +72,9 @@ describe('BrowseService', () => { 'dc.creator' ], _links: { - self: 'https://rest.api/discover/browses/author', - entries: 'https://rest.api/discover/browses/author/entries', - items: 'https://rest.api/discover/browses/author/items' + self: { href: 'https://rest.api/discover/browses/author' }, + entries: { href: 'https://rest.api/discover/browses/author/entries' }, + items: { href: 'https://rest.api/discover/browses/author/items' } } }) ]; @@ -125,9 +125,11 @@ describe('BrowseService', () => { }); it('should return a RemoteData object containing the correct BrowseDefinition[]', () => { - const expected = cold('--a-', { a: { - payload: browseDefinitions - }}); + const expected = cold('--a-', { + a: { + payload: browseDefinitions + } + }); expect(service.getBrowseDefinitions()).toBeObservable(expected); }); @@ -142,15 +144,17 @@ describe('BrowseService', () => { rdbService = getMockRemoteDataBuildService(); service = initTestService(); spyOn(service, 'getBrowseDefinitions').and - .returnValue(hot('--a-', { a: { + .returnValue(hot('--a-', { + a: { payload: browseDefinitions - }})); + } + })); spyOn(rdbService, 'toRemoteDataObservable').and.callThrough(); }); describe('when getBrowseEntriesFor is called with a valid browse definition id', () => { it('should configure a new BrowseEntriesRequest', () => { - const expected = new BrowseEntriesRequest(requestService.generateRequestId(), browseDefinitions[1]._links.entries); + const expected = new BrowseEntriesRequest(requestService.generateRequestId(), browseDefinitions[1]._links.entries.href); scheduler.schedule(() => service.getBrowseEntriesFor(new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); scheduler.flush(); @@ -169,7 +173,7 @@ describe('BrowseService', () => { describe('when getBrowseItemsFor is called with a valid browse definition id', () => { it('should configure a new BrowseItemsRequest', () => { - const expected = new BrowseItemsRequest(requestService.generateRequestId(), browseDefinitions[1]._links.items + '?filterValue=' + mockAuthorName); + const expected = new BrowseItemsRequest(requestService.generateRequestId(), browseDefinitions[1]._links.items.href + '?filterValue=' + mockAuthorName); scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); scheduler.flush(); @@ -215,9 +219,11 @@ describe('BrowseService', () => { rdbService = getMockRemoteDataBuildService(); service = initTestService(); spyOn(service, 'getBrowseDefinitions').and - .returnValue(hot('--a-', { a: { + .returnValue(hot('--a-', { + a: { payload: browseDefinitions - }})); + } + })); }); it('should return the URL for the given metadataKey and linkPath', () => { @@ -288,14 +294,16 @@ describe('BrowseService', () => { rdbService = getMockRemoteDataBuildService(); service = initTestService(); spyOn(service, 'getBrowseDefinitions').and - .returnValue(hot('--a-', { a: { + .returnValue(hot('--a-', { + a: { payload: browseDefinitions - }})); + } + })); spyOn(rdbService, 'toRemoteDataObservable').and.callThrough(); }); describe('when getFirstItemFor is called with a valid browse definition id', () => { - const expectedURL = browseDefinitions[1]._links.items + '?page=0&size=1'; + const expectedURL = browseDefinitions[1]._links.items.href + '?page=0&size=1'; it('should configure a new BrowseItemsRequest', () => { const expected = new BrowseItemsRequest(requestService.generateRequestId(), expectedURL); diff --git a/src/app/core/browse/browse.service.ts b/src/app/core/browse/browse.service.ts index eb494d7bdb..78e63e8540 100644 --- a/src/app/core/browse/browse.service.ts +++ b/src/app/core/browse/browse.service.ts @@ -10,18 +10,16 @@ import { isNotEmptyOperator } from '../../shared/empty.util'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { GenericSuccessResponse } from '../cache/response.models'; import { PaginatedList } from '../data/paginated-list'; import { RemoteData } from '../data/remote-data'; -import { - BrowseEndpointRequest, - BrowseEntriesRequest, - BrowseItemsRequest, - RestRequest -} from '../data/request.models'; +import { BrowseEndpointRequest, BrowseEntriesRequest, BrowseItemsRequest, RestRequest } from '../data/request.models'; import { RequestService } from '../data/request.service'; import { BrowseDefinition } from '../shared/browse-definition.model'; import { BrowseEntry } from '../shared/browse-entry.model'; +import { DSpaceObject } from '../shared/dspace-object.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; import { configureRequest, filterSuccessfulResponses, @@ -31,10 +29,7 @@ import { getRequestFromRequestHref } from '../shared/operators'; import { URLCombiner } from '../url-combiner/url-combiner'; -import { Item } from '../shared/item.model'; -import { DSpaceObject } from '../shared/dspace-object.model'; import { BrowseEntrySearchOptions } from './browse-entry-search-options.model'; -import { GenericSuccessResponse } from '../cache/response.models'; /** * The service handling all browse requests @@ -81,10 +76,11 @@ export class BrowseService { map((response: GenericSuccessResponse) => response.payload), ensureArrayHasValue(), map((definitions: BrowseDefinition[]) => definitions - .map((definition: BrowseDefinition) => Object.assign(new BrowseDefinition(), definition))), - distinctUntilChanged() + .map((definition: BrowseDefinition) => { + return Object.assign(new BrowseDefinition(), definition) + })), + distinctUntilChanged(), ); - return this.rdb.toRemoteDataObservable(requestEntry$, payload$); } @@ -96,7 +92,10 @@ export class BrowseService { return this.getBrowseDefinitions().pipe( getBrowseDefinitionLinks(options.metadataDefinition), hasValueOperator(), - map((_links: any) => _links.entries), + map((_links: any) => { + const entriesLink = _links.entries.href || _links.entries; + return entriesLink; + }), hasValueOperator(), map((href: string) => { // TODO nearly identical to PaginatedSearchOptions => refactor @@ -133,7 +132,10 @@ export class BrowseService { return this.getBrowseDefinitions().pipe( getBrowseDefinitionLinks(options.metadataDefinition), hasValueOperator(), - map((_links: any) => _links.items), + map((_links: any) => { + const itemsLink = _links.items.href || _links.items; + return itemsLink; + }), hasValueOperator(), map((href: string) => { const args = []; @@ -171,7 +173,10 @@ export class BrowseService { return this.getBrowseDefinitions().pipe( getBrowseDefinitionLinks(definition), hasValueOperator(), - map((_links: any) => _links.items), + map((_links: any) => { + const itemsLink = _links.items.href || _links.items; + return itemsLink; + }), hasValueOperator(), map((href: string) => { const args = []; @@ -249,7 +254,7 @@ export class BrowseService { if (isEmpty(def) || isEmpty(def._links) || isEmpty(def._links[linkPath])) { throw new Error(`A browse endpoint for ${linkPath} on ${metadataKey} isn't configured`); } else { - return def._links[linkPath]; + return def._links[linkPath] || def._links[linkPath].href; } }), startWith(undefined), diff --git a/src/app/core/cache/builders/build-decorators.spec.ts b/src/app/core/cache/builders/build-decorators.spec.ts new file mode 100644 index 0000000000..e47cf1a80a --- /dev/null +++ b/src/app/core/cache/builders/build-decorators.spec.ts @@ -0,0 +1,83 @@ +import { HALLink } from '../../shared/hal-link.model'; +import { HALResource } from '../../shared/hal-resource.model'; +import { ResourceType } from '../../shared/resource-type'; +import { + dataService, + getDataServiceFor, + getLinkDefinition, + link, +} from './build-decorators'; + +/* tslint:disable:max-classes-per-file */ +class TestService {} +class AnotherTestService {} +class TestHALResource implements HALResource { + _links: { + self: HALLink; + foo: HALLink; + }; + + bar?: any +} +let testType; + +describe('build decorators', () => { + beforeEach(() => { + testType = new ResourceType('testType-' + new Date().getTime()); + }); + describe('@dataService/getDataServiceFor', () => { + + it('should register a resourcetype for a dataservice', () => { + dataService(testType)(TestService); + expect(getDataServiceFor(testType)).toBe(TestService); + }); + + describe(`when the resource type isn't specified`, () => { + it(`should throw an error`, () => { + expect(() => { + dataService(undefined)(TestService); + }).toThrow(); + }); + }); + + describe(`when there already is a registered dataservice for a resourcetype`, () => { + it(`should throw an error`, () => { + dataService(testType)(TestService); + expect(() => { + dataService(testType)(AnotherTestService); + }).toThrow(); + }); + }); + + }); + + describe(`@link/getLinkDefinitions`, () => { + it(`should register a link`, () => { + const target = new TestHALResource(); + link(testType, true, 'foo')(target, 'bar'); + const result = getLinkDefinition(TestHALResource, 'foo'); + expect(result.resourceType).toBe(testType); + expect(result.isList).toBe(true); + expect(result.linkName).toBe('foo'); + expect(result.propertyName).toBe('bar'); + }); + + describe(`when the linkname isn't specified`, () => { + it(`should use the propertyname`, () => { + const target = new TestHALResource(); + link(testType)(target, 'foo'); + const result = getLinkDefinition(TestHALResource, 'foo'); + expect(result.linkName).toBe('foo'); + expect(result.propertyName).toBe('foo'); + }); + }); + + describe(`when there's no @link`, () => { + it(`should return undefined`, () => { + const result = getLinkDefinition(TestHALResource, 'self'); + expect(result).toBeUndefined(); + }); + }); + }); +}); +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/cache/builders/build-decorators.ts b/src/app/core/cache/builders/build-decorators.ts index 0bfb5f0321..4ba04bfa55 100644 --- a/src/app/core/cache/builders/build-decorators.ts +++ b/src/app/core/cache/builders/build-decorators.ts @@ -1,80 +1,161 @@ import 'reflect-metadata'; +import { hasNoValue, hasValue } from '../../../shared/empty.util'; +import { DataService } from '../../data/data.service'; import { GenericConstructor } from '../../shared/generic-constructor'; -import { CacheableObject, TypedObject } from '../object-cache.reducer'; +import { HALResource } from '../../shared/hal-resource.model'; import { ResourceType } from '../../shared/resource-type'; +import { CacheableObject, TypedObject } from '../object-cache.reducer'; -const mapsToMetadataKey = Symbol('mapsTo'); -const relationshipKey = Symbol('relationship'); +const resolvedLinkKey = Symbol('resolvedLink'); -const relationshipMap = new Map(); +const resolvedLinkMap = new Map(); const typeMap = new Map(); +const dataServiceMap = new Map(); +const linkMap = new Map(); /** - * Decorator function to map a normalized class to it's not-normalized counter part class - * It will also maps a type to the matching class - * @param value The not-normalized class to map to + * Decorator function to map a ResourceType to its class + * @param target The contructor of the typed class to map */ -export function mapsTo(value: GenericConstructor) { - return function decorator(objectConstructor: GenericConstructor) { - Reflect.defineMetadata(mapsToMetadataKey, value, objectConstructor); - mapsToType((value as any).type, objectConstructor); - } -} - -/** - * Maps a type to the matching class - * @param value The resourse type - * @param objectConstructor The class to map to - */ -function mapsToType(value: ResourceType, objectConstructor: GenericConstructor) { - if (!objectConstructor || !value) { - return; - } - typeMap.set(value.value, objectConstructor); -} - -/** - * Returns the mapped class for the given normalized class - * @param target The normalized class - */ -export function getMapsTo(target: any) { - return Reflect.getOwnMetadata(mapsToMetadataKey, target); +export function typedObject(target: typeof TypedObject) { + typeMap.set(target.type.value, target); } /** * Returns the mapped class for the given type * @param type The resource type */ -export function getMapsToType(type: string | ResourceType) { +export function getClassForType(type: string | ResourceType) { if (typeof(type) === 'object') { type = (type as ResourceType).value; } return typeMap.get(type); } -export function relationship(value: GenericConstructor, isList: boolean = false): any { - return function r(target: any, propertyKey: string, descriptor: PropertyDescriptor) { - if (!target || !propertyKey) { - return; +/** + * A class decorator to indicate that this class is a dataservice + * for a given resource type. + * + * "dataservice" in this context means that it has findByHref and + * findAllByHref methods. + * + * @param resourceType the resource type the class is a dataservice for + */ +export function dataService(resourceType: ResourceType): any { + return (target: any) => { + if (hasNoValue(resourceType)) { + throw new Error(`Invalid @dataService annotation on ${target}, resourceType needs to be defined`); + } + const existingDataservice = dataServiceMap.get(resourceType.value); + + if (hasValue(existingDataservice)) { + throw new Error(`Multiple dataservices for ${resourceType.value}: ${existingDataservice} and ${target}`); } - const metaDataList: string[] = relationshipMap.get(target.constructor) || []; - if (metaDataList.indexOf(propertyKey) === -1) { - metaDataList.push(propertyKey); - } - relationshipMap.set(target.constructor, metaDataList); - return Reflect.metadata(relationshipKey, { - resourceType: (value as any).type.value, - isList - }).apply(this, arguments); + dataServiceMap.set(resourceType.value, target); }; } -export function getRelationMetadata(target: any, propertyKey: string) { - return Reflect.getMetadata(relationshipKey, target, propertyKey); +/** + * Return the dataservice matching the given resource type + * + * @param resourceType the resource type you want the matching dataservice for + */ +export function getDataServiceFor(resourceType: ResourceType) { + return dataServiceMap.get(resourceType.value); } -export function getRelationships(target: any) { - return relationshipMap.get(target); +/** + * A class to represent the data that can be set by the @link decorator + */ +export class LinkDefinition { + resourceType: ResourceType; + isList = false; + linkName: keyof T['_links']; + propertyName: keyof T; +} + +/** + * A property decorator to indicate that a certain property is the placeholder + * where the contents of a resolved link should be stored. + * + * e.g. if an Item has an hal link for bundles, and an item.bundles property + * this decorator should decorate that item.bundles property. + * + * @param resourceType the resource type of the object(s) the link retrieves + * @param isList an optional boolean indicating whether or not it concerns a list, + * defaults to false + * @param linkName an optional string in case the {@link HALLink} name differs from the + * property name + */ +export const link = ( + resourceType: ResourceType, + isList = false, + linkName?: keyof T['_links'], + ) => { + return (target: T, propertyName: string) => { + let targetMap = linkMap.get(target.constructor); + + if (hasNoValue(targetMap)) { + targetMap = new Map>(); + } + + if (hasNoValue(linkName)) { + linkName = propertyName as any; + } + + targetMap.set(linkName, { + resourceType, + isList, + linkName, + propertyName + }); + + linkMap.set(target.constructor, targetMap); + } +}; + +/** + * Returns all LinkDefinitions for a model class + * @param source + */ +export const getLinkDefinitions = (source: GenericConstructor): Map> => { + return linkMap.get(source); +}; + +/** + * Returns a specific LinkDefinition for a model class + * + * @param source the model class + * @param linkName the name of the link + */ +export const getLinkDefinition = (source: GenericConstructor, linkName: keyof T['_links']): LinkDefinition => { + const sourceMap = linkMap.get(source); + if (hasValue(sourceMap)) { + return sourceMap.get(linkName); + } else { + return undefined; + } +}; + +/** + * A class level decorator to indicate you want to inherit @link annotations + * from a parent class. + * + * @param parent the parent class to inherit @link annotations from + */ +export function inheritLinkAnnotations(parent: any): any { + return (child: any) => { + const parentMap: Map> = linkMap.get(parent) || new Map(); + const childMap: Map> = linkMap.get(child) || new Map(); + + parentMap.forEach((value, key) => { + if (!childMap.has(key)) { + childMap.set(key, value); + } + }); + + linkMap.set(child, childMap); + } } diff --git a/src/app/core/cache/builders/link.service.spec.ts b/src/app/core/cache/builders/link.service.spec.ts new file mode 100644 index 0000000000..b34aea320a --- /dev/null +++ b/src/app/core/cache/builders/link.service.spec.ts @@ -0,0 +1,222 @@ +import { Injectable } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; +import { FindListOptions } from '../../data/request.models'; +import { HALLink } from '../../shared/hal-link.model'; +import { HALResource } from '../../shared/hal-resource.model'; +import { ResourceType } from '../../shared/resource-type'; +import * as decorators from './build-decorators'; +import { getDataServiceFor } from './build-decorators'; +import { LinkService } from './link.service'; + +const spyOnFunction = (obj: T, func: keyof T) => { + const spy = jasmine.createSpy(func as string); + spyOnProperty(obj, func, 'get').and.returnValue(spy); + + return spy; +}; + +const TEST_MODEL = new ResourceType('testmodel'); +let result: any; + +/* tslint:disable:max-classes-per-file */ +class TestModel implements HALResource { + static type = TEST_MODEL; + + type = TEST_MODEL; + + value: string; + + _links: { + self: HALLink; + predecessor: HALLink; + successor: HALLink; + }; + + predecessor?: TestModel; + successor?: TestModel; +} + +@Injectable() +class TestDataService { + findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>) { + return 'findAllByHref' + } + findByHref(href: string, ...linksToFollow: Array>) { + return 'findByHref' + } +} + +let testDataService: TestDataService; + +let testModel: TestModel; + +describe('LinkService', () => { + let service: LinkService; + + beforeEach(() => { + testModel = Object.assign(new TestModel(), { + value: 'a test value', + _links: { + self: { + href: 'http://self.link' + }, + predecessor: { + href: 'http://predecessor.link' + }, + successor: { + href: 'http://successor.link' + }, + } + }); + testDataService = new TestDataService(); + spyOn(testDataService, 'findAllByHref').and.callThrough(); + spyOn(testDataService, 'findByHref').and.callThrough(); + TestBed.configureTestingModule({ + providers: [LinkService, { + provide: TestDataService, + useValue: testDataService + }] + }); + service = TestBed.get(LinkService); + }); + + describe('resolveLink', () => { + describe(`when the linkdefinition concerns a single object`, () => { + beforeEach(() => { + spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({ + resourceType: TEST_MODEL, + linkName: 'predecessor', + propertyName: 'predecessor' + }); + spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService); + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))) + }); + it('should call dataservice.findByHref with the correct href and nested links', () => { + expect(testDataService.findByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, followLink('successor')); + }); + }); + describe(`when the linkdefinition concerns a list`, () => { + beforeEach(() => { + spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({ + resourceType: TEST_MODEL, + linkName: 'predecessor', + propertyName: 'predecessor', + isList: true + }); + spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService); + service.resolveLink(testModel, followLink('predecessor', { some: 'options '} as any, followLink('successor'))) + }); + it('should call dataservice.findAllByHref with the correct href, findListOptions, and nested links', () => { + expect(testDataService.findAllByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, { some: 'options '} as any, followLink('successor')); + }); + }); + describe('either way', () => { + beforeEach(() => { + spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({ + resourceType: TEST_MODEL, + linkName: 'predecessor', + propertyName: 'predecessor' + }); + spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(TestDataService); + result = service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))) + }); + + it('should call getLinkDefinition with the correct model and link', () => { + expect(decorators.getLinkDefinition).toHaveBeenCalledWith(testModel.constructor as any, 'predecessor'); + }); + + it('should call getDataServiceFor with the correct resource type', () => { + expect(decorators.getDataServiceFor).toHaveBeenCalledWith(TEST_MODEL); + }); + + it('should return the model with the resolved link', () => { + expect(result.type).toBe(TEST_MODEL); + expect(result.value).toBe('a test value'); + expect(result._links.self.href).toBe('http://self.link'); + expect(result.predecessor).toBe('findByHref'); + }); + }); + + describe(`when the specified link doesn't exist on the model's class`, () => { + beforeEach(() => { + spyOnFunction(decorators, 'getLinkDefinition').and.returnValue(undefined); + }); + it('should throw an error', () => { + expect(() => { + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))) + }).toThrow(); + }); + }); + + describe(`when there is no dataservice for the resourcetype in the link`, () => { + beforeEach(() => { + spyOnFunction(decorators, 'getLinkDefinition').and.returnValue({ + resourceType: TEST_MODEL, + linkName: 'predecessor', + propertyName: 'predecessor' + }); + spyOnFunction(decorators, 'getDataServiceFor').and.returnValue(undefined); + }); + it('should throw an error', () => { + expect(() => { + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))) + }).toThrow(); + }); + }); + }); + + describe('resolveLinks', () => { + beforeEach(() => { + spyOn(service, 'resolveLink'); + service.resolveLinks(testModel, followLink('predecessor'), followLink('successor')) + }); + + it('should call resolveLink with the model for each of the provided links', () => { + expect(service.resolveLink).toHaveBeenCalledWith(testModel, followLink('predecessor')); + expect(service.resolveLink).toHaveBeenCalledWith(testModel, followLink('successor')); + }); + + it('should return the model', () => { + expect(result.type).toBe(TEST_MODEL); + expect(result.value).toBe('a test value'); + expect(result._links.self.href).toBe('http://self.link'); + }); + }); + + describe('removeResolvedLinks', () => { + beforeEach(() => { + testModel.predecessor = 'predecessor value' as any; + testModel.successor = 'successor value' as any; + spyOnFunction(decorators, 'getLinkDefinitions').and.returnValue([ + { + resourceType: TEST_MODEL, + linkName: 'predecessor', + propertyName: 'predecessor', + }, + { + resourceType: TEST_MODEL, + linkName: 'successor', + propertyName: 'successor', + } + ]) + }); + + it('should return a new version of the object without any resolved links', () => { + result = service.removeResolvedLinks(testModel); + expect(result.value).toBe(testModel.value); + expect(result.type).toBe(testModel.type); + expect(result._links).toBe(testModel._links); + expect(result.predecessor).toBeUndefined(); + expect(result.successor).toBeUndefined(); + }); + + it('should leave the original object untouched', () => { + service.removeResolvedLinks(testModel); + expect(testModel.predecessor as any).toBe('predecessor value'); + expect(testModel.successor as any).toBe('successor value'); + }); + }); + +}); +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/cache/builders/link.service.ts b/src/app/core/cache/builders/link.service.ts new file mode 100644 index 0000000000..c41a5484a1 --- /dev/null +++ b/src/app/core/cache/builders/link.service.ts @@ -0,0 +1,90 @@ +import { Injectable, Injector } from '@angular/core'; +import { hasNoValue, hasValue, isNotEmpty } from '../../../shared/empty.util'; +import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; +import { GenericConstructor } from '../../shared/generic-constructor'; +import { HALResource } from '../../shared/hal-resource.model'; +import { getDataServiceFor, getLinkDefinition, getLinkDefinitions, LinkDefinition } from './build-decorators'; + +/** + * A Service to handle the resolving and removing + * of resolved {@link HALLink}s on HALResources + */ +@Injectable({ + providedIn: 'root' +}) +export class LinkService { + + constructor( + protected parentInjector: Injector, + ) { + } + + /** + * Resolve the given {@link FollowLinkConfig}s for the given model + * + * @param model the {@link HALResource} to resolve the links for + * @param linksToFollow the {@link FollowLinkConfig}s to resolve + */ + public resolveLinks(model: T, ...linksToFollow: Array>): T { + linksToFollow.forEach((linkToFollow: FollowLinkConfig) => { + this.resolveLink(model, linkToFollow); + }); + return model; + } + + /** + * Resolve the given {@link FollowLinkConfig} for the given model + * + * @param model the {@link HALResource} to resolve the link for + * @param linkToFollow the {@link FollowLinkConfig} to resolve + */ + public resolveLink(model, linkToFollow: FollowLinkConfig): T { + const matchingLinkDef = getLinkDefinition(model.constructor, linkToFollow.name); + + if (hasNoValue(matchingLinkDef)) { + throw new Error(`followLink('${linkToFollow.name}') was used for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`); + } else { + const provider = getDataServiceFor(matchingLinkDef.resourceType); + + if (hasNoValue(provider)) { + throw new Error(`The @link() for ${linkToFollow.name} on ${model.constructor.name} models uses the resource type ${matchingLinkDef.resourceType.value.toUpperCase()}, but there is no service with an @dataService(${matchingLinkDef.resourceType.value.toUpperCase()}) annotation in order to retrieve it`); + } + + const service = Injector.create({ + providers: [], + parent: this.parentInjector + }).get(provider); + + const href = model._links[matchingLinkDef.linkName].href; + + try { + if (matchingLinkDef.isList) { + model[linkToFollow.name] = service.findAllByHref(href, linkToFollow.findListOptions, ...linkToFollow.linksToFollow); + } else { + model[linkToFollow.name] = service.findByHref(href, ...linkToFollow.linksToFollow); + } + } catch (e) { + throw new Error(`Something went wrong when using @dataService(${matchingLinkDef.resourceType.value}) ${hasValue(service) ? '' : '(undefined) '}to resolve link ${linkToFollow.name} from ${href}`); + } + } + return model; + } + + /** + * Remove any resolved links that the model may have. + * + * @param model the {@link HALResource} to remove the links from + * @returns a copy of the given model, without resolved links. + */ + public removeResolvedLinks(model: T): T { + const result = Object.assign(new (model.constructor as GenericConstructor)(), model); + const linkDefs = getLinkDefinitions(model.constructor as GenericConstructor); + if (isNotEmpty(linkDefs)) { + linkDefs.forEach((linkDef: LinkDefinition) => { + result[linkDef.propertyName] = undefined; + }); + } + return result; + } + +} diff --git a/src/app/core/cache/builders/normalized-object-build.service.ts b/src/app/core/cache/builders/normalized-object-build.service.ts deleted file mode 100644 index 69d7454d2d..0000000000 --- a/src/app/core/cache/builders/normalized-object-build.service.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Injectable } from '@angular/core'; -import { NormalizedObject } from '../models/normalized-object.model'; -import { getMapsToType, getRelationships } from './build-decorators'; -import { hasValue, isNotEmpty } from '../../../shared/empty.util'; -import { CacheableObject, TypedObject } from '../object-cache.reducer'; - -/** - * Return true if halObj has a value for `_links.self` - * - * @param {any} halObj The object to test - */ -export function isRestDataObject(halObj: any): boolean { - return isNotEmpty(halObj._links) && hasValue(halObj._links.self); -} - -/** - * Return true if halObj has a value for `page` and `_embedded` - * - * @param {any} halObj The object to test - */ -export function isRestPaginatedList(halObj: any): boolean { - return hasValue(halObj.page) && hasValue(halObj._embedded); -} - -/** - * A service to turn domain models in to their normalized - * counterparts. - */ -@Injectable() -export class NormalizedObjectBuildService { - - /** - * Returns the normalized model that corresponds to the given domain model - * - * @param {TDomain} domainModel a domain model - */ - normalize(domainModel: T): NormalizedObject { - const normalizedConstructor = getMapsToType((domainModel as any).type); - const relationships = getRelationships(normalizedConstructor) || []; - const normalizedModel = Object.assign({}, domainModel) as any; - relationships.forEach((key: string) => { - if (hasValue(normalizedModel[key])) { - normalizedModel[key] = normalizedModel._links[key]; - } - }); - return normalizedModel; - } -} diff --git a/src/app/core/cache/builders/remote-data-build.service.spec.ts b/src/app/core/cache/builders/remote-data-build.service.spec.ts index 2f0e024521..85267d7f4c 100644 --- a/src/app/core/cache/builders/remote-data-build.service.spec.ts +++ b/src/app/core/cache/builders/remote-data-build.service.spec.ts @@ -1,10 +1,10 @@ -import { RemoteDataBuildService } from './remote-data-build.service'; -import { Item } from '../../shared/item.model'; -import { PaginatedList } from '../../data/paginated-list'; -import { PageInfo } from '../../shared/page-info.model'; -import { RemoteData } from '../../data/remote-data'; import { of as observableOf } from 'rxjs'; import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils'; +import { PaginatedList } from '../../data/paginated-list'; +import { RemoteData } from '../../data/remote-data'; +import { Item } from '../../shared/item.model'; +import { PageInfo } from '../../shared/page-info.model'; +import { RemoteDataBuildService } from './remote-data-build.service'; const pageInfo = new PageInfo(); const array = [ @@ -37,7 +37,7 @@ describe('RemoteDataBuildService', () => { let service: RemoteDataBuildService; beforeEach(() => { - service = new RemoteDataBuildService(undefined, undefined); + service = new RemoteDataBuildService(undefined, undefined, undefined); }); describe('when toPaginatedList is called', () => { 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 48c5090102..94c660d672 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -1,36 +1,46 @@ import { Injectable } from '@angular/core'; - import { combineLatest as observableCombineLatest, Observable, of as observableOf, race as observableRace } from 'rxjs'; -import { distinctUntilChanged, flatMap, map, startWith, switchMap, tap } from 'rxjs/operators'; - -import { hasValue, hasValueOperator, isEmpty, isNotEmpty, isNotUndefined } from '../../../shared/empty.util'; +import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; +import { + hasValue, + hasValueOperator, + isEmpty, + isNotEmpty, + isNotUndefined +} from '../../../shared/empty.util'; +import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; import { PaginatedList } from '../../data/paginated-list'; import { RemoteData } from '../../data/remote-data'; import { RemoteDataError } from '../../data/remote-data-error'; -import { GetRequest } from '../../data/request.models'; import { RequestEntry } from '../../data/request.reducer'; import { RequestService } from '../../data/request.service'; -import { NormalizedObject } from '../models/normalized-object.model'; -import { ObjectCacheService } from '../object-cache.service'; -import { DSOSuccessResponse, ErrorResponse } from '../response.models'; -import { getMapsTo, getRelationMetadata, getRelationships } from './build-decorators'; -import { PageInfo } from '../../shared/page-info.model'; import { filterSuccessfulResponses, getRequestFromRequestHref, getRequestFromRequestUUID, getResourceLinksFromResponse } from '../../shared/operators'; -import { CacheableObject, TypedObject } from '../object-cache.reducer'; -import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { PageInfo } from '../../shared/page-info.model'; +import { CacheableObject } from '../object-cache.reducer'; +import { ObjectCacheService } from '../object-cache.service'; +import { DSOSuccessResponse, ErrorResponse } from '../response.models'; +import { LinkService } from './link.service'; @Injectable() export class RemoteDataBuildService { constructor(protected objectCache: ObjectCacheService, + protected linkService: LinkService, protected requestService: RequestService) { } - buildSingle(href$: string | Observable): Observable> { + /** + * Creates a single {@link RemoteData} object based on the response of a request to the REST server, with a list of + * {@link FollowLinkConfig} that indicate which embedded info should be added to the object + * @param href$ Observable href of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + buildSingle(href$: string | Observable, ...linksToFollow: Array>): Observable> { if (typeof href$ === 'string') { href$ = observableOf(href$); } @@ -70,9 +80,9 @@ export class RemoteDataBuildService { } }), hasValueOperator(), - map((normalized: NormalizedObject) => { - return this.build(normalized); - }), + map((obj: T) => + this.linkService.resolveLinks(obj, ...linksToFollow) + ), startWith(undefined), distinctUntilChanged() ); @@ -108,7 +118,13 @@ export class RemoteDataBuildService { ); } - buildList(href$: string | Observable): Observable>> { + /** + * Creates a list of {@link RemoteData} objects based on the response of a request to the REST server, with a list of + * {@link FollowLinkConfig} that indicate which embedded info should be added to the objects + * @param href$ Observable href of objects we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + buildList(href$: string | Observable, ...linksToFollow: Array>): Observable>> { if (typeof href$ === 'string') { href$ = observableOf(href$); } @@ -118,10 +134,10 @@ export class RemoteDataBuildService { getResourceLinksFromResponse(), switchMap((resourceUUIDs: string[]) => { return this.objectCache.getList(resourceUUIDs).pipe( - map((normList: Array>) => { - return normList.map((normalized: NormalizedObject) => { - return this.build(normalized); - }); + map((objs: T[]) => { + return objs.map((obj: T) => + this.linkService.resolveLinks(obj, ...linksToFollow) + ); })); }), startWith([]), @@ -150,54 +166,6 @@ export class RemoteDataBuildService { return this.toRemoteDataObservable(requestEntry$, payload$); } - build(normalized: NormalizedObject): T { - const links: any = {}; - const relationships = getRelationships(normalized.constructor) || []; - - relationships.forEach((relationship: string) => { - let result; - if (hasValue(normalized[relationship])) { - const { resourceType, isList } = getRelationMetadata(normalized, relationship); - const objectList = normalized[relationship].page || normalized[relationship]; - if (typeof objectList !== 'string') { - objectList.forEach((href: string) => { - this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href)) - }); - - const rdArr = []; - objectList.forEach((href: string) => { - rdArr.push(this.buildSingle(href)); - }); - - if (isList) { - result = this.aggregate(rdArr); - } else if (rdArr.length === 1) { - result = rdArr[0]; - } - } else { - this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), objectList)); - - // The rest API can return a single URL to represent a list of resources (e.g. /items/:id/bitstreams) - // in that case only 1 href will be stored in the normalized obj (so the isArray above fails), - // but it should still be built as a list - if (isList) { - result = this.buildList(objectList); - } else { - result = this.buildSingle(objectList); - } - } - - if (hasValue(normalized[relationship].page)) { - links[relationship] = this.toPaginatedList(result, normalized[relationship].pageInfo); - } else { - links[relationship] = result; - } - } - }); - const domainModel = getMapsTo(normalized.constructor); - return Object.assign(new domainModel(), normalized, links); - } - aggregate(input: Array>>): Observable> { if (isEmpty(input)) { diff --git a/src/app/core/cache/models/items/normalized-item-type.model.ts b/src/app/core/cache/models/items/normalized-item-type.model.ts deleted file mode 100644 index fdb3b9e455..0000000000 --- a/src/app/core/cache/models/items/normalized-item-type.model.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { ItemType } from '../../../shared/item-relationships/item-type.model'; -import { mapsTo } from '../../builders/build-decorators'; -import { NormalizedObject } from '../normalized-object.model'; -import { IDToUUIDSerializer } from '../../id-to-uuid-serializer'; - -/** - * Normalized model class for a DSpace ItemType - */ -@mapsTo(ItemType) -@inheritSerialization(NormalizedObject) -export class NormalizedItemType extends NormalizedObject { - /** - * The label that describes the ResourceType of the Item - */ - @autoserialize - label: string; - - /** - * The identifier of this ItemType - */ - @autoserialize - id: string; - - /** - * The universally unique identifier of this ItemType - */ - @autoserializeAs(new IDToUUIDSerializer(ItemType.type.value), 'id') - uuid: string; -} diff --git a/src/app/core/cache/models/items/normalized-relationship-type.model.ts b/src/app/core/cache/models/items/normalized-relationship-type.model.ts deleted file mode 100644 index 23c3333a9b..0000000000 --- a/src/app/core/cache/models/items/normalized-relationship-type.model.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { RelationshipType } from '../../../shared/item-relationships/relationship-type.model'; -import { ResourceType } from '../../../shared/resource-type'; -import { mapsTo, relationship } from '../../builders/build-decorators'; -import { NormalizedDSpaceObject } from '../normalized-dspace-object.model'; -import { NormalizedObject } from '../normalized-object.model'; -import { IDToUUIDSerializer } from '../../id-to-uuid-serializer'; -import { ItemType } from '../../../shared/item-relationships/item-type.model'; - -/** - * Normalized model class for a DSpace RelationshipType - */ -@mapsTo(RelationshipType) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedRelationshipType extends NormalizedObject { - /** - * The identifier of this RelationshipType - */ - @autoserialize - id: string; - - /** - * The label that describes the Relation to the left of this RelationshipType - */ - @autoserialize - leftwardType: string; - - /** - * The maximum amount of Relationships allowed to the left of this RelationshipType - */ - @autoserialize - leftMaxCardinality: number; - - /** - * The minimum amount of Relationships allowed to the left of this RelationshipType - */ - @autoserialize - leftMinCardinality: number; - - /** - * The label that describes the Relation to the right of this RelationshipType - */ - @autoserialize - rightwardType: string; - - /** - * The maximum amount of Relationships allowed to the right of this RelationshipType - */ - @autoserialize - rightMaxCardinality: number; - - /** - * The minimum amount of Relationships allowed to the right of this RelationshipType - */ - @autoserialize - rightMinCardinality: number; - - /** - * The type of Item found to the left of this RelationshipType - */ - @autoserialize - @relationship(ItemType, false) - leftType: string; - - /** - * The type of Item found to the right of this RelationshipType - */ - @autoserialize - @relationship(ItemType, false) - rightType: string; - - /** - * The universally unique identifier of this RelationshipType - */ - @autoserializeAs(new IDToUUIDSerializer(RelationshipType.type.value), 'id') - uuid: string; -} diff --git a/src/app/core/cache/models/items/normalized-relationship.model.ts b/src/app/core/cache/models/items/normalized-relationship.model.ts deleted file mode 100644 index 1c1dcf8d5b..0000000000 --- a/src/app/core/cache/models/items/normalized-relationship.model.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { autoserialize, deserialize, deserializeAs, inheritSerialization } from 'cerialize'; -import { Relationship } from '../../../shared/item-relationships/relationship.model'; -import { mapsTo, relationship } from '../../builders/build-decorators'; -import { NormalizedObject } from '../normalized-object.model'; -import { IDToUUIDSerializer } from '../../id-to-uuid-serializer'; -import { RelationshipType } from '../../../shared/item-relationships/relationship-type.model'; -import { Item } from '../../../shared/item.model'; - -/** - * Normalized model class for a DSpace Relationship - */ -@mapsTo(Relationship) -@inheritSerialization(NormalizedObject) -export class NormalizedRelationship extends NormalizedObject { - - /** - * The identifier of this Relationship - */ - @deserialize - id: string; - - /** - * The item to the left of this relationship - */ - @deserialize - @relationship(Item, false) - leftItem: string; - - /** - * The item to the right of this relationship - */ - @deserialize - @relationship(Item, false) - rightItem: string; - - /** - * The place of the Item to the left side of this Relationship - */ - @autoserialize - leftPlace: number; - - /** - * The place of the Item to the right side of this Relationship - */ - @autoserialize - rightPlace: number; - - /** - * The name variant of the Item to the left side of this Relationship - */ - @autoserialize - leftwardValue: string; - - /** - * The name variant of the Item to the right side of this Relationship - */ - @autoserialize - rightwardValue: string; - - /** - * The type of Relationship - */ - @deserialize - @relationship(RelationshipType, false) - relationshipType: string; - - /** - * The universally unique identifier of this Relationship - */ - @deserializeAs(new IDToUUIDSerializer(Relationship.type.value), 'id') - uuid: string; -} diff --git a/src/app/core/cache/models/normalized-bitstream-format.model.ts b/src/app/core/cache/models/normalized-bitstream-format.model.ts deleted file mode 100644 index 2283ecb368..0000000000 --- a/src/app/core/cache/models/normalized-bitstream-format.model.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { BitstreamFormat } from '../../shared/bitstream-format.model'; - -import { mapsTo } from '../builders/build-decorators'; -import { IDToUUIDSerializer } from '../id-to-uuid-serializer'; -import { NormalizedObject } from './normalized-object.model'; -import { BitstreamFormatSupportLevel } from '../../shared/bitstream-format-support-level'; - -/** - * Normalized model class for a Bitstream Format - */ -@mapsTo(BitstreamFormat) -@inheritSerialization(NormalizedObject) -export class NormalizedBitstreamFormat extends NormalizedObject { - /** - * Short description of this Bitstream Format - */ - @autoserialize - shortDescription: string; - - /** - * Description of this Bitstream Format - */ - @autoserialize - description: string; - - /** - * String representing the MIME type of this Bitstream Format - */ - @autoserialize - mimetype: string; - - /** - * The level of support the system offers for this Bitstream Format - */ - @autoserialize - supportLevel: BitstreamFormatSupportLevel; - - /** - * True if the Bitstream Format is used to store system information, rather than the content of items in the system - */ - @autoserialize - internal: boolean; - - /** - * String representing this Bitstream Format's file extension - */ - @autoserialize - extensions: string[]; - - /** - * Identifier for this Bitstream Format - * Note that this ID is unique for bitstream formats, - * but might not be unique across different object types - */ - @autoserialize - id: string; - - /** - * Universally unique identifier for this Bitstream Format - * Consist of a prefix and the id field to ensure the identifier is unique across all object types - */ - @autoserializeAs(new IDToUUIDSerializer('bitstream-format'), 'id') - uuid: string; -} diff --git a/src/app/core/cache/models/normalized-bitstream.model.ts b/src/app/core/cache/models/normalized-bitstream.model.ts deleted file mode 100644 index a9e389fd41..0000000000 --- a/src/app/core/cache/models/normalized-bitstream.model.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; - -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { Bitstream } from '../../shared/bitstream.model'; -import { mapsTo, relationship } from '../builders/build-decorators'; -import { Item } from '../../shared/item.model'; -import { BitstreamFormat } from '../../shared/bitstream-format.model'; - -/** - * Normalized model class for a DSpace Bitstream - */ -@mapsTo(Bitstream) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedBitstream extends NormalizedDSpaceObject { - /** - * The size of this bitstream in bytes - */ - @autoserialize - sizeBytes: number; - - /** - * The relative path to this Bitstream's file - */ - @autoserialize - content: string; - - /** - * The format of this Bitstream - */ - @autoserialize - @relationship(BitstreamFormat, false) - format: string; - - /** - * The description of this Bitstream - */ - @autoserialize - description: string; - - /** - * An array of Bundles that are direct parents of this Bitstream - */ - @autoserialize - @relationship(Item, true) - parents: string[]; - - /** - * The Bundle that owns this Bitstream - */ - @autoserialize - @relationship(Item, false) - owner: string; - - /** - * The name of the Bundle this Bitstream is part of - */ - @autoserialize - bundleName: string; - -} diff --git a/src/app/core/cache/models/normalized-bundle.model.ts b/src/app/core/cache/models/normalized-bundle.model.ts deleted file mode 100644 index 9582643efb..0000000000 --- a/src/app/core/cache/models/normalized-bundle.model.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; - -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { Bundle } from '../../shared/bundle.model'; -import { mapsTo, relationship } from '../builders/build-decorators'; -import { Bitstream } from '../../shared/bitstream.model'; - -/** - * Normalized model class for a DSpace Bundle - */ -@mapsTo(Bundle) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedBundle extends NormalizedDSpaceObject { - - /** - * The bundle's name - */ - @autoserialize - name: string; - - /** - * The primary bitstream of this Bundle - */ - @autoserialize - @relationship(Bitstream, false) - primaryBitstream: string; - - /** - * An array of Items that are direct parents of this Bundle - */ - parents: string[]; - - /** - * The Item that owns this Bundle - */ - owner: string; - - /** - * List of Bitstreams that are part of this Bundle - */ - @autoserialize - @relationship(Bitstream, true) - bitstreams: string[]; - -} diff --git a/src/app/core/cache/models/normalized-collection.model.ts b/src/app/core/cache/models/normalized-collection.model.ts deleted file mode 100644 index 9b3419675a..0000000000 --- a/src/app/core/cache/models/normalized-collection.model.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; - -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { Collection } from '../../shared/collection.model'; -import { mapsTo, relationship } from '../builders/build-decorators'; -import { NormalizedResourcePolicy } from './normalized-resource-policy.model'; -import { NormalizedBitstream } from './normalized-bitstream.model'; -import { NormalizedCommunity } from './normalized-community.model'; -import { NormalizedItem } from './normalized-item.model'; -import { License } from '../../shared/license.model'; -import { ResourcePolicy } from '../../shared/resource-policy.model'; -import { Bitstream } from '../../shared/bitstream.model'; -import { Community } from '../../shared/community.model'; -import { Item } from '../../shared/item.model'; - -/** - * Normalized model class for a DSpace Collection - */ -@mapsTo(Collection) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedCollection extends NormalizedDSpaceObject { - - /** - * A string representing the unique handle of this Collection - */ - @autoserialize - handle: string; - - /** - * The Bitstream that represents the license of this Collection - */ - @autoserialize - @relationship(License, false) - license: string; - - /** - * The Bitstream that represents the default Access Conditions of this Collection - */ - @autoserialize - @relationship(ResourcePolicy, false) - defaultAccessConditions: string; - - /** - * The Bitstream that represents the logo of this Collection - */ - @deserialize - @relationship(Bitstream, false) - logo: string; - - /** - * An array of Communities that are direct parents of this Collection - */ - @deserialize - @relationship(Community, true) - parents: string[]; - - /** - * The Community that owns this Collection - */ - @deserialize - @relationship(Community, false) - owner: string; - - /** - * List of Items that are part of (not necessarily owned by) this Collection - */ - @deserialize - @relationship(Item, true) - items: string[]; - -} diff --git a/src/app/core/cache/models/normalized-community.model.ts b/src/app/core/cache/models/normalized-community.model.ts deleted file mode 100644 index 173760ca72..0000000000 --- a/src/app/core/cache/models/normalized-community.model.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; - -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { Community } from '../../shared/community.model'; -import { mapsTo, relationship } from '../builders/build-decorators'; -import { ResourceType } from '../../shared/resource-type'; -import { NormalizedBitstream } from './normalized-bitstream.model'; -import { NormalizedCollection } from './normalized-collection.model'; -import { Bitstream } from '../../shared/bitstream.model'; -import { Collection } from '../../shared/collection.model'; - -/** - * Normalized model class for a DSpace Community - */ -@mapsTo(Community) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedCommunity extends NormalizedDSpaceObject { - /** - * A string representing the unique handle of this Community - */ - @autoserialize - handle: string; - - /** - * The Bitstream that represents the logo of this Community - */ - @deserialize - @relationship(Bitstream, false) - logo: string; - - /** - * An array of Communities that are direct parents of this Community - */ - @deserialize - @relationship(Community, true) - parents: string[]; - - /** - * The Community that owns this Community - */ - @deserialize - @relationship(Community, false) - owner: string; - - /** - * List of Collections that are owned by this Community - */ - @deserialize - @relationship(Collection, true) - collections: string[]; - - @deserialize - @relationship(Community, true) - subcommunities: string[]; - -} diff --git a/src/app/core/cache/models/normalized-dspace-object.model.ts b/src/app/core/cache/models/normalized-dspace-object.model.ts deleted file mode 100644 index 3c43dd85dc..0000000000 --- a/src/app/core/cache/models/normalized-dspace-object.model.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { autoserializeAs, deserializeAs, autoserialize } from 'cerialize'; -import { DSpaceObject } from '../../shared/dspace-object.model'; -import { MetadataMap, MetadataMapSerializer } from '../../shared/metadata.models'; -import { mapsTo } from '../builders/build-decorators'; -import { NormalizedObject } from './normalized-object.model'; -import { TypedObject } from '../object-cache.reducer'; - -/** - * An model class for a DSpaceObject. - */ -@mapsTo(DSpaceObject) -export class NormalizedDSpaceObject extends NormalizedObject implements TypedObject { - - /** - * The link to the rest endpoint where this object can be found - * - * Repeated here to make the serialization work, - * inheritSerialization doesn't seem to work for more than one level - */ - @deserializeAs(String) - self: string; - - /** - * The human-readable identifier of this DSpaceObject - * - * Currently mapped to uuid but left in to leave room - * for a shorter, more user friendly type of id - */ - @autoserializeAs(String, 'uuid') - id: string; - - /** - * The universally unique identifier of this DSpaceObject - */ - @autoserializeAs(String) - uuid: string; - - /** - * A string representing the kind of DSpaceObject, e.g. community, item, … - */ - @autoserialize - type: string; - - /** - * All metadata of this DSpaceObject - */ - @autoserializeAs(MetadataMapSerializer) - metadata: MetadataMap; - - /** - * An array of DSpaceObjects that are direct parents of this DSpaceObject - */ - @deserializeAs(String) - parents: string[]; - - /** - * The DSpaceObject that owns this DSpaceObject - */ - @deserializeAs(String) - owner: string; - - /** - * The links to all related resources returned by the rest api. - * - * Repeated here to make the serialization work, - * inheritSerialization doesn't seem to work for more than one level - */ - @deserializeAs(Object) - _links: { - [name: string]: string - } -} diff --git a/src/app/core/cache/models/normalized-external-source-entry.model.ts b/src/app/core/cache/models/normalized-external-source-entry.model.ts deleted file mode 100644 index de262949e7..0000000000 --- a/src/app/core/cache/models/normalized-external-source-entry.model.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { NormalizedObject } from './normalized-object.model'; -import { ExternalSourceEntry } from '../../shared/external-source-entry.model'; -import { mapsTo } from '../builders/build-decorators'; -import { MetadataMap, MetadataMapSerializer } from '../../shared/metadata.models'; - -/** - * Normalized model class for an external source entry - */ -@mapsTo(ExternalSourceEntry) -@inheritSerialization(NormalizedObject) -export class NormalizedExternalSourceEntry extends NormalizedObject { - /** - * Unique identifier - */ - @autoserialize - id: string; - - /** - * The value to display - */ - @autoserialize - display: string; - - /** - * The value to store the entry with - */ - @autoserialize - value: string; - - /** - * The ID of the external source this entry originates from - */ - @autoserialize - externalSource: string; - - /** - * Metadata of the entry - */ - @autoserializeAs(MetadataMapSerializer) - metadata: MetadataMap; -} diff --git a/src/app/core/cache/models/normalized-external-source.model.ts b/src/app/core/cache/models/normalized-external-source.model.ts deleted file mode 100644 index fd9a42fb72..0000000000 --- a/src/app/core/cache/models/normalized-external-source.model.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { NormalizedObject } from './normalized-object.model'; -import { ExternalSource } from '../../shared/external-source.model'; -import { mapsTo } from '../builders/build-decorators'; - -/** - * Normalized model class for an external source - */ -@mapsTo(ExternalSource) -@inheritSerialization(NormalizedObject) -export class NormalizedExternalSource extends NormalizedObject { - /** - * Unique identifier - */ - @autoserialize - id: string; - - /** - * The name of this external source - */ - @autoserialize - name: string; - - /** - * Is the source hierarchical? - */ - @autoserialize - hierarchical: boolean; -} diff --git a/src/app/core/cache/models/normalized-item.model.ts b/src/app/core/cache/models/normalized-item.model.ts deleted file mode 100644 index 9b7edf70c0..0000000000 --- a/src/app/core/cache/models/normalized-item.model.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { inheritSerialization, deserialize, autoserialize, autoserializeAs } from 'cerialize'; - -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { Item } from '../../shared/item.model'; -import { mapsTo, relationship } from '../builders/build-decorators'; -import { Collection } from '../../shared/collection.model'; -import { Relationship } from '../../shared/item-relationships/relationship.model'; -import { Bundle } from '../../shared/bundle.model'; - -/** - * Normalized model class for a DSpace Item - */ -@mapsTo(Item) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedItem extends NormalizedDSpaceObject { - - /** - * A string representing the unique handle of this Item - */ - @autoserialize - handle: string; - - /** - * The Date of the last modification of this Item - */ - @deserialize - lastModified: Date; - - /** - * A boolean representing if this Item is currently archived or not - */ - @autoserializeAs(Boolean, 'inArchive') - isArchived: boolean; - - /** - * A boolean representing if this Item is currently discoverable or not - */ - @autoserializeAs(Boolean, 'discoverable') - isDiscoverable: boolean; - - /** - * A boolean representing if this Item is currently withdrawn or not - */ - @autoserializeAs(Boolean, 'withdrawn') - isWithdrawn: boolean; - - /** - * An array of Collections that are direct parents of this Item - */ - @deserialize - @relationship(Collection, true) - parents: string[]; - - /** - * The Collection that owns this Item - */ - @deserialize - @relationship(Collection, false) - owningCollection: string; - - /** - * List of Bitstreams that are owned by this Item - */ - @deserialize - @relationship(Bundle, true) - bundles: string[]; - - @deserialize - @relationship(Relationship, true) - relationships: string[]; - -} diff --git a/src/app/core/cache/models/normalized-license.model.ts b/src/app/core/cache/models/normalized-license.model.ts deleted file mode 100644 index 02bd1808c8..0000000000 --- a/src/app/core/cache/models/normalized-license.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { mapsTo } from '../builders/build-decorators'; -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { License } from '../../shared/license.model'; - -/** - * Normalized model class for a Collection License - */ -@mapsTo(License) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedLicense extends NormalizedDSpaceObject { - - /** - * A boolean representing if this License is custom or not - */ - @autoserialize - custom: boolean; - - /** - * The text of the license - */ - @autoserialize - text: string; -} diff --git a/src/app/core/cache/models/normalized-object.model.ts b/src/app/core/cache/models/normalized-object.model.ts deleted file mode 100644 index 8a3aed32c9..0000000000 --- a/src/app/core/cache/models/normalized-object.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { CacheableObject, TypedObject } from '../object-cache.reducer'; -import { autoserialize, deserialize } from 'cerialize'; -import { ResourceType } from '../../shared/resource-type'; -/** - * An abstract model class for a NormalizedObject. - */ -export abstract class NormalizedObject implements CacheableObject { - /** - * The link to the rest endpoint where this object can be found - */ - @deserialize - self: string; - - @deserialize - _links: { - [name: string]: string - }; - - /** - * A string representing the kind of object - */ - @deserialize - type: string; -} diff --git a/src/app/core/cache/models/normalized-resource-policy.model.ts b/src/app/core/cache/models/normalized-resource-policy.model.ts deleted file mode 100644 index cd25a0af05..0000000000 --- a/src/app/core/cache/models/normalized-resource-policy.model.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { ResourcePolicy } from '../../shared/resource-policy.model'; - -import { mapsTo } from '../builders/build-decorators'; -import { NormalizedObject } from './normalized-object.model'; -import { IDToUUIDSerializer } from '../id-to-uuid-serializer'; -import { ActionType } from './action-type.model'; - -/** - * Normalized model class for a Resource Policy - */ -@mapsTo(ResourcePolicy) -@inheritSerialization(NormalizedObject) -export class NormalizedResourcePolicy extends NormalizedObject { - /** - * The action that is allowed by this Resource Policy - */ - @autoserialize - action: ActionType; - - /** - * The name for this Resource Policy - */ - @autoserialize - name: string; - - /** - * The uuid of the Group this Resource Policy applies to - */ - @autoserialize - groupUUID: string; - - /** - * Identifier for this Resource Policy - * Note that this ID is unique for resource policies, - * but might not be unique across different object types - */ - @autoserialize - id: string; - - /** - * The universally unique identifier for this Resource Policy - * Consist of a prefix and the id field to ensure the identifier is unique across all object types - */ - @autoserializeAs(new IDToUUIDSerializer('resource-policy'), 'id') - uuid: string; - -} diff --git a/src/app/core/cache/models/normalized-site.model.ts b/src/app/core/cache/models/normalized-site.model.ts deleted file mode 100644 index 68a7e0a480..0000000000 --- a/src/app/core/cache/models/normalized-site.model.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { inheritSerialization } from 'cerialize'; -import { NormalizedDSpaceObject } from './normalized-dspace-object.model'; -import { mapsTo } from '../builders/build-decorators'; -import { Site } from '../../shared/site.model'; - -/** - * Normalized model class for a Site object - */ -@mapsTo(Site) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedSite extends NormalizedDSpaceObject { - -} diff --git a/src/app/core/cache/object-cache.reducer.spec.ts b/src/app/core/cache/object-cache.reducer.spec.ts index a65e63ab86..6519e887c9 100644 --- a/src/app/core/cache/object-cache.reducer.spec.ts +++ b/src/app/core/cache/object-cache.reducer.spec.ts @@ -1,6 +1,6 @@ import * as deepFreeze from 'deep-freeze'; - -import { objectCacheReducer } from './object-cache.reducer'; +import { Operation } from 'fast-json-patch'; +import { Item } from '../shared/item.model'; import { AddPatchObjectCacheAction, AddToObjectCacheAction, @@ -8,8 +8,8 @@ import { RemoveFromObjectCacheAction, ResetObjectCacheTimestampsAction } from './object-cache.actions'; -import { Operation } from 'fast-json-patch'; -import { Item } from '../shared/item.model'; + +import { objectCacheReducer } from './object-cache.reducer'; class NullAction extends RemoveFromObjectCacheAction { type = null; @@ -31,19 +31,21 @@ describe('objectCacheReducer', () => { data: { type: Item.type, self: selfLink1, - foo: 'bar' + foo: 'bar', + _links: { self: { href: selfLink1 } } }, timeAdded: new Date().getTime(), msToLive: 900000, requestUUID: requestUUID1, patches: [], - isDirty: false + isDirty: false, }, [selfLink2]: { data: { type: Item.type, self: requestUUID2, - foo: 'baz' + foo: 'baz', + _links: { self: { href: requestUUID2 } } }, timeAdded: new Date().getTime(), msToLive: 900000, @@ -70,7 +72,7 @@ describe('objectCacheReducer', () => { it('should add the payload to the cache in response to an ADD action', () => { const state = Object.create(null); - const objectToCache = { self: selfLink1, type: Item.type }; + const objectToCache = { self: selfLink1, type: Item.type, _links: { self: { href: selfLink1 } } }; const timeAdded = new Date().getTime(); const msToLive = 900000; const requestUUID = requestUUID1; @@ -87,7 +89,8 @@ describe('objectCacheReducer', () => { self: selfLink1, foo: 'baz', somethingElse: true, - type: Item.type + type: Item.type, + _links: { self: { href: selfLink1 } } }; const timeAdded = new Date().getTime(); const msToLive = 900000; @@ -103,7 +106,7 @@ describe('objectCacheReducer', () => { it('should perform the ADD action without affecting the previous state', () => { const state = Object.create(null); - const objectToCache = { self: selfLink1, type: Item.type }; + const objectToCache = { self: selfLink1, type: Item.type, _links: { self: { href: selfLink1 } } }; const timeAdded = new Date().getTime(); const msToLive = 900000; const requestUUID = requestUUID1; @@ -121,8 +124,8 @@ describe('objectCacheReducer', () => { expect(newState[selfLink1]).toBeUndefined(); }); - it("shouldn't do anything in response to the REMOVE action for an object that isn't cached", () => { - const wrongKey = "this isn't cached"; + it('shouldn\'t do anything in response to the REMOVE action for an object that isn\'t cached', () => { + const wrongKey = 'this isn\'t cached'; const action = new RemoveFromObjectCacheAction(wrongKey); const newState = objectCacheReducer(testState, action); diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts index afc040bf59..a39ceb4e16 100644 --- a/src/app/core/cache/object-cache.reducer.ts +++ b/src/app/core/cache/object-cache.reducer.ts @@ -1,3 +1,7 @@ +import { autoserialize, deserialize } from 'cerialize'; +import { HALLink } from '../shared/hal-link.model'; +import { HALResource } from '../shared/hal-resource.model'; +import { excludeFromEquals } from '../utilities/equals.decorators'; import { ObjectCacheAction, ObjectCacheActionTypes, @@ -34,6 +38,7 @@ export interface Patch { export abstract class TypedObject { static type: ResourceType; + type: ResourceType; } /* tslint:disable:max-classes-per-file */ @@ -42,10 +47,13 @@ export abstract class TypedObject { * * A cacheable object should have a self link */ -export class CacheableObject extends TypedObject { +export class CacheableObject extends TypedObject implements HALResource { uuid?: string; handle?: string; - self: string; + + _links: { + self: HALLink; + } // isNew: boolean; // dirtyType: DirtyType; // hasDirtyAttributes: boolean; @@ -129,9 +137,9 @@ export function objectCacheReducer(state = initialState, action: ObjectCacheActi * the new state, with the object added, or overwritten. */ function addToObjectCache(state: ObjectCacheState, action: AddToObjectCacheAction): ObjectCacheState { - const existing = state[action.payload.objectToCache.self]; + const existing = state[action.payload.objectToCache._links.self.href]; return Object.assign({}, state, { - [action.payload.objectToCache.self]: { + [action.payload.objectToCache._links.self.href]: { data: action.payload.objectToCache, timeAdded: action.payload.timeAdded, msToLive: action.payload.msToLive, diff --git a/src/app/core/cache/object-cache.service.spec.ts b/src/app/core/cache/object-cache.service.spec.ts index 39dc10de2c..e7c208e095 100644 --- a/src/app/core/cache/object-cache.service.spec.ts +++ b/src/app/core/cache/object-cache.service.spec.ts @@ -1,34 +1,36 @@ import * as ngrx from '@ngrx/store'; import { Store } from '@ngrx/store'; +import { Operation } from 'fast-json-patch'; import { of as observableOf } from 'rxjs'; - -import { ObjectCacheService } from './object-cache.service'; +import { first } from 'rxjs/operators'; +import { CoreState } from '../core.reducers'; +import { RestRequestMethod } from '../data/rest-request-method'; +import { Item } from '../shared/item.model'; import { AddPatchObjectCacheAction, AddToObjectCacheAction, ApplyPatchObjectCacheAction, RemoveFromObjectCacheAction } from './object-cache.actions'; -import { CoreState } from '../core.reducers'; -import { NormalizedItem } from './models/normalized-item.model'; -import { first } from 'rxjs/operators'; -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'; -import { Item } from '../shared/item.model'; + +import { ObjectCacheService } from './object-cache.service'; +import { AddToSSBAction } from './server-sync-buffer.actions'; describe('ObjectCacheService', () => { let service: ObjectCacheService; let store: Store; + let linkServiceStub; const selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; const requestUUID = '4d3a4ce8-a375-4b98-859b-39f0a014d736'; const timestamp = new Date().getTime(); const msToLive = 900000; let objectToCache = { - self: selfLink, - type: Item.type + type: Item.type, + _links: { + self: { href: selfLink } + } }; let cacheEntry; let invalidCacheEntry; @@ -36,8 +38,10 @@ describe('ObjectCacheService', () => { function init() { objectToCache = { - self: selfLink, - type: Item.type + type: Item.type, + _links: { + self: { href: selfLink } + } }; cacheEntry = { data: objectToCache, @@ -50,8 +54,12 @@ describe('ObjectCacheService', () => { beforeEach(() => { init(); store = new Store(undefined, undefined, undefined); + linkServiceStub = { + removeResolvedLinks: (a) => a + }; + spyOn(linkServiceStub, 'removeResolvedLinks').and.callThrough(); spyOn(store, 'dispatch'); - service = new ObjectCacheService(store); + service = new ObjectCacheService(store, linkServiceStub); spyOn(Date.prototype, 'getTime').and.callFake(() => { return timestamp; @@ -62,6 +70,7 @@ describe('ObjectCacheService', () => { it('should dispatch an ADD action with the object to add, the time to live, and the current timestamp', () => { service.add(objectToCache, msToLive, requestUUID); expect(store.dispatch).toHaveBeenCalledWith(new AddToObjectCacheAction(objectToCache, timestamp, msToLive, requestUUID)); + expect(linkServiceStub.removeResolvedLinks).toHaveBeenCalledWith(objectToCache); }); }); @@ -82,9 +91,9 @@ describe('ObjectCacheService', () => { // due to the implementation of spyOn above, this subscribe will be synchronous service.getObjectBySelfLink(selfLink).pipe(first()).subscribe((o) => { - expect(o.self).toBe(selfLink); + expect(o._links.self.href).toBe(selfLink); // this only works if testObj is an instance of TestClass - expect(o instanceof NormalizedItem).toBeTruthy(); + expect(o instanceof Item).toBeTruthy(); } ); }); @@ -105,13 +114,14 @@ describe('ObjectCacheService', () => { describe('getList', () => { it('should return an observable of the array of cached objects with the specified self link and type', () => { - const item = new NormalizedItem(); - item.self = selfLink; + const item = Object.assign(new Item(), { + _links: { self: { href: selfLink } } + }); spyOn(service, 'getObjectBySelfLink').and.returnValue(observableOf(item)); service.getList([selfLink, selfLink]).pipe(first()).subscribe((arr) => { - expect(arr[0].self).toBe(selfLink); - expect(arr[0] instanceof NormalizedItem).toBeTruthy(); + expect(arr[0]._links.self.href).toBe(selfLink); + expect(arr[0] instanceof Item).toBeTruthy(); }); }); }); @@ -127,7 +137,7 @@ describe('ObjectCacheService', () => { expect(service.hasBySelfLink(selfLink)).toBe(true); }); - it("should return false if the object with the supplied self link isn't cached", () => { + it('should return false if the object with the supplied self link isn\'t cached', () => { spyOnProperty(ngrx, 'select').and.callFake(() => { return () => { return () => observableOf(undefined); diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index 8d4e910471..53894df5f1 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -10,7 +10,7 @@ import { coreSelector } from '../core.selectors'; import { RestRequestMethod } from '../data/rest-request-method'; import { selfLinkFromUuidSelector } from '../index/index.selectors'; import { GenericConstructor } from '../shared/generic-constructor'; -import { NormalizedObject } from './models/normalized-object.model'; +import { LinkService } from './builders/link.service'; import { AddPatchObjectCacheAction, AddToObjectCacheAction, @@ -20,7 +20,7 @@ import { import { CacheableObject, ObjectCacheEntry, ObjectCacheState } from './object-cache.reducer'; import { AddToSSBAction } from './server-sync-buffer.actions'; -import { getMapsToType } from './builders/build-decorators'; +import { getClassForType } from './builders/build-decorators'; /** * The base selector function to select the object cache in the store @@ -45,21 +45,25 @@ const entryFromSelfLinkSelector = */ @Injectable() export class ObjectCacheService { - constructor(private store: Store) { + constructor( + private store: Store, + private linkService: LinkService + ) { } /** * Add an object to the cache * - * @param objectToCache + * @param object * The object to add * @param msToLive * The number of milliseconds it should be cached for * @param requestUUID * The UUID of the request that resulted in this object */ - add(objectToCache: CacheableObject, msToLive: number, requestUUID: string): void { - this.store.dispatch(new AddToObjectCacheAction(objectToCache, new Date().getTime(), msToLive, requestUUID)); + add(object: CacheableObject, msToLive: number, requestUUID: string): void { + object = this.linkService.removeResolvedLinks(object); // Ensure the object we're storing has no resolved links + this.store.dispatch(new AddToObjectCacheAction(object, new Date().getTime(), msToLive, requestUUID)); } /** @@ -77,14 +81,14 @@ export class ObjectCacheService { * * @param uuid * The UUID of the object to get - * @return Observable> - * An observable of the requested object in normalized form + * @return Observable + * An observable of the requested object */ getObjectByUUID(uuid: string): - Observable> { + Observable { return this.store.pipe( select(selfLinkFromUuidSelector(uuid)), - mergeMap((selfLink: string) => this.getObjectBySelfLink(selfLink) + mergeMap((selfLink: string) => this.getObjectBySelfLink(selfLink) ) ) } @@ -94,10 +98,10 @@ export class ObjectCacheService { * * @param selfLink * The selfLink of the object to get - * @return Observable> - * An observable of the requested object in normalized form + * @return Observable + * An observable of the requested object */ - getObjectBySelfLink(selfLink: string): Observable> { + getObjectBySelfLink(selfLink: string): Observable { return this.getBySelfLink(selfLink).pipe( map((entry: ObjectCacheEntry) => { if (isNotEmpty(entry.patches)) { @@ -110,8 +114,11 @@ export class ObjectCacheService { } ), map((entry: ObjectCacheEntry) => { - const type: GenericConstructor> = getMapsToType((entry.data as any).type); - return Object.assign(new type(), entry.data) as NormalizedObject + const type: GenericConstructor = getClassForType((entry.data as any).type); + if (typeof type !== 'function') { + throw new Error(`${type} is not a valid constructor for ${JSON.stringify(entry.data)}`); + } + return Object.assign(new type(), entry.data) as T }) ); } @@ -180,7 +187,7 @@ export class ObjectCacheService { * The type of the objects to get * @return Observable> */ - getList(selfLinks: string[]): Observable>> { + getList(selfLinks: string[]): Observable { return observableCombineLatest( selfLinks.map((selfLink: string) => this.getObjectBySelfLink(selfLink)) ); @@ -254,7 +261,7 @@ export class ObjectCacheService { const timeOutdated = entry.timeAdded + entry.msToLive; const isOutDated = new Date().getTime() > timeOutdated; if (isOutDated) { - this.store.dispatch(new RemoveFromObjectCacheAction(entry.data.self)); + this.store.dispatch(new RemoveFromObjectCacheAction(entry.data._links.self.href)); } return !isOutDated; } diff --git a/src/app/core/cache/response.models.ts b/src/app/core/cache/response.models.ts index 5f4e15e138..3f46ecf647 100644 --- a/src/app/core/cache/response.models.ts +++ b/src/app/core/cache/response.models.ts @@ -1,4 +1,5 @@ import { SearchQueryResponse } from '../../shared/search/search-query-response.model'; +import { AuthStatus } from '../auth/models/auth-status.model'; import { RequestError } from '../data/request.models'; import { PageInfo } from '../shared/page-info.model'; import { ConfigObject } from '../config/models/config.model'; @@ -11,7 +12,6 @@ import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstream import { PaginatedList } from '../data/paginated-list'; import { SubmissionObject } from '../submission/models/submission-object.model'; import { DSpaceObject } from '../shared/dspace-object.model'; -import { NormalizedAuthStatus } from '../auth/models/normalized-auth-status.model'; import { MetadataSchema } from '../metadata/metadata-schema.model'; import { MetadataField } from '../metadata/metadata-field.model'; import { ContentSource } from '../shared/content-source.model'; @@ -203,7 +203,7 @@ export class AuthStatusResponse extends RestResponse { public toCache = false; constructor( - public response: NormalizedAuthStatus, + public response: AuthStatus, public statusCode: number, public statusText: string, ) { diff --git a/src/app/core/cache/server-sync-buffer.effects.spec.ts b/src/app/core/cache/server-sync-buffer.effects.spec.ts index 773e0ab60c..37ad0e6346 100644 --- a/src/app/core/cache/server-sync-buffer.effects.spec.ts +++ b/src/app/core/cache/server-sync-buffer.effects.spec.ts @@ -1,22 +1,22 @@ import { TestBed } from '@angular/core/testing'; - -import { Observable, of as observableOf } from 'rxjs'; import { provideMockActions } from '@ngrx/effects/testing'; +import { Store, StoreModule } from '@ngrx/store'; import { cold, hot } from 'jasmine-marbles'; -import { ServerSyncBufferEffects } from './server-sync-buffer.effects'; -import { GLOBAL_CONFIG } from '../../../config'; -import { CommitSSBAction, EmptySSBAction, ServerSyncBufferActionTypes } from './server-sync-buffer.actions'; -import { RestRequestMethod } from '../data/rest-request-method'; -import { Store, StoreModule } from '@ngrx/store'; -import { RequestService } from '../data/request.service'; -import { ObjectCacheService } from './object-cache.service'; -import { MockStore } from '../../shared/testing/mock-store'; +import { Observable, of as observableOf } from 'rxjs'; import * as operators from 'rxjs/operators'; -import { spyOnOperator } from '../../shared/testing/utils'; -import { DSpaceObject } from '../shared/dspace-object.model'; +import { GLOBAL_CONFIG } from '../../../config'; import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { MockStore } from '../../shared/testing/mock-store'; +import { spyOnOperator } from '../../shared/testing/utils'; +import { RequestService } from '../data/request.service'; +import { RestRequestMethod } from '../data/rest-request-method'; +import { DSpaceObject } from '../shared/dspace-object.model'; import { ApplyPatchObjectCacheAction } from './object-cache.actions'; +import { ObjectCacheService } from './object-cache.service'; +import { CommitSSBAction, EmptySSBAction, ServerSyncBufferActionTypes } from './server-sync-buffer.actions'; + +import { ServerSyncBufferEffects } from './server-sync-buffer.effects'; describe('ServerSyncBufferEffects', () => { let ssbEffects: ServerSyncBufferEffects; @@ -47,8 +47,9 @@ describe('ServerSyncBufferEffects', () => { { provide: ObjectCacheService, useValue: { getObjectBySelfLink: (link) => { - const object = new DSpaceObject(); - object.self = link; + const object = Object.assign(new DSpaceObject(), { + _links: { self: { href: link } } + }); return observableOf(object); } } diff --git a/src/app/core/cache/server-sync-buffer.effects.ts b/src/app/core/cache/server-sync-buffer.effects.ts index 3aa6ad312f..3a0e801f27 100644 --- a/src/app/core/cache/server-sync-buffer.effects.ts +++ b/src/app/core/cache/server-sync-buffer.effects.ts @@ -2,6 +2,7 @@ import { delay, exhaustMap, map, switchMap, take } from 'rxjs/operators'; import { Inject, Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { coreSelector } from '../core.selectors'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { AddToSSBAction, CommitSSBAction, @@ -18,7 +19,6 @@ import { RequestService } from '../data/request.service'; import { PutRequest } from '../data/request.models'; import { ObjectCacheService } from './object-cache.service'; import { ApplyPatchObjectCacheAction } from './object-cache.actions'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; import { GenericConstructor } from '../shared/generic-constructor'; import { hasValue, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; import { Observable } from 'rxjs/internal/Observable'; @@ -100,7 +100,7 @@ export class ServerSyncBufferEffects { return patchObject.pipe( map((object) => { - const serializedObject = new DSpaceRESTv2Serializer(object.constructor as GenericConstructor<{}>).serialize(object); + const serializedObject = new DSpaceSerializer(object.constructor as GenericConstructor<{}>).serialize(object); this.requestService.configure(new PutRequest(this.requestService.generateRequestId(), href, serializedObject)); diff --git a/src/app/core/config/config-response-parsing.service.spec.ts b/src/app/core/config/config-response-parsing.service.spec.ts index 90dd1670b8..87a7057078 100644 --- a/src/app/core/config/config-response-parsing.service.spec.ts +++ b/src/app/core/config/config-response-parsing.service.spec.ts @@ -1,22 +1,21 @@ -import { ConfigSuccessResponse, ErrorResponse } from '../cache/response.models'; -import { ConfigResponseParsingService } from './config-response-parsing.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { GlobalConfig } from '../../../config/global-config.interface'; -import { ConfigRequest } from '../data/request.models'; - import { Store } from '@ngrx/store'; +import { GlobalConfig } from '../../../config/global-config.interface'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { ConfigSuccessResponse, ErrorResponse } from '../cache/response.models'; import { CoreState } from '../core.reducers'; import { PaginatedList } from '../data/paginated-list'; +import { ConfigRequest } from '../data/request.models'; import { PageInfo } from '../shared/page-info.model'; -import { NormalizedSubmissionSectionModel } from './models/normalized-config-submission-section.model'; -import { NormalizedSubmissionDefinitionModel } from './models/normalized-config-submission-definition.model'; +import { ConfigResponseParsingService } from './config-response-parsing.service'; +import { SubmissionDefinitionModel } from './models/config-submission-definition.model'; +import { SubmissionSectionModel } from './models/config-submission-section.model'; describe('ConfigResponseParsingService', () => { let service: ConfigResponseParsingService; const EnvConfig = {} as GlobalConfig; const store = {} as Store; - const objectCacheService = new ObjectCacheService(store); + const objectCacheService = new ObjectCacheService(store, undefined); let validResponse; beforeEach(() => { service = new ConfigResponseParsingService(EnvConfig, objectCacheService); @@ -150,7 +149,7 @@ describe('ConfigResponseParsingService', () => { }, _embedded: [{}, {}], _links: { - self: 'https://rest.api/config/submissiondefinitions/traditional/sections' + self: { href: 'https://rest.api/config/submissiondefinitions/traditional/sections' } } } } @@ -170,77 +169,76 @@ describe('ConfigResponseParsingService', () => { totalElements: 4, totalPages: 1, currentPage: 1, - self: 'https://rest.api/config/submissiondefinitions/traditional/sections' + _links: { + self: { + href: 'https://rest.api/config/submissiondefinitions/traditional/sections' + }, + }, }); const definitions = - Object.assign(new NormalizedSubmissionDefinitionModel(), { + Object.assign(new SubmissionDefinitionModel(), { isDefault: true, name: 'traditional', type: 'submissiondefinition', _links: { - sections: 'https://rest.api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/config/submissiondefinitions/traditional' + sections: { href: 'https://rest.api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/config/submissiondefinitions/traditional', sections: new PaginatedList(pageinfo, [ - Object.assign(new NormalizedSubmissionSectionModel(), { + Object.assign(new SubmissionSectionModel(), { header: 'submit.progressbar.describe.stepone', mandatory: true, sectionType: 'submission-form', - visibility:{ - main:null, - other:'READONLY' + visibility: { + main: null, + other: 'READONLY' }, type: 'submissionsection', _links: { - self: 'https://rest.api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/config/submissionsections/traditionalpageone', }), - Object.assign(new NormalizedSubmissionSectionModel(), { + Object.assign(new SubmissionSectionModel(), { header: 'submit.progressbar.describe.steptwo', mandatory: true, sectionType: 'submission-form', - visibility:{ - main:null, - other:'READONLY' + visibility: { + main: null, + other: 'READONLY' }, type: 'submissionsection', _links: { - self: 'https://rest.api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/config/submissionsections/traditionalpagetwo', }), - Object.assign(new NormalizedSubmissionSectionModel(), { + Object.assign(new SubmissionSectionModel(), { header: 'submit.progressbar.upload', mandatory: false, sectionType: 'upload', - visibility:{ - main:null, - other:'READONLY' + visibility: { + main: null, + other: 'READONLY' }, type: 'submissionsection', _links: { - self: 'https://rest.api/config/submissionsections/upload', - config: 'https://rest.api/config/submissionuploads/upload' + self: { href: 'https://rest.api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/config/submissionuploads/upload' } }, - self: 'https://rest.api/config/submissionsections/upload', }), - Object.assign(new NormalizedSubmissionSectionModel(), { + Object.assign(new SubmissionSectionModel(), { header: 'submit.progressbar.license', mandatory: true, sectionType: 'license', - visibility:{ - main:null, - other:'READONLY' + visibility: { + main: null, + other: 'READONLY' }, type: 'submissionsection', _links: { - self: 'https://rest.api/config/submissionsections/license' + self: { href: 'https://rest.api/config/submissionsections/license' } }, - self: 'https://rest.api/config/submissionsections/license', }) ]) }); diff --git a/src/app/core/config/config-response-parsing.service.ts b/src/app/core/config/config-response-parsing.service.ts index d1f49710d3..d674445d54 100644 --- a/src/app/core/config/config-response-parsing.service.ts +++ b/src/app/core/config/config-response-parsing.service.ts @@ -15,6 +15,7 @@ import { ObjectCacheService } from '../cache/object-cache.service'; @Injectable() export class ConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { protected toCache = false; + protected shouldDirectlyAttachEmbeds = true; constructor( @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, diff --git a/src/app/core/config/models/config-submission-definition.model.ts b/src/app/core/config/models/config-submission-definition.model.ts index 0449e6a964..f3e888d513 100644 --- a/src/app/core/config/models/config-submission-definition.model.ts +++ b/src/app/core/config/models/config-submission-definition.model.ts @@ -1,22 +1,40 @@ -import { ConfigObject } from './config.model'; -import { SubmissionSectionModel } from './config-submission-section.model'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { PaginatedList } from '../../data/paginated-list'; +import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; +import { SubmissionSectionModel } from './config-submission-section.model'; +import { ConfigObject } from './config.model'; /** * Class for the configuration describing the submission */ +@typedObject +@inheritSerialization(ConfigObject) export class SubmissionDefinitionModel extends ConfigObject { static type = new ResourceType('submissiondefinition'); /** * A boolean representing if this submission definition is the default or not */ + @autoserialize isDefault: boolean; /** * A list of SubmissionSectionModel that are present in this submission definition */ + // TODO refactor using remotedata + @deserialize sections: PaginatedList; + /** + * The links to all related resources returned by the rest api. + */ + @deserialize + _links: { + self: HALLink, + collections: HALLink, + sections: HALLink + }; + } diff --git a/src/app/core/config/models/config-submission-definitions.model.ts b/src/app/core/config/models/config-submission-definitions.model.ts index d9892f542f..1fdf571806 100644 --- a/src/app/core/config/models/config-submission-definitions.model.ts +++ b/src/app/core/config/models/config-submission-definitions.model.ts @@ -1,6 +1,10 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { SubmissionDefinitionModel } from './config-submission-definition.model'; import { ResourceType } from '../../shared/resource-type'; +@typedObject +@inheritSerialization(SubmissionDefinitionModel) export class SubmissionDefinitionsModel extends SubmissionDefinitionModel { static type = new ResourceType('submissiondefinitions'); diff --git a/src/app/core/config/models/config-submission-form.model.ts b/src/app/core/config/models/config-submission-form.model.ts index a65d285c95..d3fcfa9738 100644 --- a/src/app/core/config/models/config-submission-form.model.ts +++ b/src/app/core/config/models/config-submission-form.model.ts @@ -1,3 +1,5 @@ +import { autoserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { ConfigObject } from './config.model'; import { FormFieldModel } from '../../../shared/form/builder/models/form-field.model'; import { ResourceType } from '../../shared/resource-type'; @@ -12,11 +14,14 @@ export interface FormRowModel { /** * A model class for a NormalizedObject. */ +@typedObject +@inheritSerialization(ConfigObject) export class SubmissionFormModel extends ConfigObject { static type = new ResourceType('submissionform'); /** * An array of [FormRowModel] that are present in this form */ + @autoserialize rows: FormRowModel[]; } diff --git a/src/app/core/config/models/config-submission-forms.model.ts b/src/app/core/config/models/config-submission-forms.model.ts index 017d7d68cc..8130bf3264 100644 --- a/src/app/core/config/models/config-submission-forms.model.ts +++ b/src/app/core/config/models/config-submission-forms.model.ts @@ -1,9 +1,13 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { SubmissionFormModel } from './config-submission-form.model'; import { ResourceType } from '../../shared/resource-type'; /** * A model class for a NormalizedObject. */ +@typedObject +@inheritSerialization(SubmissionFormModel) export class SubmissionFormsModel extends SubmissionFormModel { static type = new ResourceType('submissionforms'); } diff --git a/src/app/core/config/models/config-submission-section.model.ts b/src/app/core/config/models/config-submission-section.model.ts index 4c560fa631..d8249297b1 100644 --- a/src/app/core/config/models/config-submission-section.model.ts +++ b/src/app/core/config/models/config-submission-section.model.ts @@ -1,6 +1,9 @@ -import { ConfigObject } from './config.model'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { SectionsType } from '../../../submission/sections/sections-type'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; +import { ConfigObject } from './config.model'; /** * An interface that define section visibility and its properties. @@ -10,27 +13,42 @@ export interface SubmissionSectionVisibility { other: any } +@typedObject +@inheritSerialization(ConfigObject) export class SubmissionSectionModel extends ConfigObject { static type = new ResourceType('submissionsection'); /** * The header for this section */ + @autoserialize header: string; /** * A boolean representing if this submission section is the mandatory or not */ + @autoserialize mandatory: boolean; /** * A string representing the kind of section object */ + @autoserialize sectionType: SectionsType; /** * The [SubmissionSectionVisibility] object for this section */ - visibility: SubmissionSectionVisibility + @autoserialize + visibility: SubmissionSectionVisibility; + + /** + * The {@link HALLink}s for this SubmissionSectionModel + */ + @deserialize + _links: { + self: HALLink; + config: HALLink; + } } diff --git a/src/app/core/config/models/config-submission-sections.model.ts b/src/app/core/config/models/config-submission-sections.model.ts index ae7b133391..7f78712273 100644 --- a/src/app/core/config/models/config-submission-sections.model.ts +++ b/src/app/core/config/models/config-submission-sections.model.ts @@ -1,6 +1,10 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { SubmissionSectionModel } from './config-submission-section.model'; import { ResourceType } from '../../shared/resource-type'; +@typedObject +@inheritSerialization(SubmissionSectionModel) export class SubmissionSectionsModel extends SubmissionSectionModel { static type = new ResourceType('submissionsections'); } diff --git a/src/app/core/config/models/config-submission-uploads.model.ts b/src/app/core/config/models/config-submission-uploads.model.ts index 812a590041..b7733ee25d 100644 --- a/src/app/core/config/models/config-submission-uploads.model.ts +++ b/src/app/core/config/models/config-submission-uploads.model.ts @@ -1,22 +1,30 @@ +import { autoserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; import { ConfigObject } from './config.model'; import { AccessConditionOption } from './config-access-condition-option.model'; import { SubmissionFormsModel } from './config-submission-forms.model'; import { ResourceType } from '../../shared/resource-type'; +@typedObject +@inheritSerialization(ConfigObject) export class SubmissionUploadsModel extends ConfigObject { static type = new ResourceType('submissionupload'); /** * A list of available bitstream access conditions */ + @autoserialize accessConditionOptions: AccessConditionOption[]; /** * An object representing the configuration describing the bistream metadata form */ + @autoserialize metadata: SubmissionFormsModel; + @autoserialize required: boolean; + @autoserialize maxSize: number; } diff --git a/src/app/core/config/models/config.model.ts b/src/app/core/config/models/config.model.ts index 20d67ec69d..fabb16eb23 100644 --- a/src/app/core/config/models/config.model.ts +++ b/src/app/core/config/models/config.model.ts @@ -1,22 +1,30 @@ +import { autoserialize, deserialize } from 'cerialize'; import { CacheableObject } from '../../cache/object-cache.reducer'; +import { HALLink } from '../../shared/hal-link.model'; import { ResourceType } from '../../shared/resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; export abstract class ConfigObject implements CacheableObject { /** * The name for this configuration */ + @autoserialize public name: string; + /** + * The type of this ConfigObject + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + /** * The links to all related resources returned by the rest api. */ - public _links: { - [name: string]: string + @deserialize + _links: { + self: HALLink, + [name: string]: HALLink }; - - /** - * The link to the rest endpoint where this config object can be found - */ - self: string; } diff --git a/src/app/core/config/models/normalized-config-submission-definition.model.ts b/src/app/core/config/models/normalized-config-submission-definition.model.ts deleted file mode 100644 index cb56e01acf..0000000000 --- a/src/app/core/config/models/normalized-config-submission-definition.model.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { SubmissionSectionModel } from './config-submission-section.model'; -import { PaginatedList } from '../../data/paginated-list'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { SubmissionDefinitionsModel } from './config-submission-definitions.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { SubmissionDefinitionModel } from './config-submission-definition.model'; - -/** - * Normalized class for the configuration describing the submission - */ -@mapsTo(SubmissionDefinitionModel) -@inheritSerialization(NormalizedConfigObject) -export class NormalizedSubmissionDefinitionModel extends NormalizedConfigObject { - - /** - * A boolean representing if this submission definition is the default or not - */ - @autoserialize - isDefault: boolean; - - /** - * A list of SubmissionSectionModel that are present in this submission definition - */ - @autoserializeAs(SubmissionSectionModel) - sections: PaginatedList; - -} diff --git a/src/app/core/config/models/normalized-config-submission-definitions.model.ts b/src/app/core/config/models/normalized-config-submission-definitions.model.ts deleted file mode 100644 index 4c52d96458..0000000000 --- a/src/app/core/config/models/normalized-config-submission-definitions.model.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { inheritSerialization } from 'cerialize'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { SubmissionDefinitionsModel } from './config-submission-definitions.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { NormalizedSubmissionDefinitionModel } from './normalized-config-submission-definition.model'; - -/** - * Normalized class for the configuration describing the submission - */ -@mapsTo(SubmissionDefinitionsModel) -@inheritSerialization(NormalizedConfigObject) -export class NormalizedSubmissionDefinitionsModel extends NormalizedSubmissionDefinitionModel { -} diff --git a/src/app/core/config/models/normalized-config-submission-form.model.ts b/src/app/core/config/models/normalized-config-submission-form.model.ts deleted file mode 100644 index afdfef4818..0000000000 --- a/src/app/core/config/models/normalized-config-submission-form.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { FormRowModel, SubmissionFormModel } from './config-submission-form.model'; - -/** - * Normalized class for the configuration describing the submission form - */ -@mapsTo(SubmissionFormModel) -@inheritSerialization(NormalizedConfigObject) -export class NormalizedSubmissionFormModel extends NormalizedConfigObject { - - /** - * An array of [FormRowModel] that are present in this form - */ - @autoserialize - rows: FormRowModel[]; -} diff --git a/src/app/core/config/models/normalized-config-submission-forms.model.ts b/src/app/core/config/models/normalized-config-submission-forms.model.ts deleted file mode 100644 index c040a94587..0000000000 --- a/src/app/core/config/models/normalized-config-submission-forms.model.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { inheritSerialization } from 'cerialize'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { SubmissionFormsModel } from './config-submission-forms.model'; -import { NormalizedSubmissionFormModel } from './normalized-config-submission-form.model'; - -/** - * Normalized class for the configuration describing the submission form - */ -@mapsTo(SubmissionFormsModel) -@inheritSerialization(NormalizedSubmissionFormModel) -export class NormalizedSubmissionFormsModel extends NormalizedSubmissionFormModel { -} diff --git a/src/app/core/config/models/normalized-config-submission-section.model.ts b/src/app/core/config/models/normalized-config-submission-section.model.ts deleted file mode 100644 index 364a981060..0000000000 --- a/src/app/core/config/models/normalized-config-submission-section.model.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { SectionsType } from '../../../submission/sections/sections-type'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { - SubmissionSectionModel, - SubmissionSectionVisibility -} from './config-submission-section.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; - -/** - * Normalized class for the configuration describing the submission section - */ -@mapsTo(SubmissionSectionModel) -@inheritSerialization(NormalizedConfigObject) -export class NormalizedSubmissionSectionModel extends NormalizedConfigObject { - - /** - * The header for this section - */ - @autoserialize - header: string; - - /** - * A boolean representing if this submission section is the mandatory or not - */ - @autoserialize - mandatory: boolean; - - /** - * A string representing the kind of section object - */ - @autoserialize - sectionType: SectionsType; - - /** - * The [SubmissionSectionVisibility] object for this section - */ - @autoserialize - visibility: SubmissionSectionVisibility - -} diff --git a/src/app/core/config/models/normalized-config-submission-sections.model.ts b/src/app/core/config/models/normalized-config-submission-sections.model.ts deleted file mode 100644 index fb1e4c671a..0000000000 --- a/src/app/core/config/models/normalized-config-submission-sections.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { SectionsType } from '../../../submission/sections/sections-type'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { - SubmissionSectionModel, - SubmissionSectionVisibility -} from './config-submission-section.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { SubmissionSectionsModel } from './config-submission-sections.model'; -import { NormalizedSubmissionSectionModel } from './normalized-config-submission-section.model'; - -/** - * Normalized class for the configuration describing the submission section - */ -@mapsTo(SubmissionSectionsModel) -@inheritSerialization(NormalizedSubmissionSectionModel) -export class NormalizedSubmissionSectionsModel extends NormalizedSubmissionSectionModel { -} diff --git a/src/app/core/config/models/normalized-config-submission-uploads.model.ts b/src/app/core/config/models/normalized-config-submission-uploads.model.ts deleted file mode 100644 index 7a21c15912..0000000000 --- a/src/app/core/config/models/normalized-config-submission-uploads.model.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { AccessConditionOption } from './config-access-condition-option.model'; -import { SubmissionFormsModel } from './config-submission-forms.model'; -import { NormalizedConfigObject } from './normalized-config.model'; -import { SubmissionUploadsModel } from './config-submission-uploads.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; - -/** - * Normalized class for the configuration describing the submission upload section - */ -@mapsTo(SubmissionUploadsModel) -@inheritSerialization(NormalizedConfigObject) -export class NormalizedSubmissionUploadsModel extends NormalizedConfigObject { - - /** - * A list of available bitstream access conditions - */ - @autoserialize - accessConditionOptions: AccessConditionOption[]; - - /** - * An object representing the configuration describing the bistream metadata form - */ - @autoserializeAs(SubmissionFormsModel) - metadata: SubmissionFormsModel; - - @autoserialize - required: boolean; - - @autoserialize - maxSize: number; - -} diff --git a/src/app/core/config/models/normalized-config.model.ts b/src/app/core/config/models/normalized-config.model.ts deleted file mode 100644 index 1bf4ffb826..0000000000 --- a/src/app/core/config/models/normalized-config.model.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { NormalizedObject } from '../../cache/models/normalized-object.model'; -import { CacheableObject, TypedObject } from '../../cache/object-cache.reducer'; -import { ResourceType } from '../../shared/resource-type'; - -/** - * Normalized abstract class for a configuration object - */ -@inheritSerialization(NormalizedObject) -export abstract class NormalizedConfigObject implements CacheableObject { - - /** - * The name for this configuration - */ - @autoserialize - public name: string; - - /** - * The links to all related resources returned by the rest api. - */ - @autoserialize - public _links: { - [name: string]: string - }; - - /** - * The link to the rest endpoint where this config object can be found - */ - @autoserialize - self: string; - -} diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 69cde7b61a..e894b1a6cd 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -1,142 +1,140 @@ -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; import { CommonModule } from '@angular/common'; - -import { StoreModule } from '@ngrx/store'; -import { EffectsModule } from '@ngrx/effects'; -import { DynamicFormLayoutService, DynamicFormService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; - -import { coreEffects } from './core.effects'; -import { coreReducers } from './core.reducers'; - -import { isNotEmpty } from '../shared/empty.util'; - -import { ApiService } from './services/api.service'; -import { BrowseEntriesResponseParsingService } from './data/browse-entries-response-parsing.service'; -import { CollectionDataService } from './data/collection-data.service'; -import { CommunityDataService } from './data/community-data.service'; -import { DebugResponseParsingService } from './data/debug-response-parsing.service'; -import { DSOResponseParsingService } from './data/dso-response-parsing.service'; -import { SearchResponseParsingService } from './data/search-response-parsing.service'; -import { DSpaceRESTv2Service } from './dspace-rest-v2/dspace-rest-v2.service'; -import { FormBuilderService } from '../shared/form/builder/form-builder.service'; -import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service'; -import { FormService } from '../shared/form/form.service'; -import { GroupEpersonService } from './eperson/group-eperson.service'; -import { HostWindowService } from '../shared/host-window.service'; -import { ItemDataService } from './data/item-data.service'; -import { MetadataService } from './metadata/metadata.service'; -import { ObjectCacheService } from './cache/object-cache.service'; -import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; -import { RemoteDataBuildService } from './cache/builders/remote-data-build.service'; -import { RequestService } from './data/request.service'; -import { EndpointMapResponseParsingService } from './data/endpoint-map-response-parsing.service'; -import { ServerResponseService } from './services/server-response.service'; -import { NativeWindowFactory, NativeWindowService } from './services/window.service'; -import { BrowseService } from './browse/browse.service'; -import { BrowseResponseParsingService } from './data/browse-response-parsing.service'; -import { ConfigResponseParsingService } from './config/config-response-parsing.service'; -import { SubmissionDefinitionsConfigService } from './config/submission-definitions-config.service'; -import { SubmissionFormsConfigService } from './config/submission-forms-config.service'; -import { SubmissionSectionsConfigService } from './config/submission-sections-config.service'; -import { SubmissionResponseParsingService } from './submission/submission-response-parsing.service'; -import { EpersonResponseParsingService } from './eperson/eperson-response-parsing.service'; -import { JsonPatchOperationsBuilder } from './json-patch/builder/json-patch-operations-builder'; -import { AuthorityService } from './integration/authority.service'; -import { IntegrationResponseParsingService } from './integration/integration-response-parsing.service'; -import { WorkspaceitemDataService } from './submission/workspaceitem-data.service'; -import { UUIDService } from './shared/uuid.service'; -import { AuthenticatedGuard } from './auth/authenticated.guard'; -import { AuthRequestService } from './auth/auth-request.service'; -import { AuthResponseParsingService } from './auth/auth-response-parsing.service'; import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; -import { AuthInterceptor } from './auth/auth.interceptor'; -import { HALEndpointService } from './shared/hal-endpoint.service'; -import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service'; -import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service'; -import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service'; -import { ResourcePolicyService } from './data/resource-policy.service'; -import { RegistryService } from './registry/registry.service'; -import { RegistryMetadataschemasResponseParsingService } from './data/registry-metadataschemas-response-parsing.service'; -import { RegistryMetadatafieldsResponseParsingService } from './data/registry-metadatafields-response-parsing.service'; -import { RegistryBitstreamformatsResponseParsingService } from './data/registry-bitstreamformats-response-parsing.service'; -import { WorkflowItemDataService } from './submission/workflowitem-data.service'; -import { NotificationsService } from '../shared/notifications/notifications.service'; -import { UploaderService } from '../shared/uploader/uploader.service'; -import { FileService } from './shared/file.service'; -import { SubmissionRestService } from './submission/submission-rest.service'; -import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service'; -import { DSpaceObjectDataService } from './data/dspace-object-data.service'; -import { MetadataschemaParsingService } from './data/metadataschema-parsing.service'; -import { FilteredDiscoveryPageResponseParsingService } from './data/filtered-discovery-page-response-parsing.service'; -import { CSSVariableService } from '../shared/sass-helper/sass-helper.service'; -import { MenuService } from '../shared/menu/menu.service'; -import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service'; -import { NormalizedObjectBuildService } from './cache/builders/normalized-object-build.service'; -import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service'; -import { ObjectUpdatesService } from './data/object-updates/object-updates.service'; -import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service'; -import { SearchService } from './shared/search/search.service'; -import { RelationshipService } from './data/relationship.service'; -import { NormalizedCollection } from './cache/models/normalized-collection.model'; -import { NormalizedCommunity } from './cache/models/normalized-community.model'; -import { NormalizedDSpaceObject } from './cache/models/normalized-dspace-object.model'; -import { NormalizedBitstream } from './cache/models/normalized-bitstream.model'; -import { NormalizedBundle } from './cache/models/normalized-bundle.model'; -import { NormalizedBitstreamFormat } from './cache/models/normalized-bitstream-format.model'; -import { NormalizedItem } from './cache/models/normalized-item.model'; -import { NormalizedEPerson } from './eperson/models/normalized-eperson.model'; -import { NormalizedGroup } from './eperson/models/normalized-group.model'; -import { NormalizedResourcePolicy } from './cache/models/normalized-resource-policy.model'; -import { NormalizedMetadataSchema } from './metadata/normalized-metadata-schema.model'; -import { NormalizedMetadataField } from './metadata/normalized-metadata-field.model'; -import { NormalizedLicense } from './cache/models/normalized-license.model'; -import { NormalizedWorkflowItem } from './submission/models/normalized-workflowitem.model'; -import { NormalizedWorkspaceItem } from './submission/models/normalized-workspaceitem.model'; -import { NormalizedSubmissionDefinitionsModel } from './config/models/normalized-config-submission-definitions.model'; -import { NormalizedSubmissionFormsModel } from './config/models/normalized-config-submission-forms.model'; -import { NormalizedSubmissionSectionModel } from './config/models/normalized-config-submission-section.model'; -import { NormalizedAuthStatus } from './auth/models/normalized-auth-status.model'; -import { NormalizedAuthorityValue } from './integration/models/normalized-authority-value.model'; -import { RoleService } from './roles/role.service'; -import { MyDSpaceGuard } from '../+my-dspace-page/my-dspace.guard'; -import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing.service'; -import { ClaimedTaskDataService } from './tasks/claimed-task-data.service'; -import { PoolTaskDataService } from './tasks/pool-task-data.service'; -import { TaskResponseParsingService } from './tasks/task-response-parsing.service'; -import { BitstreamFormatDataService } from './data/bitstream-format-data.service'; -import { NormalizedClaimedTask } from './tasks/models/normalized-claimed-task-object.model'; -import { NormalizedTaskObject } from './tasks/models/normalized-task-object.model'; -import { NormalizedPoolTask } from './tasks/models/normalized-pool-task-object.model'; -import { NormalizedRelationship } from './cache/models/items/normalized-relationship.model'; -import { NormalizedRelationshipType } from './cache/models/items/normalized-relationship-type.model'; -import { NormalizedItemType } from './cache/models/items/normalized-item-type.model'; -import { MetadatafieldParsingService } from './data/metadatafield-parsing.service'; -import { NormalizedSubmissionUploadsModel } from './config/models/normalized-config-submission-uploads.model'; -import { NormalizedBrowseEntry } from './shared/normalized-browse-entry.model'; -import { BrowseDefinition } from './shared/browse-definition.model'; -import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service'; -import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service'; -import { ObjectSelectService } from '../shared/object-select/object-select.service'; -import {EntityTypeService} from './data/entity-type.service'; -import { SiteDataService } from './data/site-data.service'; -import { NormalizedSite } from './cache/models/normalized-site.model'; +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { DynamicFormLayoutService, DynamicFormService, DynamicFormValidationService } from '@ng-dynamic-forms/core'; +import { EffectsModule } from '@ngrx/effects'; +import { StoreModule } from '@ngrx/store'; + +import { MyDSpaceGuard } from '../+my-dspace-page/my-dspace.guard'; +import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../../config'; +import { isNotEmpty } from '../shared/empty.util'; +import { FormBuilderService } from '../shared/form/builder/form-builder.service'; +import { FormService } from '../shared/form/form.service'; +import { HostWindowService } from '../shared/host-window.service'; +import { MenuService } from '../shared/menu/menu.service'; +import { EndpointMockingRestService } from '../shared/mocks/dspace-rest-v2/endpoint-mocking-rest.service'; import { MOCK_RESPONSE_MAP, MockResponseMap, mockResponseMap } from '../shared/mocks/dspace-rest-v2/mocks/mock-response-map'; -import { EndpointMockingRestService } from '../shared/mocks/dspace-rest-v2/endpoint-mocking-rest.service'; -import { ENV_CONFIG, GLOBAL_CONFIG, GlobalConfig } from '../../config'; -import { SearchFilterService } from './shared/search/search-filter.service'; -import { SearchConfigurationService } from './shared/search/search-configuration.service'; +import { NotificationsService } from '../shared/notifications/notifications.service'; import { SelectableListService } from '../shared/object-list/selectable-list/selectable-list.service'; -import { RelationshipTypeService } from './data/relationship-type.service'; +import { ObjectSelectService } from '../shared/object-select/object-select.service'; +import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; +import { CSSVariableService } from '../shared/sass-helper/sass-helper.service'; import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { NormalizedExternalSource } from './cache/models/normalized-external-source.model'; -import { NormalizedExternalSourceEntry } from './cache/models/normalized-external-source-entry.model'; +import { UploaderService } from '../shared/uploader/uploader.service'; +import { SectionFormOperationsService } from '../submission/sections/form/section-form-operations.service'; +import { AuthRequestService } from './auth/auth-request.service'; +import { AuthResponseParsingService } from './auth/auth-response-parsing.service'; +import { AuthInterceptor } from './auth/auth.interceptor'; +import { AuthenticatedGuard } from './auth/authenticated.guard'; +import { AuthStatus } from './auth/models/auth-status.model'; +import { BrowseService } from './browse/browse.service'; +import { RemoteDataBuildService } from './cache/builders/remote-data-build.service'; +import { ObjectCacheService } from './cache/object-cache.service'; +import { ConfigResponseParsingService } from './config/config-response-parsing.service'; +import { SubmissionDefinitionsModel } from './config/models/config-submission-definitions.model'; +import { SubmissionFormsModel } from './config/models/config-submission-forms.model'; +import { SubmissionSectionModel } from './config/models/config-submission-section.model'; +import { SubmissionUploadsModel } from './config/models/config-submission-uploads.model'; +import { SubmissionDefinitionsConfigService } from './config/submission-definitions-config.service'; +import { SubmissionFormsConfigService } from './config/submission-forms-config.service'; +import { SubmissionSectionsConfigService } from './config/submission-sections-config.service'; +import { coreEffects } from './core.effects'; +import { coreReducers } from './core.reducers'; +import { BitstreamFormatDataService } from './data/bitstream-format-data.service'; +import { BrowseEntriesResponseParsingService } from './data/browse-entries-response-parsing.service'; +import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service'; +import { BrowseResponseParsingService } from './data/browse-response-parsing.service'; +import { CollectionDataService } from './data/collection-data.service'; +import { CommunityDataService } from './data/community-data.service'; +import { ContentSourceResponseParsingService } from './data/content-source-response-parsing.service'; +import { DebugResponseParsingService } from './data/debug-response-parsing.service'; +import { DefaultChangeAnalyzer } from './data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service'; +import { DSOResponseParsingService } from './data/dso-response-parsing.service'; +import { DSpaceObjectDataService } from './data/dspace-object-data.service'; +import { EndpointMapResponseParsingService } from './data/endpoint-map-response-parsing.service'; +import { ItemTypeDataService } from './data/entity-type-data.service'; +import { EntityTypeService } from './data/entity-type.service'; import { ExternalSourceService } from './data/external-source.service'; +import { FacetConfigResponseParsingService } from './data/facet-config-response-parsing.service'; +import { FacetValueMapResponseParsingService } from './data/facet-value-map-response-parsing.service'; +import { FacetValueResponseParsingService } from './data/facet-value-response-parsing.service'; +import { FilteredDiscoveryPageResponseParsingService } from './data/filtered-discovery-page-response-parsing.service'; +import { ItemDataService } from './data/item-data.service'; +import { LicenseDataService } from './data/license-data.service'; import { LookupRelationService } from './data/lookup-relation.service'; +import { MappedCollectionsReponseParsingService } from './data/mapped-collections-reponse-parsing.service'; +import { MetadatafieldParsingService } from './data/metadatafield-parsing.service'; +import { MetadataschemaParsingService } from './data/metadataschema-parsing.service'; +import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing.service'; +import { ObjectUpdatesService } from './data/object-updates/object-updates.service'; +import { RegistryBitstreamformatsResponseParsingService } from './data/registry-bitstreamformats-response-parsing.service'; +import { RegistryMetadatafieldsResponseParsingService } from './data/registry-metadatafields-response-parsing.service'; +import { RegistryMetadataschemasResponseParsingService } from './data/registry-metadataschemas-response-parsing.service'; +import { RelationshipTypeService } from './data/relationship-type.service'; +import { RelationshipService } from './data/relationship.service'; +import { ResourcePolicyService } from './data/resource-policy.service'; +import { SearchResponseParsingService } from './data/search-response-parsing.service'; +import { SiteDataService } from './data/site-data.service'; +import { DSpaceRESTv2Service } from './dspace-rest-v2/dspace-rest-v2.service'; +import { EPersonDataService } from './eperson/eperson-data.service'; +import { EpersonResponseParsingService } from './eperson/eperson-response-parsing.service'; +import { EPerson } from './eperson/models/eperson.model'; +import { Group } from './eperson/models/group.model'; +import { AuthorityService } from './integration/authority.service'; +import { IntegrationResponseParsingService } from './integration/integration-response-parsing.service'; +import { AuthorityValue } from './integration/models/authority.value'; +import { JsonPatchOperationsBuilder } from './json-patch/builder/json-patch-operations-builder'; +import { MetadataField } from './metadata/metadata-field.model'; +import { MetadataSchema } from './metadata/metadata-schema.model'; +import { MetadataService } from './metadata/metadata.service'; +import { RegistryService } from './registry/registry.service'; +import { RoleService } from './roles/role.service'; + +import { ApiService } from './services/api.service'; +import { ServerResponseService } from './services/server-response.service'; +import { NativeWindowFactory, NativeWindowService } from './services/window.service'; +import { BitstreamFormat } from './shared/bitstream-format.model'; +import { Bitstream } from './shared/bitstream.model'; +import { BrowseDefinition } from './shared/browse-definition.model'; +import { BrowseEntry } from './shared/browse-entry.model'; +import { Bundle } from './shared/bundle.model'; +import { Collection } from './shared/collection.model'; +import { Community } from './shared/community.model'; +import { DSpaceObject } from './shared/dspace-object.model'; +import { ExternalSourceEntry } from './shared/external-source-entry.model'; +import { ExternalSource } from './shared/external-source.model'; +import { FileService } from './shared/file.service'; +import { HALEndpointService } from './shared/hal-endpoint.service'; +import { ItemType } from './shared/item-relationships/item-type.model'; +import { RelationshipType } from './shared/item-relationships/relationship-type.model'; +import { Relationship } from './shared/item-relationships/relationship.model'; +import { Item } from './shared/item.model'; +import { License } from './shared/license.model'; +import { ResourcePolicy } from './shared/resource-policy.model'; +import { SearchConfigurationService } from './shared/search/search-configuration.service'; +import { SearchFilterService } from './shared/search/search-filter.service'; +import { SearchService } from './shared/search/search.service'; +import { Site } from './shared/site.model'; +import { UUIDService } from './shared/uuid.service'; +import { WorkflowItem } from './submission/models/workflowitem.model'; +import { WorkspaceItem } from './submission/models/workspaceitem.model'; +import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service'; +import { SubmissionResponseParsingService } from './submission/submission-response-parsing.service'; +import { SubmissionRestService } from './submission/submission-rest.service'; +import { WorkflowItemDataService } from './submission/workflowitem-data.service'; +import { WorkspaceitemDataService } from './submission/workspaceitem-data.service'; +import { ClaimedTaskDataService } from './tasks/claimed-task-data.service'; +import { ClaimedTask } from './tasks/models/claimed-task-object.model'; +import { PoolTask } from './tasks/models/pool-task-object.model'; +import { TaskObject } from './tasks/models/task-object.model'; +import { PoolTaskDataService } from './tasks/pool-task-data.service'; +import { TaskResponseParsingService } from './tasks/task-response-parsing.service'; /** * When not in production, endpoint responses can be mocked for testing purposes @@ -170,7 +168,11 @@ const PROVIDERS = [ SiteDataService, DSOResponseParsingService, { provide: MOCK_RESPONSE_MAP, useValue: mockResponseMap }, - { provide: DSpaceRESTv2Service, useFactory: restServiceFactory, deps: [GLOBAL_CONFIG, MOCK_RESPONSE_MAP, HttpClient]}, + { + provide: DSpaceRESTv2Service, + useFactory: restServiceFactory, + deps: [GLOBAL_CONFIG, MOCK_RESPONSE_MAP, HttpClient] + }, DynamicFormLayoutService, DynamicFormService, DynamicFormValidationService, @@ -178,7 +180,7 @@ const PROVIDERS = [ SectionFormOperationsService, FormService, EpersonResponseParsingService, - GroupEpersonService, + EPersonDataService, HALEndpointService, HostWindowService, ItemDataService, @@ -188,9 +190,7 @@ const PROVIDERS = [ ResourcePolicyService, RegistryService, BitstreamFormatDataService, - NormalizedObjectBuildService, RemoteDataBuildService, - RequestService, EndpointMapResponseParsingService, FacetValueResponseParsingService, FacetValueMapResponseParsingService, @@ -251,6 +251,8 @@ const PROVIDERS = [ RelationshipTypeService, ExternalSourceService, LookupRelationService, + LicenseDataService, + ItemTypeDataService, // register AuthInterceptor as HttpInterceptor { provide: HTTP_INTERCEPTORS, @@ -265,40 +267,40 @@ const PROVIDERS = [ /** * Declaration needed to make sure all decorator functions are called in time */ -export const normalizedModels = +export const models = [ - NormalizedDSpaceObject, - NormalizedBundle, - NormalizedBitstream, - NormalizedBitstreamFormat, - NormalizedItem, - NormalizedSite, - NormalizedCollection, - NormalizedCommunity, - NormalizedEPerson, - NormalizedGroup, - NormalizedResourcePolicy, - NormalizedMetadataSchema, - NormalizedMetadataField, - NormalizedLicense, - NormalizedWorkflowItem, - NormalizedWorkspaceItem, - NormalizedSubmissionDefinitionsModel, - NormalizedSubmissionFormsModel, - NormalizedSubmissionSectionModel, - NormalizedSubmissionUploadsModel, - NormalizedAuthStatus, - NormalizedAuthorityValue, - NormalizedBrowseEntry, + DSpaceObject, + Bundle, + Bitstream, + BitstreamFormat, + Item, + Site, + Collection, + Community, + EPerson, + Group, + ResourcePolicy, + MetadataSchema, + MetadataField, + License, + WorkflowItem, + WorkspaceItem, + SubmissionDefinitionsModel, + SubmissionFormsModel, + SubmissionSectionModel, + SubmissionUploadsModel, + AuthStatus, + AuthorityValue, + BrowseEntry, BrowseDefinition, - NormalizedClaimedTask, - NormalizedTaskObject, - NormalizedPoolTask, - NormalizedRelationship, - NormalizedRelationshipType, - NormalizedItemType, - NormalizedExternalSource, - NormalizedExternalSourceEntry + ClaimedTask, + TaskObject, + PoolTask, + Relationship, + RelationshipType, + ItemType, + ExternalSource, + ExternalSourceEntry, ]; @NgModule({ diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts index ea2d71faa7..3615ab4023 100644 --- a/src/app/core/data/base-response-parsing.service.ts +++ b/src/app/core/data/base-response-parsing.service.ts @@ -1,21 +1,45 @@ import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { CacheableObject } from '../cache/object-cache.reducer'; +import { Serializer } from '../serializer'; import { PageInfo } from '../shared/page-info.model'; import { ObjectCacheService } from '../cache/object-cache.service'; import { GlobalConfig } from '../../../config/global-config.interface'; import { GenericConstructor } from '../shared/generic-constructor'; import { PaginatedList } from './paginated-list'; -import { isRestDataObject, isRestPaginatedList } from '../cache/builders/normalized-object-build.service'; -import { ResourceType } from '../shared/resource-type'; -import { getMapsToType } from '../cache/builders/build-decorators'; +import { getClassForType } from '../cache/builders/build-decorators'; import { RestRequest } from './request.models'; /* tslint:disable:max-classes-per-file */ +/** + * Return true if halObj has a value for `_links.self` + * + * @param {any} halObj The object to test + */ +export function isRestDataObject(halObj: any): boolean { + return isNotEmpty(halObj._links) && hasValue(halObj._links.self); +} + +/** + * Return true if halObj has a value for `page` with properties + * `size`, `totalElements`, `totalPages`, `number` + * + * @param {any} halObj The object to test + */ +export function isRestPaginatedList(halObj: any): boolean { + return hasValue(halObj.page) && + hasValue(halObj.page.size) && + hasValue(halObj.page.totalElements) && + hasValue(halObj.page.totalPages) && + hasValue(halObj.page.number); +} + export abstract class BaseResponseParsingService { protected abstract EnvConfig: GlobalConfig; protected abstract objectCache: ObjectCacheService; protected abstract toCache: boolean; + protected shouldDirectlyAttachEmbeds = false; + protected serializerConstructor: GenericConstructor> = DSpaceSerializer; protected process(data: any, request: RestRequest): any { if (isNotEmpty(data)) { @@ -33,20 +57,20 @@ export abstract class BaseResponseParsingService { .filter((property) => data._embedded.hasOwnProperty(property)) .forEach((property) => { const parsedObj = this.process(data._embedded[property], request); - if (isNotEmpty(parsedObj)) { - if (isRestPaginatedList(data._embedded[property])) { - object[property] = parsedObj; - object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj)); - } else if (isRestDataObject(data._embedded[property])) { - object[property] = this.retrieveObjectOrUrl(parsedObj); - } else if (Array.isArray(parsedObj)) { - object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj)) - } + if (this.shouldDirectlyAttachEmbeds && isNotEmpty(parsedObj)) { + if (isRestPaginatedList(data._embedded[property])) { + object[property] = parsedObj; + object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj)); + } else if (isRestDataObject(data._embedded[property])) { + object[property] = this.retrieveObjectOrUrl(parsedObj); + } else if (Array.isArray(parsedObj)) { + object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj)) + } } }); } - this.cache(object, request); + this.cache(object, request, data); return object; } const result = {}; @@ -87,33 +111,38 @@ export abstract class BaseResponseParsingService { protected deserialize(obj): any { const type: string = obj.type; if (hasValue(type)) { - const normObjConstructor = getMapsToType(type) as GenericConstructor; + const objConstructor = getClassForType(type) as GenericConstructor; - if (hasValue(normObjConstructor)) { - const serializer = new DSpaceRESTv2Serializer(normObjConstructor); + if (hasValue(objConstructor)) { + const serializer = new this.serializerConstructor(objConstructor); return serializer.deserialize(obj); } else { - // TODO: move check to Validator? - // throw new Error(`The server returned an object with an unknown a known type: ${type}`); return null; } } else { - // TODO: move check to Validator - // throw new Error(`The server returned an object without a type: ${JSON.stringify(obj)}`); return null; } } - protected cache(obj, request: RestRequest) { + protected cache(obj, request: RestRequest, data: any) { if (this.toCache) { - this.addToObjectCache(obj, request); + this.addToObjectCache(obj, request, data); } } - protected addToObjectCache(co: CacheableObject, request: RestRequest): void { - if (hasNoValue(co) || hasNoValue(co.self)) { - throw new Error('The server returned an invalid object'); + protected addToObjectCache(co: CacheableObject, request: RestRequest, data: any): void { + if (hasNoValue(co) || hasNoValue(co._links) || hasNoValue(co._links.self) || hasNoValue(co._links.self.href)) { + const type = hasValue(data) && hasValue(data.type) ? data.type : 'object'; + let dataJSON: string; + if (hasValue(data._embedded)) { + dataJSON = JSON.stringify(Object.assign({}, data, { + _embedded: '...' + })); + } else { + dataJSON = JSON.stringify(data); + } + throw new Error(`Can't cache incomplete ${type}: ${JSON.stringify(co)}, parsed from (partial) response: ${dataJSON}`); } this.objectCache.add(co, hasValue(request.responseMsToLive) ? request.responseMsToLive : this.EnvConfig.cache.msToLive.default, request.uuid); } @@ -121,7 +150,7 @@ export abstract class BaseResponseParsingService { processPageInfo(payload: any): PageInfo { if (hasValue(payload.page)) { const pageObj = Object.assign({}, payload.page, { _links: payload._links }); - const pageInfoObject = new DSpaceRESTv2Serializer(PageInfo).deserialize(pageObj); + const pageInfoObject = new DSpaceSerializer(PageInfo).deserialize(pageObj); if (pageInfoObject.currentPage >= 0) { Object.assign(pageInfoObject, { currentPage: pageInfoObject.currentPage + 1 }); } @@ -140,7 +169,7 @@ export abstract class BaseResponseParsingService { } protected retrieveObjectOrUrl(obj: any): any { - return this.toCache ? obj.self : obj; + return this.toCache ? obj._links.self.href : obj; } protected isSuccessStatus(statusCode: number) { diff --git a/src/app/core/data/bitstream-data.service.ts b/src/app/core/data/bitstream-data.service.ts new file mode 100644 index 0000000000..408dceb56e --- /dev/null +++ b/src/app/core/data/bitstream-data.service.ts @@ -0,0 +1,170 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs/internal/Observable'; +import { map, switchMap } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { Bitstream } from '../shared/bitstream.model'; +import { BITSTREAM } from '../shared/bitstream.resource-type'; +import { Bundle } from '../shared/bundle.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; +import { BundleDataService } from './bundle-data.service'; +import { CommunityDataService } from './community-data.service'; +import { DataService } from './data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { RemoteDataError } from './remote-data-error'; +import { FindListOptions } from './request.models'; +import { RequestService } from './request.service'; + +/** + * A service to retrieve {@link Bitstream}s from the REST API + */ +@Injectable({ + providedIn: 'root' +}) +@dataService(BITSTREAM) +export class BitstreamDataService extends DataService { + + /** + * The HAL path to the bitstream endpoint + */ + protected linkPath = 'bitstreams'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected cds: CommunityDataService, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DSOChangeAnalyzer, + protected bundleService: BundleDataService, + ) { + super(); + } + + /** + * Retrieves the {@link Bitstream}s in a given bundle + * + * @param bundle the bundle to retrieve bitstreams from + * @param options options for the find all request + */ + findAllByBundle(bundle: Bundle, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { + return this.findAllByHref(bundle._links.bitstreams.href, options, ...linksToFollow); + } + + /** + * Retrieves the thumbnail for the given item + * @returns {Observable>} the first bitstream in the THUMBNAIL bundle + */ + // TODO should be implemented rest side. {@link Item} should get a thumbnail link + public getThumbnailFor(item: Item): Observable> { + return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( + switchMap((bundleRD: RemoteData) => { + if (hasValue(bundleRD.payload)) { + return this.findAllByBundle(bundleRD.payload, { elementsPerPage: 1 }).pipe( + map((bitstreamRD: RemoteData>) => { + if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { + return new RemoteData( + false, + false, + true, + undefined, + bitstreamRD.payload.page[0] + ); + } else { + return bitstreamRD as any; + } + }) + ); + } else { + return [bundleRD as any]; + } + }) + ); + } + + /** + * Retrieve the matching thumbnail for a {@link Bitstream}. + * + * The {@link Item} is technically redundant, but is available + * in all current use cases, and having it simplifies this method + * + * @param item The {@link Item} the {@link Bitstream} and its thumbnail are a part of + * @param bitstreamInOriginal The original {@link Bitstream} to find the thumbnail for + */ + // TODO should be implemented rest side + public getMatchingThumbnail(item: Item, bitstreamInOriginal: Bitstream): Observable> { + return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( + switchMap((bundleRD: RemoteData) => { + if (hasValue(bundleRD.payload)) { + return this.findAllByBundle(bundleRD.payload, { elementsPerPage: Number.MAX_SAFE_INTEGER }).pipe( + map((bitstreamRD: RemoteData>) => { + if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { + const matchingThumbnail = bitstreamRD.payload.page.find((thumbnail: Bitstream) => + thumbnail.name.startsWith(bitstreamInOriginal.name) + ); + if (hasValue(matchingThumbnail)) { + return new RemoteData( + false, + false, + true, + undefined, + matchingThumbnail + ); + } else { + return new RemoteData( + false, + false, + false, + new RemoteDataError(404, '404', 'No matching thumbnail found'), + undefined + ); + } + } else { + return bitstreamRD as any; + } + }) + ); + } else { + return [bundleRD as any]; + } + }) + ); + } + + /** + * Retrieve all {@link Bitstream}s in a certain {@link Bundle}. + * + * The {@link Item} is technically redundant, but is available + * in all current use cases, and having it simplifies this method + * + * @param item the {@link Item} the {@link Bundle} is a part of + * @param bundleName the name of the {@link Bundle} we want to find {@link Bitstream}s for + * @param options the {@link FindListOptions} for the request + * @param linksToFollow the {@link FollowLinkConfig}s for the request + */ + public findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { + return this.bundleService.findByItemAndName(item, bundleName).pipe( + switchMap((bundleRD: RemoteData) => { + if (hasValue(bundleRD.payload)) { + return this.findAllByBundle(bundleRD.payload, options, ...linksToFollow); + } else { + return [bundleRD as any]; + } + }) + ); + } + +} diff --git a/src/app/core/data/bitstream-format-data.service.spec.ts b/src/app/core/data/bitstream-format-data.service.spec.ts index c626fcd6e2..daf3dea87c 100644 --- a/src/app/core/data/bitstream-format-data.service.spec.ts +++ b/src/app/core/data/bitstream-format-data.service.spec.ts @@ -8,7 +8,6 @@ import { cold, getTestScheduler, hot } from 'jasmine-marbles'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { BitstreamFormat } from '../shared/bitstream-format.model'; import { async } from '@angular/core/testing'; @@ -48,14 +47,12 @@ describe('BitstreamFormatDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; const rdbService = {} as RemoteDataBuildService; function initTestService(halService) { return new BitstreamFormatDataService( requestService, rdbService, - dataBuildService, store, objectCache, halService, diff --git a/src/app/core/data/bitstream-format-data.service.ts b/src/app/core/data/bitstream-format-data.service.ts index c30330a0a3..5c7029a09f 100644 --- a/src/app/core/data/bitstream-format-data.service.ts +++ b/src/app/core/data/bitstream-format-data.service.ts @@ -1,31 +1,34 @@ -import { Injectable } from '@angular/core'; -import { DataService } from './data.service'; -import { BitstreamFormat } from '../shared/bitstream-format.model'; -import { RequestService } from './request.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { createSelector, select, Store } from '@ngrx/store'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; -import { DeleteByIDRequest, FindListOptions, PostRequest, PutRequest } from './request.models'; +import { Injectable } from '@angular/core'; +import { createSelector, select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; -import { find, map, tap } from 'rxjs/operators'; -import { configureRequest, getResponseFromEntry } from '../shared/operators'; import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged'; -import { RestResponse } from '../cache/response.models'; -import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; +import { find, map, tap } from 'rxjs/operators'; import { BitstreamFormatsRegistryDeselectAction, BitstreamFormatsRegistryDeselectAllAction, BitstreamFormatsRegistrySelectAction } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions'; +import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; import { hasValue } from '../../shared/empty.util'; -import { RequestEntry } from './request.reducer'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { RestResponse } from '../cache/response.models'; import { CoreState } from '../core.reducers'; import { coreSelector } from '../core.selectors'; +import { BitstreamFormat } from '../shared/bitstream-format.model'; +import { BITSTREAM_FORMAT } from '../shared/bitstream-format.resource-type'; +import { Bitstream } from '../shared/bitstream.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { configureRequest, getResponseFromEntry } from '../shared/operators'; +import { DataService } from './data.service'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { RemoteData } from './remote-data'; +import { DeleteByIDRequest, PostRequest, PutRequest } from './request.models'; +import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; const bitstreamFormatsStateSelector = createSelector( coreSelector, @@ -38,6 +41,7 @@ const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSele * A service responsible for fetching/sending data from/to the REST API on the bitstreamformats endpoint */ @Injectable() +@dataService(BITSTREAM_FORMAT) export class BitstreamFormatDataService extends DataService { protected linkPath = 'bitstreamformats'; @@ -45,7 +49,6 @@ export class BitstreamFormatDataService extends DataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -55,16 +58,6 @@ export class BitstreamFormatDataService extends DataService { super(); } - /** - * Get the endpoint for browsing bitstream formats - * @param {FindListOptions} options - * @param {string} linkPath - * @returns {Observable} - */ - getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable { - return this.halService.getEndpoint(this.linkPath); - } - /** * Get the endpoint to update an existing bitstream format * @param formatId @@ -183,4 +176,8 @@ export class BitstreamFormatDataService extends DataService { map((request: RequestEntry) => request.response.isSuccessful) ); } + + findByBitstream(bitstream: Bitstream): Observable> { + return this.findByHref(bitstream._links.format.href); + } } diff --git a/src/app/core/data/browse-entries-response-parsing.service.ts b/src/app/core/data/browse-entries-response-parsing.service.ts index a2f5f21312..ec35b8cc75 100644 --- a/src/app/core/data/browse-entries-response-parsing.service.ts +++ b/src/app/core/data/browse-entries-response-parsing.service.ts @@ -5,11 +5,11 @@ import { isNotEmpty } from '../../shared/empty.util'; import { ObjectCacheService } from '../cache/object-cache.service'; import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { BrowseEntry } from '../shared/browse-entry.model'; import { BaseResponseParsingService } from './base-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { NormalizedBrowseEntry } from '../shared/normalized-browse-entry.model'; @Injectable() export class BrowseEntriesResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { @@ -26,7 +26,7 @@ export class BrowseEntriesResponseParsingService extends BaseResponseParsingServ if (isNotEmpty(data.payload)) { let browseEntries = []; if (isNotEmpty(data.payload._embedded) && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) { - const serializer = new DSpaceRESTv2Serializer(NormalizedBrowseEntry); + const serializer = new DSpaceSerializer(BrowseEntry); browseEntries = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]); } return new GenericSuccessResponse(browseEntries, data.statusCode, data.statusText, this.processPageInfo(data.payload)); diff --git a/src/app/core/data/browse-items-response-parsing-service.ts b/src/app/core/data/browse-items-response-parsing-service.ts index 324b36199a..08ade5772d 100644 --- a/src/app/core/data/browse-items-response-parsing-service.ts +++ b/src/app/core/data/browse-items-response-parsing-service.ts @@ -6,12 +6,11 @@ import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { ObjectCacheService } from '../cache/object-cache.service'; import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { DSpaceObject } from '../shared/dspace-object.model'; import { BaseResponseParsingService } from './base-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { DSpaceObject } from '../shared/dspace-object.model'; -import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model'; /** * A ResponseParsingService used to parse DSpaceRESTV2Response coming from the REST API to Browse Items (DSpaceObject[]) @@ -35,7 +34,7 @@ export class BrowseItemsResponseParsingService extends BaseResponseParsingServic parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._embedded) && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) { - const serializer = new DSpaceRESTv2Serializer(NormalizedDSpaceObject); + const serializer = new DSpaceSerializer(DSpaceObject); const items = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]); return new GenericSuccessResponse(items, data.statusCode, data.statusText, this.processPageInfo(data.payload)); } else if (hasValue(data.payload) && hasValue(data.payload.page)) { diff --git a/src/app/core/data/browse-response-parsing.service.spec.ts b/src/app/core/data/browse-response-parsing.service.spec.ts index 8d0fe7cd41..fedfea1309 100644 --- a/src/app/core/data/browse-response-parsing.service.spec.ts +++ b/src/app/core/data/browse-response-parsing.service.spec.ts @@ -1,8 +1,8 @@ +import { ErrorResponse, GenericSuccessResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { BrowseDefinition } from '../shared/browse-definition.model'; import { BrowseResponseParsingService } from './browse-response-parsing.service'; import { BrowseEndpointRequest } from './request.models'; -import { GenericSuccessResponse, ErrorResponse } from '../cache/response.models'; -import { BrowseDefinition } from '../shared/browse-definition.model'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; describe('BrowseResponseParsingService', () => { let service: BrowseResponseParsingService; @@ -31,7 +31,6 @@ describe('BrowseResponseParsingService', () => { metadata: 'dc.date.issued' }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }], order: 'ASC', - type: 'browse', metadata: ['dc.date.issued'], _links: { self: { href: 'https://rest.api/discover/browses/dateissued' }, @@ -44,7 +43,6 @@ describe('BrowseResponseParsingService', () => { metadata: 'dc.date.issued' }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }], order: 'ASC', - type: 'browse', metadata: ['dc.contributor.*', 'dc.creator'], _links: { self: { href: 'https://rest.api/discover/browses/author' }, @@ -68,7 +66,6 @@ describe('BrowseResponseParsingService', () => { metadata: 'dc.date.issued' }, { name: 'dateaccessioned', metadata: 'dc.date.accessioned' }], order: 'ASC', - type: 'browse', metadata: ['dc.date.issued'], _links: { self: { href: 'https://rest.api/discover/browses/dateissued' }, @@ -117,8 +114,8 @@ describe('BrowseResponseParsingService', () => { 'dc.date.issued' ], _links: { - self: 'https://rest.api/discover/browses/dateissued', - items: 'https://rest.api/discover/browses/dateissued/items' + self: { href: 'https://rest.api/discover/browses/dateissued' }, + items: { href: 'https://rest.api/discover/browses/dateissued/items' } } }), Object.assign(new BrowseDefinition(), { @@ -143,9 +140,9 @@ describe('BrowseResponseParsingService', () => { 'dc.creator' ], _links: { - self: 'https://rest.api/discover/browses/author', - entries: 'https://rest.api/discover/browses/author/entries', - items: 'https://rest.api/discover/browses/author/items' + self: { href: 'https://rest.api/discover/browses/author' }, + entries: { href: 'https://rest.api/discover/browses/author/entries' }, + items: { href: 'https://rest.api/discover/browses/author/items' } } }) ]; diff --git a/src/app/core/data/browse-response-parsing.service.ts b/src/app/core/data/browse-response-parsing.service.ts index 3c67b2b3eb..d1b9c2f15c 100644 --- a/src/app/core/data/browse-response-parsing.service.ts +++ b/src/app/core/data/browse-response-parsing.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; +import { isNotEmpty } from '../../shared/empty.util'; +import { ErrorResponse, GenericSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { BrowseDefinition } from '../shared/browse-definition.model'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { GenericSuccessResponse, ErrorResponse, RestResponse } from '../cache/response.models'; -import { isNotEmpty } from '../../shared/empty.util'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { BrowseDefinition } from '../shared/browse-definition.model'; @Injectable() export class BrowseResponseParsingService implements ResponseParsingService { @@ -13,7 +13,7 @@ export class BrowseResponseParsingService implements ResponseParsingService { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._embedded) && Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) { - const serializer = new DSpaceRESTv2Serializer(BrowseDefinition); + const serializer = new DSpaceSerializer(BrowseDefinition); const browseDefinitions = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]); return new GenericSuccessResponse(browseDefinitions, data.statusCode, data.statusText); } else { diff --git a/src/app/core/data/bundle-data.service.ts b/src/app/core/data/bundle-data.service.ts index 280f727aad..64d58eb8ec 100644 --- a/src/app/core/data/bundle-data.service.ts +++ b/src/app/core/data/bundle-data.service.ts @@ -1,31 +1,39 @@ -import { Injectable } from '@angular/core'; -import { DataService } from './data.service'; -import { Bundle } from '../shared/bundle.model'; -import { RequestService } from './request.service'; -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 { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; -import { FindListOptions } from './request.models'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { Bundle } from '../shared/bundle.model'; +import { BUNDLE } from '../shared/bundle.resource-type'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; +import { DataService } from './data.service'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { FindListOptions } from './request.models'; +import { RequestService } from './request.service'; /** - * A service responsible for fetching/sending data from/to the REST API on the bundles endpoint + * A service to retrieve {@link Bundle}s from the REST API */ -@Injectable() +@Injectable( + {providedIn: 'root'} +) +@dataService(BUNDLE) export class BundleDataService extends DataService { protected linkPath = 'bundles'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -36,11 +44,41 @@ export class BundleDataService extends DataService { } /** - * Get the endpoint for browsing bundles - * @param {FindListOptions} options - * @returns {Observable} + * Retrieve all {@link Bundle}s in the given {@link Item} + * + * @param item the {@link Item} the {@link Bundle}s are a part of + * @param options the {@link FindListOptions} for the request + * @param linksToFollow the {@link FollowLinkConfig}s for the request */ - getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable { - return this.halService.getEndpoint(this.linkPath); + findAllByItem(item: Item, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { + return this.findAllByHref(item._links.bundles.href, options, ...linksToFollow); + } + + /** + * Retrieve a {@link Bundle} in the given {@link Item} by name + * + * @param item the {@link Item} the {@link Bundle}s are a part of + * @param bundleName the name of the {@link Bundle} to retrieve + * @param linksToFollow the {@link FollowLinkConfig}s for the request + */ + // TODO should be implemented rest side + findByItemAndName(item: Item, bundleName: string, ...linksToFollow: Array>): Observable> { + return this.findAllByItem(item, { elementsPerPage: Number.MAX_SAFE_INTEGER }, ...linksToFollow).pipe( + map((rd: RemoteData>) => { + if (hasValue(rd.payload) && hasValue(rd.payload.page)) { + const matchingBundle = rd.payload.page.find((bundle: Bundle) => + bundle.name === bundleName); + return new RemoteData( + false, + false, + true, + undefined, + matchingBundle + ); + } else { + return rd as any; + } + }), + ); } } diff --git a/src/app/core/data/change-analyzer.ts b/src/app/core/data/change-analyzer.ts index c45c9e55b7..395af4a68c 100644 --- a/src/app/core/data/change-analyzer.ts +++ b/src/app/core/data/change-analyzer.ts @@ -1,4 +1,3 @@ -import { NormalizedObject } from '../cache/models/normalized-object.model'; import { Operation } from 'fast-json-patch/lib/core'; import { CacheableObject } from '../cache/object-cache.reducer'; @@ -12,10 +11,10 @@ export interface ChangeAnalyzer { * Compare two objects and return their differences as a * JsonPatch Operation Array * - * @param {NormalizedObject} object1 + * @param {CacheableObject} object1 * The first object to compare - * @param {NormalizedObject} object2 + * @param {CacheableObject} object2 * The second object to compare */ - diff(object1: T | NormalizedObject, object2: T | NormalizedObject): Operation[]; + diff(object1: T, object2: T): Operation[]; } diff --git a/src/app/core/data/collection-data.service.spec.ts b/src/app/core/data/collection-data.service.spec.ts index c8f056bf19..96141d6a8a 100644 --- a/src/app/core/data/collection-data.service.spec.ts +++ b/src/app/core/data/collection-data.service.spec.ts @@ -126,7 +126,7 @@ describe('CollectionDataService', () => { notificationsService = new NotificationsServiceStub(); translate = getMockTranslateService(); - service = new CollectionDataService(requestService, rdbService, null, null, null, objectCache, halService, notificationsService, null, null, translate); + service = new CollectionDataService(requestService, rdbService, null, null, objectCache, halService, notificationsService, null, null, translate); } }); diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts index ed05c99e27..6ae40f4ca9 100644 --- a/src/app/core/data/collection-data.service.ts +++ b/src/app/core/data/collection-data.service.ts @@ -1,52 +1,54 @@ -import { Injectable } from '@angular/core'; - -import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { CoreState } from '../core.reducers'; -import { Collection } from '../shared/collection.model'; -import { ComColDataService } from './comcol-data.service'; -import { CommunityDataService } from './community-data.service'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs/internal/Observable'; -import { - ContentSourceRequest, - RestRequest, - UpdateContentSourceRequest, - GetRequest, - FindListOptions -} from './request.models'; -import { RemoteData } from './remote-data'; -import { PaginatedList } from './paginated-list'; +import { distinctUntilChanged, filter, map, switchMap, take } from 'rxjs/operators'; +import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; +import { INotification } from '../../shared/notifications/models/notification.model'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { SearchParam } from '../cache/models/search-param.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { Collection } from '../shared/collection.model'; +import { COLLECTION } from '../shared/collection.resource-type'; import { ContentSource } from '../shared/content-source.model'; +import { DSpaceObject } from '../shared/dspace-object.model'; +import { GenericConstructor } from '../shared/generic-constructor'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; import { configureRequest, filterSuccessfulResponses, getRequestFromRequestHref, getResponseFromEntry } from '../shared/operators'; -import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; -import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; -import { TranslateService } from '@ngx-translate/core'; -import { SearchParam } from '../cache/models/search-param.model'; +import { ComColDataService } from './comcol-data.service'; +import { CommunityDataService } from './community-data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; import { DSOResponseParsingService } from './dso-response-parsing.service'; +import { PaginatedList } from './paginated-list'; import { ResponseParsingService } from './parsing.service'; -import { GenericConstructor } from '../shared/generic-constructor'; -import { DSpaceObject } from '../shared/dspace-object.model'; -import { INotification } from '../../shared/notifications/models/notification.model'; -import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model'; +import { RemoteData } from './remote-data'; +import { + ContentSourceRequest, + FindListOptions, + GetRequest, + RestRequest, + UpdateContentSourceRequest +} from './request.models'; +import { RequestService } from './request.service'; @Injectable() +@dataService(COLLECTION) export class CollectionDataService extends ComColDataService { protected linkPath = 'collections'; protected errorTitle = 'collection.source.update.notifications.error.title'; @@ -55,7 +57,6 @@ export class CollectionDataService extends ComColDataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected cds: CommunityDataService, protected objectCache: ObjectCacheService, @@ -150,7 +151,7 @@ export class CollectionDataService extends ComColDataService { */ updateContentSource(collectionId: string, contentSource: ContentSource): Observable { const requestId = this.requestService.generateRequestId(); - const serializedContentSource = new DSpaceRESTv2Serializer(ContentSource).serialize(contentSource); + const serializedContentSource = new DSpaceSerializer(ContentSource).serialize(contentSource); const request$ = this.getHarvesterEndpoint(collectionId).pipe( take(1), map((href: string) => { @@ -208,8 +209,9 @@ export class CollectionDataService extends ComColDataService { * Fetches a list of items that are mapped to a collection * @param collectionId The id of the collection * @param searchOptions Search options to sort or filter out items + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved */ - getMappedItems(collectionId: string, searchOptions?: PaginatedSearchOptions): Observable>> { + getMappedItems(collectionId: string, searchOptions?: PaginatedSearchOptions, ...linksToFollow: Array>): Observable>> { const requestUuid = this.requestService.generateRequestId(); const href$ = this.getMappedItemsEndpoint(collectionId).pipe( @@ -231,7 +233,7 @@ export class CollectionDataService extends ComColDataService { configureRequest(this.requestService) ).subscribe(); - return this.rdbService.buildList(href$); + return this.rdbService.buildList(href$, ...linksToFollow); } protected getFindByParentHref(parentUUID: string): Observable { @@ -240,4 +242,13 @@ export class CollectionDataService extends ComColDataService { this.halService.getEndpoint('collections', `${communityEndpointHref}/${parentUUID}`)), ); } + + /** + * Returns {@link RemoteData} of {@link Collection} that is the owing collection of the given item + * @param item Item we want the owning collection of + */ + findOwningCollectionFor(item: Item): Observable> { + return this.findByHref(item._links.owningCollection.href); + } + } diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts index a7fcd205d4..fc487527b9 100644 --- a/src/app/core/data/comcol-data.service.spec.ts +++ b/src/app/core/data/comcol-data.service.spec.ts @@ -1,38 +1,31 @@ +import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; import { cold, getTestScheduler, hot } from 'jasmine-marbles'; +import { Observable, of as observableOf } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { GlobalConfig } from '../../../config'; import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { CoreState } from '../core.reducers'; +import { Community } from '../shared/community.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; import { ComColDataService } from './comcol-data.service'; import { CommunityDataService } from './community-data.service'; -import { FindListOptions, FindByIDRequest } from './request.models'; -import { RequestService } from './request.service'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { RequestEntry } from './request.reducer'; -import {Observable, of as observableOf} from 'rxjs'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; -import { Item } from '../shared/item.model'; -import { Community } from '../shared/community.model'; +import { FindByIDRequest, FindListOptions } from './request.models'; +import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; const LINK_NAME = 'test'; -/* tslint:disable:max-classes-per-file */ -class NormalizedTestObject extends NormalizedObject { -} - class TestService extends ComColDataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected EnvConfig: GlobalConfig, protected cds: CommunityDataService, @@ -52,8 +45,6 @@ class TestService extends ComColDataService { } } -/* tslint:enable:max-classes-per-file */ - describe('ComColDataService', () => { let scheduler: TestScheduler; let service: TestService; @@ -68,7 +59,6 @@ describe('ComColDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; const scopeID = 'd9d30c0c-69b7-4369-8397-ca67c888974d'; const options = Object.assign(new FindListOptions(), { @@ -102,7 +92,9 @@ describe('ComColDataService', () => { getObjectByUUID: cold('d-', { d: { _links: { - [LINK_NAME]: scopedEndpoint + [LINK_NAME]: { + href: scopedEndpoint + } } } }) @@ -113,7 +105,6 @@ describe('ComColDataService', () => { return new TestService( requestService, rdbService, - dataBuildService, store, EnvConfig, cds, diff --git a/src/app/core/data/comcol-data.service.ts b/src/app/core/data/comcol-data.service.ts index 2ce0362a4e..d83518a3b0 100644 --- a/src/app/core/data/comcol-data.service.ts +++ b/src/app/core/data/comcol-data.service.ts @@ -6,8 +6,10 @@ import { } from 'rxjs/operators'; import { merge as observableMerge, Observable, throwError as observableThrowError, combineLatest as observableCombineLatest } from 'rxjs'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; -import { NormalizedCommunity } from '../cache/models/normalized-community.model'; import { ObjectCacheService } from '../cache/object-cache.service'; +import { Community } from '../shared/community.model'; +import { HALLink } from '../shared/hal-link.model'; +import { HALResource } from '../shared/hal-resource.model'; import { CommunityDataService } from './community-data.service'; import { DataService } from './data.service'; @@ -70,8 +72,9 @@ export abstract class ComColDataService extends DataS const successResponses = responses.pipe( filter((response) => response.isSuccessful), mergeMap(() => this.objectCache.getObjectByUUID(options.scopeID)), - map((nc: NormalizedCommunity) => nc._links[linkPath]), - filter((href) => isNotEmpty(href)) + map((hr: HALResource) => hr._links[linkPath]), + filter((halLink: HALLink) => isNotEmpty(halLink)), + map((halLink: HALLink) => halLink.href) ); return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged(), share()); @@ -81,7 +84,9 @@ export abstract class ComColDataService extends DataS protected abstract getFindByParentHref(parentUUID: string): Observable; public findByParent(parentUUID: string, options: FindListOptions = {}): Observable>> { - const href$ = this.buildHrefFromFindOptions(this.getFindByParentHref(parentUUID), [], options); + const href$ = this.getFindByParentHref(parentUUID).pipe( + map((href: string) => this.buildHrefFromFindOptions(href, options)) + ); return this.findList(href$, options); } diff --git a/src/app/core/data/community-data.service.ts b/src/app/core/data/community-data.service.ts index 57bf64678f..123c3eccd1 100644 --- a/src/app/core/data/community-data.service.ts +++ b/src/app/core/data/community-data.service.ts @@ -1,25 +1,27 @@ -import { filter, switchMap, take } from 'rxjs/operators'; +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { filter, switchMap, take } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { CoreState } from '../core.reducers'; import { Community } from '../shared/community.model'; -import { ComColDataService } from './comcol-data.service'; -import { RequestService } from './request.service'; +import { COMMUNITY } from '../shared/community.resource-type'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { FindListOptions, FindListRequest } from './request.models'; -import { RemoteData } from './remote-data'; -import { hasValue } from '../../shared/empty.util'; -import { Observable } from 'rxjs'; -import { PaginatedList } from './paginated-list'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { ComColDataService } from './comcol-data.service'; import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { FindListOptions, FindListRequest } from './request.models'; +import { RequestService } from './request.service'; @Injectable() +@dataService(COMMUNITY) export class CommunityDataService extends ComColDataService { protected linkPath = 'communities'; protected topLinkPath = 'communities/search/top'; @@ -28,7 +30,6 @@ export class CommunityDataService extends ComColDataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, diff --git a/src/app/core/data/content-source-response-parsing.service.ts b/src/app/core/data/content-source-response-parsing.service.ts index 4e0490148b..95e25db613 100644 --- a/src/app/core/data/content-source-response-parsing.service.ts +++ b/src/app/core/data/content-source-response-parsing.service.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core'; -import { ResponseParsingService } from './parsing.service'; -import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; import { ContentSourceSuccessResponse, RestResponse } from '../cache/response.models'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { ContentSource } from '../shared/content-source.model'; import { MetadataConfig } from '../shared/metadata-config.model'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; @Injectable() /** @@ -17,11 +17,11 @@ export class ContentSourceResponseParsingService implements ResponseParsingServi parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; - const deserialized = new DSpaceRESTv2Serializer(ContentSource).deserialize(payload); + const deserialized = new DSpaceSerializer(ContentSource).deserialize(payload); let metadataConfigs = []; if (payload._embedded && payload._embedded.harvestermetadata && payload._embedded.harvestermetadata.configs) { - metadataConfigs = new DSpaceRESTv2Serializer(MetadataConfig).serializeArray(payload._embedded.harvestermetadata.configs); + metadataConfigs = new DSpaceSerializer(MetadataConfig).serializeArray(payload._embedded.harvestermetadata.configs); } deserialized.metadataConfigs = metadataConfigs; diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts index ca5f2cc12e..347dfa83a4 100644 --- a/src/app/core/data/data.service.spec.ts +++ b/src/app/core/data/data.service.spec.ts @@ -1,5 +1,4 @@ import { DataService } from './data.service'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; import { RequestService } from './request.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { CoreState } from '../core.reducers'; @@ -13,7 +12,6 @@ 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 { Item } from '../shared/item.model'; import * as uuidv4 from 'uuid/v4'; @@ -21,23 +19,19 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; const endpoint = 'https://rest.api/core'; -// tslint:disable:max-classes-per-file -class NormalizedTestObject extends NormalizedObject { -} - +/* tslint:disable:max-classes-per-file */ class TestService extends DataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected linkPath: string, protected halService: HALEndpointService, protected objectCache: ObjectCacheService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: ChangeAnalyzer + protected comparator: ChangeAnalyzer ) { super(); } @@ -46,9 +40,8 @@ class TestService extends DataService { return observableOf(endpoint); } } - -class DummyChangeAnalyzer implements ChangeAnalyzer { - diff(object1: NormalizedTestObject, object2: NormalizedTestObject): Operation[] { +class DummyChangeAnalyzer implements ChangeAnalyzer { + diff(object1: Item, object2: Item): Operation[] { return compare((object1 as any).metadata, (object2 as any).metadata); } @@ -63,9 +56,6 @@ describe('DataService', () => { 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 */ @@ -80,7 +70,6 @@ describe('DataService', () => { return new TestService( requestService, rdbService, - dataBuildService, store, endpoint, halService, @@ -184,13 +173,15 @@ describe('DataService', () => { operations = [{ op: 'replace', path: '/0/value', value: name2 } as Operation]; selfLink = 'https://rest.api/endpoint/1698f1d3-be98-4c51-9fd8-6bfedcbd59b7'; - dso = new DSpaceObject(); - dso.self = selfLink; - dso.metadata = [{ key: 'dc.title', value: name1 }]; + dso = Object.assign(new DSpaceObject(), { + _links: { self: { href: selfLink } }, + metadata: [{ key: 'dc.title', value: name1 }] + }); - dso2 = new DSpaceObject(); - dso2.self = selfLink; - dso2.metadata = [{ key: 'dc.title', value: name2 }]; + dso2 = Object.assign(new DSpaceObject(), { + _links: { self: { href: selfLink } }, + metadata: [{ key: 'dc.title', value: name2 }] + }); spyOn(service, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(dso)); spyOn(objectCache, 'addPatch'); @@ -207,3 +198,4 @@ describe('DataService', () => { }); }); }); +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 82fdb82008..3be1ef9768 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -1,5 +1,6 @@ import { HttpClient } from '@angular/common/http'; - +import { Store } from '@ngrx/store'; +import { Operation } from 'fast-json-patch'; import { Observable } from 'rxjs'; import { distinctUntilChanged, @@ -13,12 +14,28 @@ import { take, tap } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; - import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { getClassForType } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { SearchParam } from '../cache/models/search-param.model'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { ErrorResponse, RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { DSpaceObject } from '../shared/dspace-object.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { + configureRequest, + getRemoteDataPayload, + getResponseFromEntry, + getSucceededRemoteData +} from '../shared/operators'; import { URLCombiner } from '../url-combiner/url-combiner'; +import { ChangeAnalyzer } from './change-analyzer'; import { PaginatedList } from './paginated-list'; import { RemoteData } from './remote-data'; import { @@ -29,30 +46,13 @@ import { FindListRequest, GetRequest } from './request.models'; -import { RequestService } from './request.service'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { SearchParam } from '../cache/models/search-param.model'; -import { Operation } from 'fast-json-patch'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { DSpaceObject } from '../shared/dspace-object.model'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; -import { ErrorResponse, RestResponse } from '../cache/response.models'; -import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { CacheableObject } from '../cache/object-cache.reducer'; import { RequestEntry } from './request.reducer'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { ChangeAnalyzer } from './change-analyzer'; +import { RequestService } from './request.service'; import { RestRequestMethod } from './rest-request-method'; -import { getMapsToType } from '../cache/builders/build-decorators'; -import { CoreState } from '../core.reducers'; export abstract class DataService { protected abstract requestService: RequestService; protected abstract rdbService: RemoteDataBuildService; - protected abstract dataBuildService: NormalizedObjectBuildService; protected abstract store: Store; protected abstract linkPath: string; protected abstract halService: HALEndpointService; @@ -60,12 +60,21 @@ export abstract class DataService { protected abstract notificationsService: NotificationsService; protected abstract http: HttpClient; protected abstract comparator: ChangeAnalyzer; + /** * Allows subclasses to reset the response cache time. */ protected responseMsToLive: number; - public abstract getBrowseEndpoint(options: FindListOptions, linkPath?: string): Observable + /** + * Get the endpoint for browsing + * @param options The [[FindListOptions]] object + * @param linkPath The link path for the object + * @returns {Observable} + */ + getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable { + return this.halService.getEndpoint(this.linkPath); + } /** * Create the HREF with given options object @@ -76,12 +85,12 @@ export abstract class DataService { * Return an observable that emits created HREF */ protected getFindAllHref(options: FindListOptions = {}, linkPath?: string): Observable { - let result: Observable; + let result$: Observable; const args = []; - result = this.getBrowseEndpoint(options, linkPath).pipe(distinctUntilChanged()); + result$ = this.getBrowseEndpoint(options, linkPath).pipe(distinctUntilChanged()); - return this.buildHrefFromFindOptions(result, args, options); + return result$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args))); } /** @@ -93,10 +102,10 @@ export abstract class DataService { * Return an observable that emits created HREF */ protected getSearchByHref(searchMethod: string, options: FindListOptions = {}): Observable { - let result: Observable; + let result$: Observable; const args = []; - result = this.getSearchEndpoint(searchMethod); + result$ = this.getSearchEndpoint(searchMethod); if (hasValue(options.searchParams)) { options.searchParams.forEach((param: SearchParam) => { @@ -104,45 +113,58 @@ export abstract class DataService { }) } - return this.buildHrefFromFindOptions(result, args, options); + return result$.pipe(map((result: string) => this.buildHrefFromFindOptions(result, options, args))); } /** * Turn an options object into a query string and combine it with the given HREF * - * @param href$ The HREF to which the query string should be appended - * @param args Array with additional params to combine with query string + * @param href The HREF to which the query string should be appended * @param options The [[FindListOptions]] object + * @param extraArgs Array with additional params to combine with query string * @return {Observable} * Return an observable that emits created HREF */ - protected buildHrefFromFindOptions(href$: Observable, args: string[], options: FindListOptions): Observable { + protected buildHrefFromFindOptions(href: string, options: FindListOptions, extraArgs: string[] = []): string { + + let args = [...extraArgs]; if (hasValue(options.currentPage) && typeof options.currentPage === 'number') { /* TODO: this is a temporary fix for the pagination start index (0 or 1) discrepancy between the rest and the frontend respectively */ - args.push(`page=${options.currentPage - 1}`); + args = [...args, `page=${options.currentPage - 1}`]; } if (hasValue(options.elementsPerPage)) { - args.push(`size=${options.elementsPerPage}`); + args = [...args, `size=${options.elementsPerPage}`]; } if (hasValue(options.sort)) { - args.push(`sort=${options.sort.field},${options.sort.direction}`); + args = [...args, `sort=${options.sort.field},${options.sort.direction}`]; } if (hasValue(options.startsWith)) { - args.push(`startsWith=${options.startsWith}`); + args = [...args, `startsWith=${options.startsWith}`]; } if (isNotEmpty(args)) { - return href$.pipe(map((href: string) => new URLCombiner(href, `?${args.join('&')}`).toString())); + return new URLCombiner(href, `?${args.join('&')}`).toString(); } else { - return href$; + return href; } } - findAll(options: FindListOptions = {}): Observable>> { - return this.findList(this.getFindAllHref(options), options); + /** + * Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded + * info should be added to the objects + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findAll(options: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { + return this.findList(this.getFindAllHref(options), options, ...linksToFollow); } - protected findList(href$, options: FindListOptions) { + /** + * Returns an observable of {@link RemoteData} of an object, based on href observable, + * with a list of {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object + * @param href$ Observable of href of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + protected findList(href$, options: FindListOptions, ...linksToFollow: Array>) { href$.pipe( first((href: string) => hasValue(href))) .subscribe((href: string) => { @@ -153,7 +175,7 @@ export abstract class DataService { this.requestService.configure(request); }); - return this.rdbService.buildList(href$) as Observable>>; + return this.rdbService.buildList(href$, ...linksToFollow) as Observable>>; } /** @@ -165,7 +187,13 @@ export abstract class DataService { return `${endpoint}/${resourceID}`; } - findById(id: string): Observable> { + /** + * Returns an observable of {@link RemoteData} of an object, based on its ID, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the object + * @param id ID of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findById(id: string, ...linksToFollow: Array>): Observable> { const hrefObs = this.halService.getEndpoint(this.linkPath).pipe( map((endpoint: string) => this.getIDHref(endpoint, encodeURIComponent(id)))); @@ -180,16 +208,39 @@ export abstract class DataService { this.requestService.configure(request); }); - return this.rdbService.buildSingle(hrefObs); + return this.rdbService.buildSingle(hrefObs, ...linksToFollow); } - findByHref(href: string, options?: HttpOptions): Observable> { - const request = new GetRequest(this.requestService.generateRequestId(), href, null, options); + /** + * Returns an observable of {@link RemoteData} of an object, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the object + * @param href The url of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByHref(href: string, ...linksToFollow: Array>): Observable> { + const requestHref = this.buildHrefFromFindOptions(href, {}, []); + const request = new GetRequest(this.requestService.generateRequestId(), requestHref); if (hasValue(this.responseMsToLive)) { request.responseMsToLive = this.responseMsToLive; } this.requestService.configure(request); - return this.rdbService.buildSingle(href); + return this.rdbService.buildSingle(href, ...linksToFollow); + } + + /** + * Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the object + * @param href The url of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { + const requestHref = this.buildHrefFromFindOptions(href, findListOptions, []); + const request = new GetRequest(this.requestService.generateRequestId(), requestHref); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.configure(request); + return this.rdbService.buildList(requestHref, ...linksToFollow); } /** @@ -211,7 +262,7 @@ export abstract class DataService { * @return {Observable>} * Return an observable that emits response from the server */ - protected searchBy(searchMethod: string, options: FindListOptions = {}): Observable>> { + protected searchBy(searchMethod: string, options: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { const hrefObs = this.getSearchByHref(searchMethod, options); @@ -228,7 +279,7 @@ export abstract class DataService { switchMap((href) => this.requestService.getByHref(href)), skipWhile((requestEntry) => hasValue(requestEntry) && requestEntry.completed), switchMap((href) => - this.rdbService.buildList(hrefObs) as Observable>> + this.rdbService.buildList(hrefObs, ...linksToFollow) as Observable>> ) ); } @@ -248,18 +299,18 @@ export abstract class DataService { * @param {DSpaceObject} object The given object */ update(object: T): Observable> { - const oldVersion$ = this.findByHref(object.self); + const oldVersion$ = this.findByHref(object._links.self.href); return oldVersion$.pipe( getSucceededRemoteData(), getRemoteDataPayload(), mergeMap((oldVersion: T) => { - const operations = this.comparator.diff(oldVersion, object); - if (isNotEmpty(operations)) { - this.objectCache.addPatch(object.self, operations); + const operations = this.comparator.diff(oldVersion, object); + if (isNotEmpty(operations)) { + this.objectCache.addPatch(object._links.self.href, operations); + } + return this.findByHref(object._links.self.href); } - return this.findByHref(object.self); - } - )); + )); } /** @@ -279,8 +330,7 @@ export abstract class DataService { map((endpoint: string) => parentUUID ? `${endpoint}?parent=${parentUUID}` : endpoint) ); - const normalizedObject: NormalizedObject = this.dataBuildService.normalize(dso); - const serializedDso = new DSpaceRESTv2Serializer(getMapsToType((dso as any).type)).serialize(normalizedObject); + const serializedDso = new DSpaceSerializer(getClassForType((dso as any).type)).serialize(dso); const request$ = endpoint$.pipe( take(1), diff --git a/src/app/core/data/default-change-analyzer.service.ts b/src/app/core/data/default-change-analyzer.service.ts index 862c0e5b85..20218925fb 100644 --- a/src/app/core/data/default-change-analyzer.service.ts +++ b/src/app/core/data/default-change-analyzer.service.ts @@ -1,10 +1,10 @@ -import { Operation } from 'fast-json-patch/lib/core'; -import { compare } from 'fast-json-patch'; -import { ChangeAnalyzer } from './change-analyzer'; import { Injectable } from '@angular/core'; +import { compare } from 'fast-json-patch'; +import { Operation } from 'fast-json-patch/lib/core'; +import { getClassForType } from '../cache/builders/build-decorators'; import { CacheableObject } from '../cache/object-cache.reducer'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { ChangeAnalyzer } from './change-analyzer'; /** * A class to determine what differs between two @@ -12,19 +12,18 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec */ @Injectable() export class DefaultChangeAnalyzer implements ChangeAnalyzer { - constructor(private normalizeService: NormalizedObjectBuildService) { - } - /** * Compare the metadata of two CacheableObject and return the differences as * a JsonPatch Operation Array * - * @param {NormalizedObject} object1 + * @param {CacheableObject} object1 * The first object to compare - * @param {NormalizedObject} object2 + * @param {CacheableObject} object2 * The second object to compare */ - diff(object1: T | NormalizedObject, object2: T | NormalizedObject): Operation[] { - return compare(this.normalizeService.normalize(object1), this.normalizeService.normalize(object2)); + diff(object1: T, object2: T): Operation[] { + const serializer1 = new DSpaceSerializer(getClassForType(object1.type)); + const serializer2 = new DSpaceSerializer(getClassForType(object2.type)); + return compare(serializer1.serialize(object1), serializer2.serialize(object2)); } } diff --git a/src/app/core/data/dso-change-analyzer.service.ts b/src/app/core/data/dso-change-analyzer.service.ts index dd3487d3d0..dba8395bc5 100644 --- a/src/app/core/data/dso-change-analyzer.service.ts +++ b/src/app/core/data/dso-change-analyzer.service.ts @@ -1,7 +1,6 @@ import { Operation } from 'fast-json-patch/lib/core'; import { compare } from 'fast-json-patch'; import { ChangeAnalyzer } from './change-analyzer'; -import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model'; import { Injectable } from '@angular/core'; import { DSpaceObject } from '../shared/dspace-object.model'; @@ -16,12 +15,12 @@ export class DSOChangeAnalyzer implements ChangeAnalyzer * Compare the metadata of two DSpaceObjects and return the differences as * a JsonPatch Operation Array * - * @param {NormalizedDSpaceObject} object1 + * @param {DSpaceObject} object1 * The first object to compare - * @param {NormalizedDSpaceObject} object2 + * @param {DSpaceObject} object2 * The second object to compare */ - diff(object1: T | NormalizedDSpaceObject, object2: T | NormalizedDSpaceObject): Operation[] { + diff(object1: DSpaceObject, object2: DSpaceObject): Operation[] { return compare(object1.metadata, object2.metadata).map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path })); } } diff --git a/src/app/core/data/dso-redirect-data.service.spec.ts b/src/app/core/data/dso-redirect-data.service.spec.ts index 80507c4492..25a148d92b 100644 --- a/src/app/core/data/dso-redirect-data.service.spec.ts +++ b/src/app/core/data/dso-redirect-data.service.spec.ts @@ -7,7 +7,6 @@ import { RequestService } from './request.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { DsoRedirectDataService } from './dso-redirect-data.service'; import { Store } from '@ngrx/store'; import { CoreState } from '../core.reducers'; @@ -31,7 +30,6 @@ describe('DsoRedirectDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; const objectCache = {} as ObjectCacheService; let setup; beforeEach(() => { @@ -68,7 +66,6 @@ describe('DsoRedirectDataService', () => { service = new DsoRedirectDataService( requestService, rdbService, - dataBuildService, store, objectCache, halService, @@ -83,7 +80,7 @@ describe('DsoRedirectDataService', () => { describe('findById', () => { it('should call HALEndpointService with the path to the pid endpoint', () => { setup(); - scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE)); + scheduler.schedule(() => service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE)); scheduler.flush(); expect(halService.getEndpoint).toHaveBeenCalledWith('pid'); @@ -91,7 +88,7 @@ describe('DsoRedirectDataService', () => { it('should call HALEndpointService with the path to the dso endpoint', () => { setup(); - scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID)); + scheduler.schedule(() => service.findByIdAndIDType(dsoUUID, IdentifierType.UUID)); scheduler.flush(); expect(halService.getEndpoint).toHaveBeenCalledWith('dso'); @@ -99,7 +96,7 @@ describe('DsoRedirectDataService', () => { it('should call HALEndpointService with the path to the dso endpoint when identifier type not specified', () => { setup(); - scheduler.schedule(() => service.findById(dsoUUID)); + scheduler.schedule(() => service.findByIdAndIDType(dsoUUID)); scheduler.flush(); expect(halService.getEndpoint).toHaveBeenCalledWith('dso'); @@ -107,7 +104,7 @@ describe('DsoRedirectDataService', () => { it('should configure the proper FindByIDRequest for uuid', () => { setup(); - scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID)); + scheduler.schedule(() => service.findByIdAndIDType(dsoUUID, IdentifierType.UUID)); scheduler.flush(); expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestUUIDURL, dsoUUID)); @@ -115,7 +112,7 @@ describe('DsoRedirectDataService', () => { it('should configure the proper FindByIDRequest for handle', () => { setup(); - scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE)); + scheduler.schedule(() => service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE)); scheduler.flush(); expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestHandleURL, dsoHandle)); @@ -124,7 +121,7 @@ describe('DsoRedirectDataService', () => { it('should navigate to item route', () => { remoteData.payload.type = 'item'; setup(); - const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE); // The framework would normally subscribe but do it here so we can test navigation. redir.subscribe(); scheduler.schedule(() => redir); @@ -135,7 +132,7 @@ describe('DsoRedirectDataService', () => { it('should navigate to collections route', () => { remoteData.payload.type = 'collection'; setup(); - const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE); redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); @@ -145,7 +142,7 @@ describe('DsoRedirectDataService', () => { it('should navigate to communities route', () => { remoteData.payload.type = 'community'; setup(); - const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + const redir = service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE); redir.subscribe(); scheduler.schedule(() => redir); scheduler.flush(); diff --git a/src/app/core/data/dso-redirect-data.service.ts b/src/app/core/data/dso-redirect-data.service.ts index f4999637b3..232fde65d0 100644 --- a/src/app/core/data/dso-redirect-data.service.ts +++ b/src/app/core/data/dso-redirect-data.service.ts @@ -1,35 +1,32 @@ -import { DataService } from './data.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; import { HttpClient } from '@angular/common/http'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { RequestService } from './request.service'; -import { Store } from '@ngrx/store'; -import { CoreState } from '../core.reducers'; -import { FindListOptions, FindByIDRequest, IdentifierType } from './request.models'; -import { Observable } from 'rxjs'; -import { RemoteData } from './remote-data'; -import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; import { Injectable } from '@angular/core'; -import { filter, take, tap } from 'rxjs/operators'; -import { hasValue } from '../../shared/empty.util'; -import { getFinishedRemoteData } from '../shared/operators'; import { Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { take, tap } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { getFinishedRemoteData } from '../shared/operators'; +import { DataService } from './data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { RemoteData } from './remote-data'; +import { FindByIDRequest, IdentifierType } from './request.models'; +import { RequestService } from './request.service'; @Injectable() export class DsoRedirectDataService extends DataService { // Set the default link path to the identifier lookup endpoint. protected linkPath = 'pid'; - protected forceBypassCache = false; private uuidEndpoint = 'dso'; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -40,10 +37,6 @@ export class DsoRedirectDataService extends DataService { super(); } - getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable { - return this.halService.getEndpoint(linkPath); - } - setLinkPath(identifierType: IdentifierType) { // The default 'pid' endpoint for identifiers does not support uuid lookups. // For uuid lookups we need to change the linkPath. @@ -58,9 +51,9 @@ export class DsoRedirectDataService extends DataService { .replace(/\{\?uuid\}/, `?uuid=${resourceID}`); } - findById(id: string, identifierType = IdentifierType.UUID): Observable> { + findByIdAndIDType(id: string, identifierType = IdentifierType.UUID): Observable> { this.setLinkPath(identifierType); - return super.findById(id).pipe( + return this.findById(id).pipe( getFinishedRemoteData(), take(1), tap((response) => { diff --git a/src/app/core/data/dso-response-parsing.service.ts b/src/app/core/data/dso-response-parsing.service.ts index d2c21825cc..83676ce105 100644 --- a/src/app/core/data/dso-response-parsing.service.ts +++ b/src/app/core/data/dso-response-parsing.service.ts @@ -3,7 +3,6 @@ import { Inject, Injectable } from '@angular/core'; import { ObjectCacheService } from '../cache/object-cache.service'; import { GlobalConfig } from '../../../config/global-config.interface'; import { GLOBAL_CONFIG } from '../../../config'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; import { RestResponse, DSOSuccessResponse } from '../cache/response.models'; import { RestRequest } from './request.models'; @@ -30,7 +29,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem if (hasValue(data.payload) && hasValue(data.payload.page) && data.payload.page.totalElements === 0) { processRequestDTO = { page: [] }; } else { - processRequestDTO = this.process>(data.payload, request); + processRequestDTO = this.process(data.payload, request); } let objectList = processRequestDTO; @@ -42,7 +41,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem } else if (!Array.isArray(processRequestDTO)) { objectList = [processRequestDTO]; } - const selfLinks = objectList.map((no) => no.self); + const selfLinks = objectList.map((no) => no._links.self.href); return new DSOSuccessResponse(selfLinks, data.statusCode, data.statusText, this.processPageInfo(data.payload)) } diff --git a/src/app/core/data/dspace-object-data.service.spec.ts b/src/app/core/data/dspace-object-data.service.spec.ts index 7047db6065..b7c8c3fe9d 100644 --- a/src/app/core/data/dspace-object-data.service.spec.ts +++ b/src/app/core/data/dspace-object-data.service.spec.ts @@ -9,8 +9,6 @@ import { DSpaceObjectDataService } from './dspace-object-data.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; - describe('DSpaceObjectDataService', () => { let scheduler: TestScheduler; let service: DSpaceObjectDataService; @@ -46,12 +44,10 @@ describe('DSpaceObjectDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; service = new DSpaceObjectDataService( requestService, rdbService, - dataBuildService, objectCache, halService, notificationsService, diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts index 002ac3cdbc..38e9f8d888 100644 --- a/src/app/core/data/dspace-object-data.service.ts +++ b/src/app/core/data/dspace-object-data.service.ts @@ -1,19 +1,19 @@ +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { CoreState } from '../core.reducers'; import { DSpaceObject } from '../shared/dspace-object.model'; +import { DSPACE_OBJECT } from '../shared/dspace-object.resource-type'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { DataService } from './data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; import { RemoteData } from './remote-data'; import { RequestService } from './request.service'; -import { FindListOptions } from './request.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; /* tslint:disable:max-classes-per-file */ class DataServiceImpl extends DataService { @@ -22,7 +22,6 @@ class DataServiceImpl extends DataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -32,16 +31,13 @@ class DataServiceImpl extends DataService { super(); } - getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable { - return this.halService.getEndpoint(linkPath); - } - getIDHref(endpoint, resourceID): string { - return endpoint.replace(/\{\?uuid\}/,`?uuid=${resourceID}`); + return endpoint.replace(/\{\?uuid\}/, `?uuid=${resourceID}`); } } @Injectable() +@dataService(DSPACE_OBJECT) export class DSpaceObjectDataService { protected linkPath = 'dso'; private dataService: DataServiceImpl; @@ -49,13 +45,12 @@ export class DSpaceObjectDataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, protected comparator: DSOChangeAnalyzer) { - this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator); + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } findById(uuid: string): Observable> { diff --git a/src/app/core/data/entity-type-data.service.ts b/src/app/core/data/entity-type-data.service.ts new file mode 100644 index 0000000000..87de69b935 --- /dev/null +++ b/src/app/core/data/entity-type-data.service.ts @@ -0,0 +1,85 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ItemType } from '../shared/item-relationships/item-type.model'; +import { ITEM_TYPE } from '../shared/item-relationships/item-type.resource-type'; +import { DataService } from './data.service'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { FindListOptions } from './request.models'; +import { RequestService } from './request.service'; + +/* tslint:disable:max-classes-per-file */ + +/** + * A private DataService implementation to delegate specific methods to. + */ +class DataServiceImpl extends DataService { + protected linkPath = 'entitytypes'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } +} + +/** + * A service to retrieve {@link ItemType}s from the REST API. + */ +@Injectable() +@dataService(ITEM_TYPE) +export class ItemTypeDataService { + /** + * A private DataService instance to delegate specific methods to. + */ + private dataService: DataServiceImpl; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + } + + /** + * Returns an observable of {@link RemoteData} of an {@link ItemType}, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link ItemType} + * @param href The url of {@link ItemType} we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByHref(href: string, ...linksToFollow: Array>): Observable> { + return this.dataService.findByHref(href, ...linksToFollow); + } + + /** + * Returns a list of observables of {@link RemoteData} of {@link ItemType}s, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link ItemType} + * @param href The url of the {@link ItemType} we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByAllHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { + return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow); + } +} +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/data/entity-type.service.ts b/src/app/core/data/entity-type.service.ts index 583601d898..b8e8b7cd9a 100644 --- a/src/app/core/data/entity-type.service.ts +++ b/src/app/core/data/entity-type.service.ts @@ -1,7 +1,7 @@ +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { DataService } from './data.service'; import { RequestService } from './request.service'; 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 { HALEndpointService } from '../shared/hal-endpoint.service'; @@ -25,11 +25,9 @@ import {ItemType} from '../shared/item-relationships/item-type.model'; export class EntityTypeService extends DataService { protected linkPath = 'entitytypes'; - protected forceBypassCache = false; constructor(protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected halService: HALEndpointService, protected objectCache: ObjectCacheService, @@ -56,8 +54,9 @@ export class EntityTypeService extends DataService { /** * Get the allowed relationship types for an entity type * @param entityTypeId + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved */ - getEntityTypeRelationships(entityTypeId: string): Observable>> { + getEntityTypeRelationships(entityTypeId: string, ...linksToFollow: Array>): Observable>> { const href$ = this.getRelationshipTypesEndpoint(entityTypeId); @@ -66,7 +65,7 @@ export class EntityTypeService extends DataService { this.requestService.configure(request); }); - return this.rdbService.buildList(href$); + return this.rdbService.buildList(href$, ...linksToFollow); } /** diff --git a/src/app/core/data/external-source.service.spec.ts b/src/app/core/data/external-source.service.spec.ts index 77a2a85dfd..f891b46883 100644 --- a/src/app/core/data/external-source.service.spec.ts +++ b/src/app/core/data/external-source.service.spec.ts @@ -49,7 +49,7 @@ describe('ExternalSourceService', () => { halService = jasmine.createSpyObj('halService', { getEndpoint: observableOf('external-sources-REST-endpoint') }); - service = new ExternalSourceService(requestService, rdbService, undefined, undefined, undefined, halService, undefined, undefined, undefined); + service = new ExternalSourceService(requestService, rdbService, undefined, undefined, halService, undefined, undefined, undefined); } beforeEach(() => { diff --git a/src/app/core/data/external-source.service.ts b/src/app/core/data/external-source.service.ts index c32c13a20f..0c1a8d255c 100644 --- a/src/app/core/data/external-source.service.ts +++ b/src/app/core/data/external-source.service.ts @@ -3,7 +3,6 @@ import { DataService } from './data.service'; import { ExternalSource } from '../shared/external-source.model'; import { RequestService } from './request.service'; 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'; @@ -31,7 +30,6 @@ export class ExternalSourceService extends DataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, diff --git a/src/app/core/data/facet-config-response-parsing.service.ts b/src/app/core/data/facet-config-response-parsing.service.ts index 19b37f8b5d..3fc14b6495 100644 --- a/src/app/core/data/facet-config-response-parsing.service.ts +++ b/src/app/core/data/facet-config-response-parsing.service.ts @@ -1,17 +1,14 @@ import { Inject, Injectable } from '@angular/core'; -import { - FacetConfigSuccessResponse, - RestResponse -} from '../cache/response.models'; +import { GLOBAL_CONFIG } from '../../../config'; +import { GlobalConfig } from '../../../config/global-config.interface'; +import { SearchFilterConfig } from '../../shared/search/search-filter-config.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { FacetConfigSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { BaseResponseParsingService } from './base-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { SearchFilterConfig } from '../../shared/search/search-filter-config.model'; -import { BaseResponseParsingService } from './base-response-parsing.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { GlobalConfig } from '../../../config/global-config.interface'; -import { GLOBAL_CONFIG } from '../../../config'; @Injectable() export class FacetConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { @@ -24,7 +21,7 @@ export class FacetConfigResponseParsingService extends BaseResponseParsingServic parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const config = data.payload._embedded.facets; - const serializer = new DSpaceRESTv2Serializer(SearchFilterConfig); + const serializer = new DSpaceSerializer(SearchFilterConfig); const facetConfig = serializer.deserializeArray(config); return new FacetConfigSuccessResponse(facetConfig, data.statusCode, data.statusText); } diff --git a/src/app/core/data/facet-value-map-response-parsing.service.ts b/src/app/core/data/facet-value-map-response-parsing.service.ts index 64c8e87e7d..8c8c12dff7 100644 --- a/src/app/core/data/facet-value-map-response-parsing.service.ts +++ b/src/app/core/data/facet-value-map-response-parsing.service.ts @@ -1,19 +1,19 @@ import { Inject, Injectable } from '@angular/core'; +import { GLOBAL_CONFIG } from '../../../config'; +import { GlobalConfig } from '../../../config/global-config.interface'; +import { FacetValue } from '../../shared/search/facet-value.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { FacetValueMap, FacetValueMapSuccessResponse, FacetValueSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { BaseResponseParsingService } from './base-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { FacetValue } from '../../shared/search/facet-value.model'; -import { BaseResponseParsingService } from './base-response-parsing.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { GlobalConfig } from '../../../config/global-config.interface'; -import { GLOBAL_CONFIG } from '../../../config'; @Injectable() export class FacetValueMapResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { @@ -30,7 +30,7 @@ export class FacetValueMapResponseParsingService extends BaseResponseParsingServ const payload = data.payload; const facetMap: FacetValueMap = new FacetValueMap(); - const serializer = new DSpaceRESTv2Serializer(FacetValue); + const serializer = new DSpaceSerializer(FacetValue); payload._embedded.facets.map((facet) => { const values = facet._embedded.values.map((value) => {value.search = value._links.search.href; return value;}); const facetValues = serializer.deserializeArray(values); diff --git a/src/app/core/data/facet-value-response-parsing.service.ts b/src/app/core/data/facet-value-response-parsing.service.ts index 7fedc17545..c9ff93a1ae 100644 --- a/src/app/core/data/facet-value-response-parsing.service.ts +++ b/src/app/core/data/facet-value-response-parsing.service.ts @@ -1,14 +1,14 @@ import { Inject, Injectable } from '@angular/core'; -import { FacetValueSuccessResponse, RestResponse } from '../cache/response.models'; -import { ResponseParsingService } from './parsing.service'; -import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import {FacetValue} from '../../shared/search/facet-value.model'; -import { BaseResponseParsingService } from './base-response-parsing.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; import { GLOBAL_CONFIG } from '../../../config'; import { GlobalConfig } from '../../../config/global-config.interface'; +import { FacetValue } from '../../shared/search/facet-value.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { FacetValueSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { BaseResponseParsingService } from './base-response-parsing.service'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; @Injectable() export class FacetValueResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { @@ -21,7 +21,7 @@ export class FacetValueResponseParsingService extends BaseResponseParsingService parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; - const serializer = new DSpaceRESTv2Serializer(FacetValue); + const serializer = new DSpaceSerializer(FacetValue); // const values = payload._embedded.values.map((value) => {value.search = value._links.search.href; return value;}); const facetValues = serializer.deserializeArray(payload._embedded.values); diff --git a/src/app/core/data/item-data.service.spec.ts b/src/app/core/data/item-data.service.spec.ts index 8263601e28..06adfd5143 100644 --- a/src/app/core/data/item-data.service.spec.ts +++ b/src/app/core/data/item-data.service.spec.ts @@ -1,21 +1,20 @@ +import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; import { cold, getTestScheduler } from 'jasmine-marbles'; -import { TestScheduler } from 'rxjs/testing'; -import { BrowseService } from '../browse/browse.service'; -import { CoreState } from '../core.reducers'; -import { ItemDataService } from './item-data.service'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; import { Observable, of as observableOf } from 'rxjs'; -import { RestResponse } from '../cache/response.models'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { HttpClient } from '@angular/common/http'; -import { RequestEntry } from './request.reducer'; +import { TestScheduler } from 'rxjs/testing'; import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { BrowseService } from '../browse/browse.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; import { ExternalSourceEntry } from '../shared/external-source-entry.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ItemDataService } from './item-data.service'; +import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models'; +import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; describe('ItemDataService', () => { let scheduler: TestScheduler; @@ -45,7 +44,7 @@ describe('ItemDataService', () => { const objectCache = {} as ObjectCacheService; const halEndpointService = { getEndpoint(linkPath: string): Observable { - return cold('a', {a: itemEndpoint}); + return cold('a', { a: itemEndpoint }); } } as HALEndpointService; @@ -66,7 +65,6 @@ describe('ItemDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; const itemEndpoint = 'https://rest.api/core/items'; const ScopedItemEndpoint = `https://rest.api/core/items/${scopeID}`; @@ -83,7 +81,6 @@ describe('ItemDataService', () => { return new ItemDataService( requestService, rdbService, - dataBuildService, store, bs, objectCache, @@ -132,7 +129,7 @@ describe('ItemDataService', () => { it('should return the endpoint to withdraw and reinstate items', () => { const result = service.getItemWithdrawEndpoint(scopeID); - const expected = cold('a', {a: ScopedItemEndpoint}); + const expected = cold('a', { a: ScopedItemEndpoint }); expect(result).toBeObservable(expected); }); @@ -154,7 +151,7 @@ describe('ItemDataService', () => { it('should return the endpoint to make an item private or public', () => { const result = service.getItemDiscoverableEndpoint(scopeID); - const expected = cold('a', {a: ScopedItemEndpoint}); + const expected = cold('a', { a: ScopedItemEndpoint }); expect(result).toBeObservable(expected); }); @@ -201,7 +198,7 @@ describe('ItemDataService', () => { const externalSourceEntry = Object.assign(new ExternalSourceEntry(), { display: 'John, Doe', value: 'John, Doe', - self: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004' + _links: { self: { href: 'http://test-rest.com/server/api/integration/externalSources/orcidV2/entryValues/0000-0003-4851-8004' } } }); beforeEach(() => { diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts index cd7e70dc32..b9fb36e6d8 100644 --- a/src/app/core/data/item-data.service.ts +++ b/src/app/core/data/item-data.service.ts @@ -1,59 +1,62 @@ -import { distinctUntilChanged, filter, find, map, switchMap, take } from 'rxjs/operators'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; +import { distinctUntilChanged, filter, find, map, switchMap, tap } from 'rxjs/operators'; import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; -import { BrowseService } from '../browse/browse.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { CoreState } from '../core.reducers'; -import { Item } from '../shared/item.model'; -import { URLCombiner } from '../url-combiner/url-combiner'; - -import { DataService } from './data.service'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { - DeleteRequest, - FindListOptions, - MappedCollectionsRequest, - PatchRequest, - PostRequest, PutRequest, - RestRequest -} from './request.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { BrowseService } from '../browse/browse.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { GenericSuccessResponse, RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { Collection } from '../shared/collection.model'; +import { ExternalSourceEntry } from '../shared/external-source-entry.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { Item } from '../shared/item.model'; +import { ITEM } from '../shared/item.resource-type'; import { configureRequest, filterSuccessfulResponses, getRequestFromRequestHref, getResponseFromEntry } from '../shared/operators'; -import { RequestEntry } from './request.reducer'; -import { GenericSuccessResponse, RestResponse } from '../cache/response.models'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { Collection } from '../shared/collection.model'; -import { RemoteData } from './remote-data'; +import { URLCombiner } from '../url-combiner/url-combiner'; + +import { DataService } from './data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; import { PaginatedList } from './paginated-list'; -import { ExternalSourceEntry } from '../shared/external-source-entry.model'; +import { RemoteData } from './remote-data'; +import { + DeleteRequest, + FindListOptions, + MappedCollectionsRequest, + PatchRequest, + PostRequest, + PutRequest, + RestRequest +} from './request.models'; +import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; @Injectable() +@dataService(ITEM) export class ItemDataService extends DataService { protected linkPath = 'items'; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, private bs: BrowseService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, - protected comparator: DSOChangeAnalyzer) { + protected comparator: DSOChangeAnalyzer, + ) { super(); } @@ -238,7 +241,7 @@ export class ItemDataService extends DataService { hrefObs.pipe( find((href: string) => hasValue(href)), map((href: string) => { - const request = new PutRequest(requestId, href, collection.self, options); + const request = new PutRequest(requestId, href, collection._links.self.href, options); this.requestService.configure(request); }) ).subscribe(); @@ -266,7 +269,7 @@ export class ItemDataService extends DataService { href$.pipe( find((href: string) => hasValue(href)), map((href: string) => { - const request = new PostRequest(requestId, href, externalSourceEntry.self, options); + const request = new PostRequest(requestId, href, externalSourceEntry._links.self.href, options); this.requestService.configure(request); }) ).subscribe(); diff --git a/src/app/core/data/license-data.service.ts b/src/app/core/data/license-data.service.ts new file mode 100644 index 0000000000..23637be596 --- /dev/null +++ b/src/app/core/data/license-data.service.ts @@ -0,0 +1,85 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { License } from '../shared/license.model'; +import { LICENSE } from '../shared/license.resource-type'; +import { DataService } from './data.service'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { FindListOptions } from './request.models'; +import { RequestService } from './request.service'; + +/* tslint:disable:max-classes-per-file */ + +/** + * A private DataService implementation to delegate specific methods to. + */ +class DataServiceImpl extends DataService { + protected linkPath = ''; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } +} + +/** + * A service to retrieve {@link License}s from the REST API. + */ +@Injectable() +@dataService(LICENSE) +export class LicenseDataService { + /** + * A private DataService instance to delegate specific methods to. + */ + private dataService: DataServiceImpl; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); + } + + /** + * Returns an observable of {@link RemoteData} of a {@link License}, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link License} + * @param href The URL of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByHref(href: string, ...linksToFollow: Array>): Observable> { + return this.dataService.findByHref(href, ...linksToFollow); + } + + /** + * Returns a list of observables of {@link RemoteData} of {@link License}s, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link License} + * @param href The URL of object we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByAllHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { + return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow); + } +} +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/core/data/metadata-schema-data.service.ts b/src/app/core/data/metadata-schema-data.service.ts index 662eaa6c7c..915f588379 100644 --- a/src/app/core/data/metadata-schema-data.service.ts +++ b/src/app/core/data/metadata-schema-data.service.ts @@ -1,20 +1,19 @@ +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { CoreState } from '../core.reducers'; +import { MetadataSchema } from '../metadata/metadata-schema.model'; +import { METADATA_SCHEMA } from '../metadata/metadata-schema.resource-type'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ChangeAnalyzer } from './change-analyzer'; import { DataService } from './data.service'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { FindListOptions } from './request.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { HttpClient } from '@angular/common/http'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { ChangeAnalyzer } from './change-analyzer'; import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; -import { MetadataSchema } from '../metadata/metadata-schema.model'; +import { RequestService } from './request.service'; /* tslint:disable:max-classes-per-file */ class DataServiceImpl extends DataService { @@ -23,7 +22,6 @@ class DataServiceImpl extends DataService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -33,15 +31,13 @@ class DataServiceImpl extends DataService { super(); } - getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable { - return this.halService.getEndpoint(linkPath); - } } /** * A service responsible for fetching/sending data from/to the REST API on the metadataschemas endpoint */ @Injectable() +@dataService(METADATA_SCHEMA) export class MetadataSchemaDataService { private dataService: DataServiceImpl; @@ -52,9 +48,8 @@ export class MetadataSchemaDataService { protected halService: HALEndpointService, protected objectCache: ObjectCacheService, protected comparator: DefaultChangeAnalyzer, - protected dataBuildService: NormalizedObjectBuildService, protected http: HttpClient, protected notificationsService: NotificationsService) { - this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator); + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } } diff --git a/src/app/core/data/metadatafield-parsing.service.ts b/src/app/core/data/metadatafield-parsing.service.ts index 092285e9c5..08f7892ac7 100644 --- a/src/app/core/data/metadatafield-parsing.service.ts +++ b/src/app/core/data/metadatafield-parsing.service.ts @@ -1,10 +1,10 @@ -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { RestRequest } from './request.models'; -import { ResponseParsingService } from './parsing.service'; import { Injectable } from '@angular/core'; import { MetadatafieldSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { MetadataField } from '../metadata/metadata-field.model'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; /** * A service responsible for parsing DSpaceRESTV2Response data related to a single MetadataField to a valid RestResponse @@ -15,7 +15,7 @@ export class MetadatafieldParsingService implements ResponseParsingService { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; - const deserialized = new DSpaceRESTv2Serializer(MetadataField).deserialize(payload); + const deserialized = new DSpaceSerializer(MetadataField).deserialize(payload); return new MetadatafieldSuccessResponse(deserialized, data.statusCode, data.statusText); } diff --git a/src/app/core/data/metadataschema-parsing.service.ts b/src/app/core/data/metadataschema-parsing.service.ts index 3e9fd257bb..f4b90e5dcd 100644 --- a/src/app/core/data/metadataschema-parsing.service.ts +++ b/src/app/core/data/metadataschema-parsing.service.ts @@ -1,10 +1,10 @@ -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { RestRequest } from './request.models'; -import { ResponseParsingService } from './parsing.service'; import { Injectable } from '@angular/core'; import { MetadataschemaSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { MetadataSchema } from '../metadata/metadata-schema.model'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; @Injectable() export class MetadataschemaParsingService implements ResponseParsingService { @@ -12,7 +12,7 @@ export class MetadataschemaParsingService implements ResponseParsingService { parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { const payload = data.payload; - const deserialized = new DSpaceRESTv2Serializer(MetadataSchema).deserialize(payload); + const deserialized = new DSpaceSerializer(MetadataSchema).deserialize(payload); return new MetadataschemaSuccessResponse(deserialized, data.statusCode, data.statusText); } diff --git a/src/app/core/data/mydspace-response-parsing.service.ts b/src/app/core/data/mydspace-response-parsing.service.ts index bd5d5b1083..062bafab46 100644 --- a/src/app/core/data/mydspace-response-parsing.service.ts +++ b/src/app/core/data/mydspace-response-parsing.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { RestResponse, SearchSuccessResponse } from '../cache/response.models'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { DSOResponseParsingService } from './dso-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; import { hasValue } from '../../shared/empty.util'; import { SearchQueryResponse } from '../../shared/search/search-query-response.model'; import { MetadataMap, MetadataValue } from '../shared/metadata.models'; @@ -57,7 +57,7 @@ export class MyDSpaceResponseParsingService implements ResponseParsingService { _embedded: this.filterEmbeddedObjects(object) })); payload.objects = objects; - const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload); + const deserialized = new DSpaceSerializer(SearchQueryResponse).deserialize(payload); return new SearchSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(payload)); } diff --git a/src/app/core/data/object-updates/object-updates.actions.ts b/src/app/core/data/object-updates/object-updates.actions.ts index a3a95369fd..9df9acec8f 100644 --- a/src/app/core/data/object-updates/object-updates.actions.ts +++ b/src/app/core/data/object-updates/object-updates.actions.ts @@ -279,4 +279,6 @@ export type ObjectUpdatesAction | ReinstateObjectUpdatesAction | RemoveObjectUpdatesAction | RemoveFieldUpdateAction - | SelectVirtualMetadataAction; + | SelectVirtualMetadataAction + | SetEditableFieldUpdateAction + | SetValidFieldUpdateAction; diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts index b9de67a34d..9f05ca7889 100644 --- a/src/app/core/data/paginated-list.ts +++ b/src/app/core/data/paginated-list.ts @@ -56,14 +56,14 @@ export class PaginatedList { } set first(first: string) { - this.pageInfo.first = first; + this.pageInfo._links.first = { href: first }; } get prev(): string { return this.pageInfo.prev; } set prev(prev: string) { - this.pageInfo.prev = prev; + this.pageInfo._links.prev = { href: prev }; } get next(): string { @@ -71,7 +71,7 @@ export class PaginatedList { } set next(next: string) { - this.pageInfo.next = next; + this.pageInfo._links.next = { href: next }; } get last(): string { @@ -79,7 +79,7 @@ export class PaginatedList { } set last(last: string) { - this.pageInfo.last = last; + this.pageInfo._links.last = { href: last }; } get self(): string { @@ -87,7 +87,7 @@ export class PaginatedList { } set self(self: string) { - this.pageInfo.self = self; + this.pageInfo._links.self = { href: self }; } protected getPageLength() { diff --git a/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts b/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts index 899fee4d1e..1cbcf358e3 100644 --- a/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts +++ b/src/app/core/data/registry-bitstreamformats-response-parsing.service.ts @@ -1,11 +1,11 @@ +import { Injectable } from '@angular/core'; import { RegistryBitstreamformatsSuccessResponse, RestResponse } from '../cache/response.models'; -import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { RestRequest } from './request.models'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model'; import { DSOResponseParsingService } from './dso-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; -import { Injectable } from '@angular/core'; +import { RestRequest } from './request.models'; @Injectable() export class RegistryBitstreamformatsResponseParsingService implements ResponseParsingService { @@ -18,7 +18,7 @@ export class RegistryBitstreamformatsResponseParsingService implements ResponseP const bitstreamformats = payload._embedded.bitstreamformats; payload.bitstreamformats = bitstreamformats; - const deserialized = new DSpaceRESTv2Serializer(RegistryBitstreamformatsResponse).deserialize(payload); + const deserialized = new DSpaceSerializer(RegistryBitstreamformatsResponse).deserialize(payload); return new RegistryBitstreamformatsSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload.page)); } diff --git a/src/app/core/data/registry-metadatafields-response-parsing.service.ts b/src/app/core/data/registry-metadatafields-response-parsing.service.ts index a4bed3240e..cf9484c4c4 100644 --- a/src/app/core/data/registry-metadatafields-response-parsing.service.ts +++ b/src/app/core/data/registry-metadatafields-response-parsing.service.ts @@ -1,15 +1,12 @@ -import { - RegistryMetadatafieldsSuccessResponse, - RestResponse -} from '../cache/response.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { RestRequest } from './request.models'; -import { ResponseParsingService } from './parsing.service'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { DSOResponseParsingService } from './dso-response-parsing.service'; import { Injectable } from '@angular/core'; -import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model'; import { hasValue } from '../../shared/empty.util'; +import { RegistryMetadatafieldsSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model'; +import { DSOResponseParsingService } from './dso-response-parsing.service'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; @Injectable() export class RegistryMetadatafieldsResponseParsingService implements ResponseParsingService { @@ -30,7 +27,7 @@ export class RegistryMetadatafieldsResponseParsingService implements ResponsePar payload.metadatafields = metadatafields; - const deserialized = new DSpaceRESTv2Serializer(RegistryMetadatafieldsResponse).deserialize(payload); + const deserialized = new DSpaceSerializer(RegistryMetadatafieldsResponse).deserialize(payload); return new RegistryMetadatafieldsSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload)); } diff --git a/src/app/core/data/registry-metadataschemas-response-parsing.service.ts b/src/app/core/data/registry-metadataschemas-response-parsing.service.ts index d19b334131..416ed19dc2 100644 --- a/src/app/core/data/registry-metadataschemas-response-parsing.service.ts +++ b/src/app/core/data/registry-metadataschemas-response-parsing.service.ts @@ -1,12 +1,12 @@ -import { RegistryMetadataschemasSuccessResponse, RestResponse } from '../cache/response.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { RestRequest } from './request.models'; -import { ResponseParsingService } from './parsing.service'; -import { RegistryMetadataschemasResponse } from '../registry/registry-metadataschemas-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { DSOResponseParsingService } from './dso-response-parsing.service'; import { Injectable } from '@angular/core'; import { hasValue } from '../../shared/empty.util'; +import { RegistryMetadataschemasSuccessResponse, RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { RegistryMetadataschemasResponse } from '../registry/registry-metadataschemas-response.model'; +import { DSOResponseParsingService } from './dso-response-parsing.service'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; @Injectable() export class RegistryMetadataschemasResponseParsingService implements ResponseParsingService { @@ -22,7 +22,7 @@ export class RegistryMetadataschemasResponseParsingService implements ResponsePa } payload.metadataschemas = metadataschemas; - const deserialized = new DSpaceRESTv2Serializer(RegistryMetadataschemasResponse).deserialize(payload); + const deserialized = new DSpaceSerializer(RegistryMetadataschemasResponse).deserialize(payload); return new RegistryMetadataschemasSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(data.payload)); } diff --git a/src/app/core/data/relationship-type.service.spec.ts b/src/app/core/data/relationship-type.service.spec.ts index 118baf8738..0a86b4bc61 100644 --- a/src/app/core/data/relationship-type.service.spec.ts +++ b/src/app/core/data/relationship-type.service.spec.ts @@ -1,14 +1,15 @@ -import { RequestService } from './request.service'; -import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; -import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service'; -import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; -import { getMockRequestService } from '../../shared/mocks/mock-request.service'; -import { PaginatedList } from './paginated-list'; -import { PageInfo } from '../shared/page-info.model'; -import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; -import { RelationshipTypeService } from './relationship-type.service'; import { of as observableOf } from 'rxjs'; +import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service'; +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { ItemType } from '../shared/item-relationships/item-type.model'; +import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; +import { PageInfo } from '../shared/page-info.model'; +import { PaginatedList } from './paginated-list'; +import { RelationshipTypeService } from './relationship-type.service'; +import { RequestService } from './request.service'; describe('RelationshipTypeService', () => { let service: RelationshipTypeService; @@ -25,8 +26,10 @@ describe('RelationshipTypeService', () => { let relationshipType1; let relationshipType2; + let itemService; let buildList; let rdbService; + let objectCache; function init() { restEndpointURL = 'https://rest.api/relationshiptypes'; @@ -58,13 +61,29 @@ describe('RelationshipTypeService', () => { buildList = createSuccessfulRemoteDataObject(new PaginatedList(new PageInfo(), [relationshipType1, relationshipType2])); rdbService = getMockRemoteDataBuildService(undefined, observableOf(buildList)); + objectCache = Object.assign({ + /* tslint:disable:no-empty */ + remove: () => { + }, + hasBySelfLinkObservable: () => observableOf(false) + /* tslint:enable:no-empty */ + }) as ObjectCacheService; + + itemService = undefined; } function initTestService() { return new RelationshipTypeService( + itemService, requestService, + rdbService, + null, halService, - rdbService + objectCache, + null, + null, + null, + null ); } diff --git a/src/app/core/data/relationship-type.service.ts b/src/app/core/data/relationship-type.service.ts index 7978373b08..eefe663209 100644 --- a/src/app/core/data/relationship-type.service.ts +++ b/src/app/core/data/relationship-type.service.ts @@ -1,28 +1,49 @@ +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { filter, find, map, switchMap } from 'rxjs/operators'; -import { configureRequest, getSucceededRemoteData } from '../shared/operators'; -import { Observable } from 'rxjs/internal/Observable'; -import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; -import { RemoteData } from './remote-data'; -import { PaginatedList } from './paginated-list'; +import { Store } from '@ngrx/store'; import { combineLatest as observableCombineLatest } from 'rxjs'; -import { ItemType } from '../shared/item-relationships/item-type.model'; +import { Observable } from 'rxjs/internal/Observable'; +import { filter, find, map, switchMap } from 'rxjs/operators'; +import { AppState } from '../../app.reducer'; import { isNotUndefined } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { followLink } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ItemType } from '../shared/item-relationships/item-type.model'; +import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; +import { RELATIONSHIP_TYPE } from '../shared/item-relationships/relationship-type.resource-type'; +import { configureRequest, getSucceededRemoteData } from '../shared/operators'; +import { DataService } from './data.service'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { ItemDataService } from './item-data.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; import { FindListOptions, FindListRequest } from './request.models'; +import { RequestService } from './request.service'; /** - * The service handling all relationship requests + * The service handling all relationship type requests */ @Injectable() -export class RelationshipTypeService { +@dataService(RELATIONSHIP_TYPE) +export class RelationshipTypeService extends DataService { protected linkPath = 'relationshiptypes'; - constructor(protected requestService: RequestService, + constructor(protected itemService: ItemDataService, + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, protected halService: HALEndpointService, - protected rdbService: RemoteDataBuildService) { + protected objectCache: ObjectCacheService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer, + protected appStore: Store) { + super() } /** @@ -41,7 +62,7 @@ export class RelationshipTypeService { .pipe( map((endpointURL: string) => new FindListRequest(this.requestService.generateRequestId(), endpointURL, options)), configureRequest(this.requestService), - switchMap(() => this.rdbService.buildList(link$)) + switchMap(() => this.rdbService.buildList(link$, followLink('leftType'), followLink('rightType'))) ) as Observable>>; } diff --git a/src/app/core/data/relationship.service.spec.ts b/src/app/core/data/relationship.service.spec.ts index 99442da58d..247dce1619 100644 --- a/src/app/core/data/relationship.service.spec.ts +++ b/src/app/core/data/relationship.service.spec.ts @@ -1,26 +1,28 @@ -import { RelationshipService } from './relationship.service'; -import { RequestService } from './request.service'; -import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; -import { getMockRemoteDataBuildService } from '../../shared/mocks/mock-remote-data-build.service'; +import { Observable } from 'rxjs/internal/Observable'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { RequestEntry } from './request.reducer'; +import * as ItemRelationshipsUtils from '../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { getMockRemoteDataBuildServiceHrefMap } from '../../shared/mocks/mock-remote-data-build.service'; +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service-stub'; +import { createSuccessfulRemoteDataObject$, spyOnOperator } from '../../shared/testing/utils'; +import { followLink } from '../../shared/utils/follow-link-config.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; import { Relationship } from '../shared/item-relationships/relationship.model'; -import { RemoteData } from './remote-data'; -import { getMockRequestService } from '../../shared/mocks/mock-request.service'; import { Item } from '../shared/item.model'; -import { PaginatedList } from './paginated-list'; import { PageInfo } from '../shared/page-info.model'; -import { DeleteRequest } from './request.models'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { Observable } from 'rxjs/internal/Observable'; -import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; +import { PaginatedList } from './paginated-list'; +import { RelationshipService } from './relationship.service'; +import { RemoteData } from './remote-data'; +import { DeleteRequest, FindListOptions } from './request.models'; +import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; describe('RelationshipService', () => { let service: RelationshipService; let requestService: RequestService; - const restEndpointURL = 'https://rest.api/'; + const restEndpointURL = 'https://rest.api/core'; const relationshipsEndpointURL = `${restEndpointURL}/relationships`; const halService: any = new HALEndpointServiceStub(restEndpointURL); @@ -31,38 +33,68 @@ describe('RelationshipService', () => { rightwardType: 'isPublicationOfAuthor' }); + const ri1SelfLink = restEndpointURL + '/author1'; + const ri2SelfLink = restEndpointURL + '/author2'; + const itemSelfLink = restEndpointURL + '/publication'; + const relationship1 = Object.assign(new Relationship(), { - self: relationshipsEndpointURL + '/2', + _links: { + self: { + href: relationshipsEndpointURL + '/2' + }, + leftItem: { + href: ri1SelfLink + }, + rightItem: { + href: itemSelfLink + } + }, id: '2', uuid: '2', relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType)) }); const relationship2 = Object.assign(new Relationship(), { - self: relationshipsEndpointURL + '/3', + _links: { + self: { + href: relationshipsEndpointURL + '/3' + }, + leftItem: { + href: ri2SelfLink + }, + rightItem: { + href: itemSelfLink + }, + }, id: '3', uuid: '3', relationshipType: observableOf(new RemoteData(false, false, true, undefined, relationshipType)) }); - const relationships = [ relationship1, relationship2 ]; - - const item = Object.assign(new Item(), { - self: 'fake-item-url/publication', + const relationships = [relationship1, relationship2]; const item = Object.assign(new Item(), { id: 'publication', uuid: 'publication', - relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships))) + relationships: observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(new PageInfo(), relationships))), + _links: { + relationships: { href: restEndpointURL + '/publication/relationships' }, + self: { href: itemSelfLink } + } }); const relatedItem1 = Object.assign(new Item(), { - self: 'fake-item-url/author1', id: 'author1', - uuid: 'author1' + uuid: 'author1', + _links: { + self: { href: ri1SelfLink } + } }); const relatedItem2 = Object.assign(new Item(), { - self: 'fake-item-url/author2', id: 'author2', - uuid: 'author2' + uuid: 'author2', + _links: { + self: { href: ri2SelfLink } + } }); + relationship1.leftItem = getRemotedataObservable(relatedItem1); relationship1.rightItem = getRemotedataObservable(item); relationship2.leftItem = getRemotedataObservable(relatedItem2); @@ -70,10 +102,12 @@ describe('RelationshipService', () => { const relatedItems = [relatedItem1, relatedItem2]; const buildList$ = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [relatedItems])); - const rdbService = getMockRemoteDataBuildService(undefined, buildList$); + const relationships$ = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [relationships])); + const rdbService = getMockRemoteDataBuildServiceHrefMap(undefined, {'href': buildList$, 'https://rest.api/core/publication/relationships': relationships$}); const objectCache = Object.assign({ /* tslint:disable:no-empty */ - remove: () => {}, + remove: () => { + }, hasBySelfLinkObservable: () => observableOf(false) /* tslint:enable:no-empty */ }) as ObjectCacheService; @@ -89,7 +123,6 @@ describe('RelationshipService', () => { requestService, rdbService, null, - null, halService, objectCache, null, @@ -123,33 +156,104 @@ describe('RelationshipService', () => { }); it('should clear the cache of the related items', () => { - expect(objectCache.remove).toHaveBeenCalledWith(relatedItem1.self); - expect(objectCache.remove).toHaveBeenCalledWith(item.self); + expect(objectCache.remove).toHaveBeenCalledWith(relatedItem1._links.self.href); + expect(objectCache.remove).toHaveBeenCalledWith(item._links.self.href); expect(requestService.removeByHrefSubstring).toHaveBeenCalledWith(relatedItem1.self); expect(requestService.removeByHrefSubstring).toHaveBeenCalledWith(item.self); }); }); describe('getItemRelationshipsArray', () => { - it('should return the item\'s relationships in the form of an array', () => { + it('should return the item\'s relationships in the form of an array', (done) => { service.getItemRelationshipsArray(item).subscribe((result) => { - expect(result).toEqual(relationships); + result.forEach((relResult: any) => { + expect(relResult).toEqual(relationships); + }); + done(); }); }); }); describe('getRelatedItems', () => { - it('should return the related items', () => { - service.getRelatedItems(item).subscribe((result) => { - expect(result).toEqual(relatedItems); + let mockItem; + + beforeEach(() => { + mockItem = { uuid: 'someid' } as Item; + + spyOn(service, 'getItemRelationshipsArray').and.returnValue(observableOf(relationships)); + + spyOnOperator(ItemRelationshipsUtils, 'relationsToItems').and.returnValue((v) => v); + }); + + it('should call getItemRelationshipsArray with the correct params', (done) => { + service.getRelatedItems(mockItem).subscribe(() => { + expect(service.getItemRelationshipsArray).toHaveBeenCalledWith( + mockItem, + followLink('leftItem'), + followLink('rightItem'), + followLink('relationshipType') + ); + done(); + }); + }); + + it('should use the relationsToItems operator', (done) => { + service.getRelatedItems(mockItem).subscribe(() => { + expect(ItemRelationshipsUtils.relationsToItems).toHaveBeenCalledWith(mockItem.uuid); + done(); }); }); }); describe('getRelatedItemsByLabel', () => { - it('should return the related items by label', () => { - service.getRelatedItemsByLabel(item, relationshipType.rightwardType).subscribe((result) => { - expect(result.payload.page).toEqual(relatedItems); + let relationsList; + let mockItem; + let mockLabel; + let mockOptions; + + beforeEach(() => { + relationsList = new PaginatedList(new PageInfo({ + elementsPerPage: relationships.length, + totalElements: relationships.length, + currentPage: 1, + totalPages: 1 + }), relationships); + mockItem = { uuid: 'someid' } as Item; + mockLabel = 'label'; + mockOptions = { label: 'options' } as FindListOptions; + + const rd$ = createSuccessfulRemoteDataObject$(relationsList); + spyOn(service, 'getItemRelationshipsByLabel').and.returnValue(rd$); + + spyOnOperator(ItemRelationshipsUtils, 'paginatedRelationsToItems').and.returnValue((v) => v); + }); + + it('should call getItemRelationshipsByLabel with the correct params', (done) => { + service.getRelatedItemsByLabel( + mockItem, + mockLabel, + mockOptions + ).subscribe((result) => { + expect(service.getItemRelationshipsByLabel).toHaveBeenCalledWith( + mockItem, + mockLabel, + mockOptions, + followLink('leftItem'), + followLink('rightItem'), + followLink('relationshipType') + ); + done(); + }); + }); + + it('should use the paginatedRelationsToItems operator', (done) => { + service.getRelatedItemsByLabel( + mockItem, + mockLabel, + mockOptions + ).subscribe((result) => { + expect(ItemRelationshipsUtils.paginatedRelationsToItems).toHaveBeenCalledWith(mockItem.uuid); + done(); }); }); }) diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index 0448c18ec6..4dde567c99 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -1,47 +1,49 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { ReorderableRelationship } from '../../shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; -import { RequestService } from './request.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { MemoizedSelector, select, Store } from '@ngrx/store'; +import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators'; +import { + compareArraysUsingIds, + paginatedRelationsToItems, + relationsToItems +} from '../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { AppState, keySelector } from '../../app.reducer'; +import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; +import { ReorderableRelationship } from '../../shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; +import { + RemoveNameVariantAction, + SetNameVariantAction +} from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions'; +import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { SearchParam } from '../cache/models/search-param.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { RestResponse } from '../cache/response.models'; +import { CoreState } from '../core.reducers'; +import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; +import { Relationship } from '../shared/item-relationships/relationship.model'; +import { RELATIONSHIP } from '../shared/item-relationships/relationship.resource-type'; +import { Item } from '../shared/item.model'; import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; -import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models'; -import { Observable } from 'rxjs/internal/Observable'; -import { RestResponse } from '../cache/response.models'; -import { Item } from '../shared/item.model'; -import { Relationship } from '../shared/item-relationships/relationship.model'; -import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; -import { RemoteData, RemoteDataState } from './remote-data'; -import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs'; -import { PaginatedList } from './paginated-list'; -import { ItemDataService } from './item-data.service'; -import { - compareArraysUsingIds, - paginatedRelationsToItems, - relationsToItems -} from '../../+item-page/simple/item-types/shared/item-relationships-utils'; -import { ObjectCacheService } from '../cache/object-cache.service'; import { DataService } from './data.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { MemoizedSelector, select, Store } from '@ngrx/store'; -import { CoreState } from '../core.reducers'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; -import { SearchParam } from '../cache/models/search-param.model'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { AppState, keySelector } from '../../app.reducer'; -import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; -import { - RemoveNameVariantAction, - SetNameVariantAction -} from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions'; +import { ItemDataService } from './item-data.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData, RemoteDataState } from './remote-data'; +import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models'; +import { RequestService } from './request.service'; const relationshipListsStateSelector = (state: AppState) => state.relationshipLists; @@ -57,14 +59,13 @@ const relationshipStateSelector = (listID: string, itemID: string): MemoizedSele * The service handling all relationship requests */ @Injectable() +@dataService(RELATIONSHIP) export class RelationshipService extends DataService { protected linkPath = 'relationships'; - protected forceBypassCache = false; constructor(protected itemService: ItemDataService, protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected halService: HALEndpointService, protected objectCache: ObjectCacheService, @@ -75,10 +76,6 @@ export class RelationshipService extends DataService { super(); } - getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable { - return this.halService.getEndpoint(linkPath); - } - /** * Get the endpoint for a relationship by ID * @param uuid @@ -165,29 +162,29 @@ export class RelationshipService extends DataService { * @param item The item to remove from the cache */ private removeRelationshipItemsFromCache(item) { - this.objectCache.remove(item.self); + this.objectCache.remove(item._links.self.href); this.requestService.removeByHrefSubstring(item.uuid); combineLatest( - this.objectCache.hasBySelfLinkObservable(item.self), + this.objectCache.hasBySelfLinkObservable(item._links.self.href), this.requestService.hasByHrefObservable(item.uuid) ).pipe( filter(([existsInOC, existsInRC]) => !existsInOC && !existsInRC), take(1), - switchMap(() => this.itemService.findByHref(item.self).pipe(take(1))) + switchMap(() => this.itemService.findByHref(item._links.self.href).pipe(take(1))) ).subscribe(); } /** - * Get an item its relationships in the form of an array + * Get an item's relationships in the form of an array * @param item */ - getItemRelationshipsArray(item: Item): Observable { - return item.relationships.pipe( + getItemRelationshipsArray(item: Item, ...linksToFollow: Array>): Observable { + return this.findAllByHref(item._links.relationships.href, undefined, ...linksToFollow).pipe( getSucceededRemoteData(), getRemoteDataPayload(), map((rels: PaginatedList) => rels.page), hasValueOperator(), - distinctUntilChanged(compareArraysUsingIds()) + distinctUntilChanged(compareArraysUsingIds()), ); } @@ -197,7 +194,7 @@ export class RelationshipService extends DataService { * @param item */ getRelationshipTypeLabelsByItem(item: Item): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe( switchMap((relationships: Relationship[]) => observableCombineLatest(relationships.map((relationship: Relationship) => this.getRelationshipTypeLabelByRelationshipAndItem(relationship, item)))), map((labels: string[]) => Array.from(new Set(labels))) ); @@ -226,7 +223,12 @@ export class RelationshipService extends DataService { * @param item */ getRelatedItems(item: Item): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray( + item, + followLink('leftItem'), + followLink('rightItem'), + followLink('relationshipType') + ).pipe( relationsToItems(item.uuid) ); } @@ -239,17 +241,18 @@ export class RelationshipService extends DataService { * @param options */ getRelatedItemsByLabel(item: Item, label: string, options?: FindListOptions): Observable>> { - return this.getItemRelationshipsByLabel(item, label, options).pipe(paginatedRelationsToItems(item.uuid)); + return this.getItemRelationshipsByLabel(item, label, options, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe(paginatedRelationsToItems(item.uuid)); } /** - * Resolve a given item's relationships into related items, filtered by a relationship label - * and return the items as an array + * Resolve a given item's relationships by label + * This should move to the REST API. + * * @param item * @param label * @param options */ - getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions): Observable>> { + getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { let findListOptions = new FindListOptions(); if (options) { findListOptions = Object.assign(new FindListOptions(), options); @@ -260,7 +263,7 @@ export class RelationshipService extends DataService { } else { findListOptions.searchParams = searchParams; } - return this.searchBy('byLabel', findListOptions); + return this.searchBy('byLabel', findListOptions, ...linksToFollow); } /** @@ -270,7 +273,7 @@ export class RelationshipService extends DataService { * @param uuids */ getRelationshipsByRelatedItemIds(item: Item, uuids: string[]): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem')).pipe( switchMap((relationships: Relationship[]) => { return observableCombineLatest(...relationships.map((relationship: Relationship) => { const isLeftItem$ = this.isItemInUUIDArray(relationship.leftItem, uuids); @@ -300,8 +303,8 @@ export class RelationshipService extends DataService { * @param item2 The second item in the relationship * @param label The rightward or leftward type of the relationship */ - getRelationshipByItemsAndLabel(item1: Item, item2: Item, label: string): Observable { - return this.getItemRelationshipsByLabel(item1, label) + getRelationshipByItemsAndLabel(item1: Item, item2: Item, label: string, options?: FindListOptions): Observable { + return this.getItemRelationshipsByLabel(item1, label, options, followLink('relationshipType'), followLink('leftItem'), followLink('rightItem')) .pipe( getSucceededRemoteData(), isNotEmptyOperator(), @@ -443,19 +446,12 @@ export class RelationshipService extends DataService { clearRelatedCache(uuid: string): Observable { return this.findById(uuid).pipe( getSucceededRemoteData(), - switchMap((rd: RemoteData) => - observableCombineLatest( - rd.payload.leftItem.pipe(getSucceededRemoteData()), - rd.payload.rightItem.pipe(getSucceededRemoteData()) - ) - ), - take(1), - map(([leftItem, rightItem]) => { - this.objectCache.remove(leftItem.payload.self); - this.objectCache.remove(rightItem.payload.self); - this.requestService.removeByHrefSubstring(leftItem.payload.self); - this.requestService.removeByHrefSubstring(rightItem.payload.self); - }), + map((rd: RemoteData) => { + this.objectCache.remove(rd.payload._links.leftItem.href); + this.objectCache.remove(rd.payload._links.rightItem.href); + this.requestService.removeByHrefSubstring(rd.payload._links.leftItem.href); + this.requestService.removeByHrefSubstring(rd.payload._links.rightItem.href); + }) ); } } diff --git a/src/app/core/data/request.effects.ts b/src/app/core/data/request.effects.ts index 9ef85bfe8b..a9052aa8dc 100644 --- a/src/app/core/data/request.effects.ts +++ b/src/app/core/data/request.effects.ts @@ -1,12 +1,17 @@ -import { Observable, of as observableOf } from 'rxjs'; import { Inject, Injectable, Injector } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Observable, of as observableOf } from 'rxjs'; +import { catchError, filter, flatMap, map, take } from 'rxjs/operators'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { StoreActionTypes } from '../../store.actions'; +import { getClassForType } from '../cache/builders/build-decorators'; +import { ErrorResponse, RestResponse } from '../cache/response.models'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; import { DSpaceRESTv2Service } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { RequestActionTypes, RequestCompleteAction, @@ -16,11 +21,6 @@ import { import { RequestError, RestRequest } from './request.models'; import { RequestEntry } from './request.reducer'; import { RequestService } from './request.service'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { catchError, filter, flatMap, map, take, tap } from 'rxjs/operators'; -import { ErrorResponse, RestResponse } from '../cache/response.models'; -import { StoreActionTypes } from '../../store.actions'; -import { getMapsToType } from '../cache/builders/build-decorators'; export const addToResponseCacheAndCompleteAction = (request: RestRequest, envConfig: GlobalConfig) => (source: Observable): Observable => @@ -45,7 +45,7 @@ export class RequestEffects { flatMap((request: RestRequest) => { let body; if (isNotEmpty(request.body)) { - const serializer = new DSpaceRESTv2Serializer(getMapsToType(request.body.type)); + const serializer = new DSpaceSerializer(getClassForType(request.body.type)); body = serializer.serialize(request.body); } return this.restApi.request(request.method, request.href, body, request.options).pipe( diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index 07ea8c9c4b..df9c7d5bbb 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -159,6 +159,8 @@ export class FindListRequest extends GetRequest { } export class EndpointMapRequest extends GetRequest { + public responseMsToLive = Number.MAX_SAFE_INTEGER; + constructor( uuid: string, href: string, diff --git a/src/app/core/data/request.reducer.spec.ts b/src/app/core/data/request.reducer.spec.ts index 65a4ddba17..d32fe348b5 100644 --- a/src/app/core/data/request.reducer.spec.ts +++ b/src/app/core/data/request.reducer.spec.ts @@ -1,13 +1,15 @@ import * as deepFreeze from 'deep-freeze'; - -import { requestReducer, RequestState } from './request.reducer'; +import { RestResponse } from '../cache/response.models'; import { RequestCompleteAction, RequestConfigureAction, - RequestExecuteAction, RequestRemoveAction, ResetResponseTimestampsAction + RequestExecuteAction, + RequestRemoveAction, + ResetResponseTimestampsAction } from './request.actions'; import { GetRequest } from './request.models'; -import { RestResponse } from '../cache/response.models'; + +import { requestReducer, RequestState } from './request.reducer'; const response = new RestResponse(true, 200, 'OK'); class NullAction extends RequestCompleteAction { diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index 01560380c2..017721fdf9 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -2,6 +2,7 @@ import * as ngrx from '@ngrx/store'; import { ActionsSubject, Store } from '@ngrx/store'; import { cold, getTestScheduler, hot } from 'jasmine-marbles'; import { BehaviorSubject, EMPTY, of as observableOf } from 'rxjs'; +import { TestScheduler } from 'rxjs/testing'; import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service'; import { defaultUUID, getMockUUIDService } from '../../shared/mocks/mock-uuid.service'; @@ -19,9 +20,8 @@ import { PutRequest, RestRequest } from './request.models'; -import { RequestService } from './request.service'; -import { TestScheduler } from 'rxjs/testing'; import { RequestEntry } from './request.reducer'; +import { RequestService } from './request.service'; describe('RequestService', () => { let scheduler: TestScheduler; diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index b811a75549..1101c851ac 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -71,7 +71,9 @@ const getUuidsFromHrefSubstring = (state: IndexState, href: string): string[] => /** * A service to interact with the request state in the store */ -@Injectable() +@Injectable({ + providedIn: 'root' +}) export class RequestService { private requestsOnTheirWayToTheStore: string[] = []; @@ -216,7 +218,7 @@ export class RequestService { * @param {GetRequest} request The request to check * @returns {boolean} True if the request is cached or still pending */ - private isCachedOrPending(request: GetRequest): boolean { + public isCachedOrPending(request: GetRequest): boolean { const inReqCache = this.hasByHref(request.href); const inObjCache = this.objectCache.hasBySelfLink(request.href); const isCached = inReqCache || inObjCache; diff --git a/src/app/core/data/resource-policy.service.spec.ts b/src/app/core/data/resource-policy.service.spec.ts index 1a02171be3..abed805ca3 100644 --- a/src/app/core/data/resource-policy.service.spec.ts +++ b/src/app/core/data/resource-policy.service.spec.ts @@ -1,15 +1,13 @@ +import { HttpClient } from '@angular/common/http'; import { cold, getTestScheduler } from 'jasmine-marbles'; import { TestScheduler } from 'rxjs/testing'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { ResourcePolicy } from '../shared/resource-policy.model'; +import { ObjectCacheService } from '../cache/object-cache.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { GetRequest } from './request.models'; +import { ResourcePolicy } from '../shared/resource-policy.model'; import { RequestService } from './request.service'; import { ResourcePolicyService } from './resource-policy.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; describe('ResourcePolicyService', () => { let scheduler: TestScheduler; @@ -42,26 +40,26 @@ describe('ResourcePolicyService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; service = new ResourcePolicyService( requestService, rdbService, - dataBuildService, objectCache, halService, notificationsService, http, comparator - ) + ); + + spyOn((service as any).dataService, 'findByHref').and.callThrough(); }); describe('findByHref', () => { - it('should configure the proper GetRequest', () => { + it('should proxy the call to dataservice.findByHref', () => { scheduler.schedule(() => service.findByHref(requestURL)); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, null)); + expect((service as any).dataService.findByHref).toHaveBeenCalledWith(requestURL); }); it('should return a RemoteData for the object with the given URL', () => { diff --git a/src/app/core/data/resource-policy.service.ts b/src/app/core/data/resource-policy.service.ts index 017e5cf5ee..f66032925e 100644 --- a/src/app/core/data/resource-policy.service.ts +++ b/src/app/core/data/resource-policy.service.ts @@ -3,10 +3,13 @@ import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { dataService } from '../cache/builders/build-decorators'; import { DataService } from '../data/data.service'; import { RequestService } from '../data/request.service'; import { FindListOptions } from '../data/request.models'; +import { Collection } from '../shared/collection.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { ResourcePolicy } from '../shared/resource-policy.model'; import { RemoteData } from '../data/remote-data'; @@ -14,19 +17,22 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv import { CoreState } from '../core.reducers'; import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { RESOURCE_POLICY } from '../shared/resource-policy.resource-type'; import { ChangeAnalyzer } from './change-analyzer'; import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; -import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; +import { PaginatedList } from './paginated-list'; /* tslint:disable:max-classes-per-file */ + +/** + * A private DataService implementation to delegate specific methods to. + */ class DataServiceImpl extends DataService { protected linkPath = 'resourcepolicies'; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -36,31 +42,54 @@ class DataServiceImpl extends DataService { super(); } - getBrowseEndpoint(options: FindListOptions = {}, linkPath: string = this.linkPath): Observable { - return this.halService.getEndpoint(linkPath); - } } /** * A service responsible for fetching/sending data from/to the REST API on the resourcepolicies endpoint */ @Injectable() +@dataService(RESOURCE_POLICY) export class ResourcePolicyService { private dataService: DataServiceImpl; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, protected notificationsService: NotificationsService, protected http: HttpClient, protected comparator: DefaultChangeAnalyzer) { - this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, notificationsService, http, comparator); + this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator); } - findByHref(href: string, options?: HttpOptions): Observable> { - return this.dataService.findByHref(href, options); + /** + * Returns an observable of {@link RemoteData} of a {@link ResourcePolicy}, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link ResourcePolicy} + * @param href The url of {@link ResourcePolicy} we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findByHref(href: string, ...linksToFollow: Array>): Observable> { + return this.dataService.findByHref(href, ...linksToFollow); + } + + /** + * Returns a list of observables of {@link RemoteData} of {@link ResourcePolicy}s, based on an href, with a list of {@link FollowLinkConfig}, + * to automatically resolve {@link HALLink}s of the {@link ResourcePolicy} + * @param href The url of the {@link ResourcePolicy} we want to retrieve + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved + */ + findAllByHref(href: string, findListOptions: FindListOptions = {}, ...linksToFollow: Array>): Observable>> { + return this.dataService.findAllByHref(href, findListOptions, ...linksToFollow); + } + + /** + * Return the defaultAccessConditions {@link ResourcePolicy} list for a given {@link Collection} + * + * @param collection the {@link Collection} to retrieve the defaultAccessConditions for + * @param findListOptions the {@link FindListOptions} for the request + */ + getDefaultAccessConditionsFor(collection: Collection, findListOptions?: FindListOptions): Observable>> { + return this.dataService.findAllByHref(collection._links.defaultAccessConditions.href, findListOptions); } } diff --git a/src/app/core/data/search-response-parsing.service.ts b/src/app/core/data/search-response-parsing.service.ts index c449fa872f..ed47250922 100644 --- a/src/app/core/data/search-response-parsing.service.ts +++ b/src/app/core/data/search-response-parsing.service.ts @@ -1,13 +1,13 @@ import { Injectable } from '@angular/core'; +import { hasValue } from '../../shared/empty.util'; +import { SearchQueryResponse } from '../../shared/search/search-query-response.model'; import { RestResponse, SearchSuccessResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; +import { MetadataMap, MetadataValue } from '../shared/metadata.models'; import { DSOResponseParsingService } from './dso-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; import { RestRequest } from './request.models'; -import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { hasValue } from '../../shared/empty.util'; -import { SearchQueryResponse } from '../../shared/search/search-query-response.model'; -import { MetadataMap, MetadataValue } from '../shared/metadata.models'; @Injectable() export class SearchResponseParsingService implements ResponseParsingService { @@ -42,10 +42,6 @@ export class SearchResponseParsingService implements ResponseParsingService { const dsoSelfLinks = payload._embedded.objects .filter((object) => hasValue(object._embedded)) .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 - .map((dso) => Object.assign({}, dso, { _embedded: undefined })) .map((dso) => this.dsoParser.parse(request, { payload: dso, statusCode: data.statusCode, @@ -59,13 +55,9 @@ export class SearchResponseParsingService implements ResponseParsingService { .map((object, index) => Object.assign({}, object, { 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 - // until objs until partial results are supported by the rest api - _embedded: undefined })); payload.objects = objects; - const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload); + const deserialized = new DSpaceSerializer(SearchQueryResponse).deserialize(payload); return new SearchSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(payload)); } } diff --git a/src/app/core/data/site-data.service.spec.ts b/src/app/core/data/site-data.service.spec.ts index 6148135f50..6938cd65a9 100644 --- a/src/app/core/data/site-data.service.spec.ts +++ b/src/app/core/data/site-data.service.spec.ts @@ -8,7 +8,6 @@ import { Store } from '@ngrx/store'; import { CoreState } from '../core.reducers'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { of as observableOf } from 'rxjs'; import { RestResponse } from '../cache/response.models'; @@ -63,12 +62,10 @@ describe('SiteDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = {} as NormalizedObjectBuildService; service = new SiteDataService( requestService, rdbService, - dataBuildService, store, objectCache, halService, diff --git a/src/app/core/data/site-data.service.ts b/src/app/core/data/site-data.service.ts index c1a1b2069b..7b2bfdb543 100644 --- a/src/app/core/data/site-data.service.ts +++ b/src/app/core/data/site-data.service.ts @@ -1,35 +1,34 @@ -import { DataService } from './data.service'; -import { Site } from '../shared/site.model'; -import { RequestService } from './request.service'; -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 { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; -import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; -import { FindListOptions } from './request.models'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { RemoteData } from './remote-data'; -import { PaginatedList } from './paginated-list'; -import { Injectable } from '@angular/core'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; import { getSucceededRemoteData } from '../shared/operators'; +import { Site } from '../shared/site.model'; +import { SITE } from '../shared/site.resource-type'; +import { DataService } from './data.service'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { PaginatedList } from './paginated-list'; +import { RemoteData } from './remote-data'; +import { RequestService } from './request.service'; /** * Service responsible for handling requests related to the Site object */ @Injectable() +@dataService(SITE) export class SiteDataService extends DataService {​ protected linkPath = 'sites'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -40,15 +39,6 @@ export class SiteDataService extends DataService {​ super(); } - /** - * Get the endpoint for browsing the site object - * @param {FindListOptions} options - * @param {Observable} linkPath - */ - getBrowseEndpoint(options: FindListOptions, linkPath?: string): Observable { - return this.halService.getEndpoint(this.linkPath); - } - /** * Retrieve the Site Object */ diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts b/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts deleted file mode 100644 index 8431d6f8b3..0000000000 --- a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { autoserialize, autoserializeAs } from 'cerialize'; - -import { DSpaceRESTv2Serializer } from './dspace-rest-v2.serializer'; - -class TestModel { - @autoserialize - id: string; - - @autoserialize - name: string; - - @autoserializeAs(TestModel) - parents?: TestModel[]; -} - -const testModels = [ - { - id: 'd4466d54-d73b-4d8f-b73f-c702020baa14', - name: 'Model 1', - }, - { - id: '752a1250-949a-46ad-9bea-fbc45f0b656d', - name: 'Model 2', - } -]; - -const testResponses = [ - { - _links: { - self: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60', - parents: [ - { href: '/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78' }, - { href: '/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5' } - ] - }, - id: '9e32a2e2-6b91-4236-a361-995ccdc14c60', - type: 'testModels', - name: 'A Test Model' - }, - { - _links: { - self: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad', - parents: [ - { href: '/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5' }, - { href: '/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78' } - ] - }, - id: '598ce822-c357-46f3-ab70-63724d02d6ad', - type: 'testModels', - name: 'Another Test Model' - } -]; - -const parentHrefRegex = /^\/testmodels\/(.+)$/g; - -describe('DSpaceRESTv2Serializer', () => { - - describe('serialize', () => { - - it('should turn a model in to a valid document', () => { - const serializer = new DSpaceRESTv2Serializer(TestModel); - const doc = serializer.serialize(testModels[0]); - expect(testModels[0].id).toBe(doc.id); - expect(testModels[0].name).toBe(doc.name); - }); - - }); - - describe('serializeArray', () => { - - it('should turn an array of models in to a valid document', () => { - const serializer = new DSpaceRESTv2Serializer(TestModel); - const doc = serializer.serializeArray(testModels); - - expect(testModels[0].id).toBe(doc[0].id); - expect(testModels[0].name).toBe(doc[0].name); - expect(testModels[1].id).toBe(doc[1].id); - expect(testModels[1].name).toBe(doc[1].name); - }); - - }); - - describe('deserialize', () => { - - it('should turn a valid document describing a single entity in to a valid model', () => { - const serializer = new DSpaceRESTv2Serializer(TestModel); - const model = serializer.deserialize(testResponses[0]); - - expect(model.id).toBe(testResponses[0].id); - expect(model.name).toBe(testResponses[0].name); - }); - - // TODO: cant implement/test this yet - depends on how relationships - // will be handled in the rest api - // it('should retain relationship information', () => { - // const serializer = new DSpaceRESTv2Serializer(TestModel); - // const doc = { - // '_embedded': testResponses[0], - // }; - // - // const model = serializer.deserialize(doc); - // - // console.log(model); - // - // const modelParentIds = model.parents.map(parent => parent.id).sort(); - // const responseParentIds = doc._embedded._links.parents - // .map(parent => parent.href) - // .map(href => href.replace(parentHrefRegex, '$1')) - // .sort(); - // - // expect(modelParentIds).toEqual(responseParentIds); - // }); - - // TODO enable once validation is enabled in the serializer - // it('should throw an error when dealing with an invalid document', () => { - // const serializer = new DSpaceRESTv2Serializer(TestModel); - // const doc = testResponses[0]; - // - // expect(() => { - // serializer.deserialize(doc); - // }).toThrow(); - // }); - - it('should throw an error when dealing with a document describing an array', () => { - const serializer = new DSpaceRESTv2Serializer(TestModel); - expect(() => { - serializer.deserialize(testResponses); - }).toThrow(); - }); - - }); - - describe('deserializeArray', () => { - - // TODO: rewrite to incorporate normalisation. - // it('should turn a valid document describing a collection of objects in to an array of valid models', () => { - // const serializer = new DSpaceRESTv2Serializer(TestModel); - // const doc = { - // '_embedded': testResponses - // }; - // - // const models = serializer.deserializeArray(doc); - // - // expect(models[0].id).toBe(doc._embedded[0].id); - // expect(models[0].name).toBe(doc._embedded[0].name); - // expect(models[1].id).toBe(doc._embedded[1].id); - // expect(models[1].name).toBe(doc._embedded[1].name); - // }); - - // TODO: cant implement/test this yet - depends on how relationships - // will be handled in the rest api - // it('should retain relationship information', () => { - // const serializer = new DSpaceRESTv2Serializer(TestModel); - // const doc = { - // '_embedded': testResponses, - // }; - // - // const models = serializer.deserializeArray(doc); - // - // models.forEach((model, i) => { - // const modelParentIds = model.parents.map(parent => parent.id).sort(); - // const responseParentIds = doc._embedded[i]._links.parents - // .map(parent => parent.href) - // .map(href => href.replace(parentHrefRegex, '$1')) - // .sort(); - // - // expect(modelParentIds).toEqual(responseParentIds); - // }); - // }); - - // TODO enable once validation is enabled in the serializer - // it('should throw an error when dealing with an invalid document', () => { - // const serializer = new DSpaceRESTv2Serializer(TestModel); - // const doc = testResponses[0]; - // - // expect(() => { - // serializer.deserializeArray(doc); - // }).toThrow(); - // }); - - it('should throw an error when dealing with a document describing a single model', () => { - const serializer = new DSpaceRESTv2Serializer(TestModel); - const doc = { - _embedded: testResponses[0] - }; - - expect(() => { - serializer.deserializeArray(doc); - }).toThrow(); - }); - - }); - -}); diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts b/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts index dc60b500ff..6eb144580c 100644 --- a/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts +++ b/src/app/core/dspace-rest-v2/dspace-rest-v2.service.ts @@ -4,7 +4,6 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http' import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model'; -import { HttpObserve } from '@angular/common/http/src/client'; import { RestRequestMethod } from '../data/rest-request-method'; import { hasNoValue, isNotEmpty } from '../../shared/empty.util'; import { DSpaceObject } from '../shared/dspace-object.model'; @@ -14,7 +13,7 @@ export interface HttpOptions { body?: any; headers?: HttpHeaders; params?: HttpParams; - observe?: HttpObserve; + observe?: 'body' | 'events' | 'response'; reportProgress?: boolean; responseType?: 'arraybuffer' | 'blob' | 'json' | 'text'; withCredentials?: boolean; diff --git a/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts b/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts new file mode 100644 index 0000000000..b07a4f97d1 --- /dev/null +++ b/src/app/core/dspace-rest-v2/dspace.serializer.spec.ts @@ -0,0 +1,154 @@ +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; +import { HALLink } from '../shared/hal-link.model'; +import { HALResource } from '../shared/hal-resource.model'; +import { DSpaceSerializer } from './dspace.serializer'; + +class TestModel implements HALResource { + @autoserialize + id: string; + + @autoserialize + name: string; + + @deserialize + _links: { + self: HALLink; + parents: HALLink; + } +} + +const testModels = [ + { + id: 'd4466d54-d73b-4d8f-b73f-c702020baa14', + name: 'Model 1', + _links: { + self: { + href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60' + }, + parents: { + href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60/parents' + } + } + }, + { + id: '752a1250-949a-46ad-9bea-fbc45f0b656d', + name: 'Model 2', + _links: { + self: { + href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad' + }, + parents: { + href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad/parents' + } + } + } +]; + +const testResponses = [ + { + _links: { + self: { + href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60' + }, + parents: { + href: '/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60/parents' + } + }, + id: '9e32a2e2-6b91-4236-a361-995ccdc14c60', + type: 'testModels', + name: 'A Test Model' + }, + { + _links: { + self: { + href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad' + }, + parents: { + href: '/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad/parents' + } + }, + id: '598ce822-c357-46f3-ab70-63724d02d6ad', + type: 'testModels', + name: 'Another Test Model' + } +]; + +describe('DSpaceSerializer', () => { + + describe('serialize', () => { + + it('should turn a model in to a valid document', () => { + const serializer = new DSpaceSerializer(TestModel); + const doc = serializer.serialize(testModels[0]); + expect(doc.id).toBe(testModels[0].id); + expect(doc.name).toBe(testModels[0].name); + expect(doc._links).toBeUndefined(); + }); + + }); + + describe('serializeArray', () => { + + it('should turn an array of models in to a valid document', () => { + const serializer = new DSpaceSerializer(TestModel); + const doc = serializer.serializeArray(testModels); + + expect(doc[0].id).toBe(testModels[0].id); + expect(doc[0].name).toBe(testModels[0].name); + expect(doc[0]._links).toBeUndefined(); + expect(doc[1].id).toBe(testModels[1].id); + expect(doc[1].name).toBe(testModels[1].name); + expect(doc[1]._links).toBeUndefined(); + }); + + }); + + describe('deserialize', () => { + + it('should turn a valid document describing a single entity in to a valid model', () => { + const serializer = new DSpaceSerializer(TestModel); + const model = serializer.deserialize(testResponses[0]); + + expect(model.id).toBe(testResponses[0].id); + expect(model.name).toBe(testResponses[0].name); + }); + + it('should throw an error when dealing with a document describing an array', () => { + const serializer = new DSpaceSerializer(TestModel); + expect(() => { + serializer.deserialize(testResponses); + }).toThrow(); + }); + + }); + + describe('deserializeArray', () => { + + it('should throw an error when dealing with a document describing a single model', () => { + const serializer = new DSpaceSerializer(TestModel); + const doc = { + _embedded: testResponses[0] + }; + + expect(() => { + serializer.deserializeArray(doc); + }).toThrow(); + }); + + it('should turn an array of responses in to valid models', () => { + const serializer = new DSpaceSerializer(TestModel); + const output = serializer.deserializeArray(testResponses); + + expect(testResponses[0].id).toBe(output[0].id); + expect(testResponses[0].name).toBe(output[0].name); + expect(testResponses[0]._links.self.href).toBe(output[0]._links.self.href); + expect(testResponses[0]._links.parents.href).toBe(output[0]._links.parents.href); + expect(testResponses[1].id).toBe(output[1].id); + expect(testResponses[1].name).toBe(output[1].name); + expect(testResponses[1]._links.self.href).toBe(output[1]._links.self.href); + expect(testResponses[1]._links.parents.href).toBe(output[1]._links.parents.href); + }); + + }); + +}); diff --git a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts b/src/app/core/dspace-rest-v2/dspace.serializer.ts similarity index 53% rename from src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts rename to src/app/core/dspace-rest-v2/dspace.serializer.ts index 258edb116d..e16094a040 100644 --- a/src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts +++ b/src/app/core/dspace-rest-v2/dspace.serializer.ts @@ -1,19 +1,16 @@ -import { Serialize, Deserialize } from 'cerialize'; +import { Deserialize, Serialize } from 'cerialize'; import { Serializer } from '../serializer'; -import { DSpaceRESTV2Response } from './dspace-rest-v2-response.model'; -import { DSpaceRESTv2Validator } from './dspace-rest-v2.validator'; import { GenericConstructor } from '../shared/generic-constructor'; -import { hasNoValue, hasValue } from '../../shared/empty.util'; /** * This Serializer turns responses from v2 of DSpace's REST API * to models and vice versa */ -export class DSpaceRESTv2Serializer implements Serializer { +export class DSpaceSerializer implements Serializer { /** - * Create a new DSpaceRESTv2Serializer instance + * Create a new DSpaceSerializer instance * * @param modelType a class or interface to indicate * the kind of model this serializer should work with @@ -48,13 +45,10 @@ export class DSpaceRESTv2Serializer implements Serializer { * @returns a model of type T */ deserialize(response: any): T { - // TODO enable validation, once rest data stabilizes - // new DSpaceRESTv2Validator(response).validate(); if (Array.isArray(response)) { throw new Error('Expected a single model, use deserializeArray() instead'); } - const normalized = Object.assign({}, response, this.normalizeLinks(response._links)); - return Deserialize(normalized, this.modelType) as T; + return Deserialize(response, this.modelType) as T; } /** @@ -64,30 +58,9 @@ export class DSpaceRESTv2Serializer implements Serializer { * @returns an array of models of type T */ deserializeArray(response: any): T[] { - // TODO: enable validation, once rest data stabilizes - // new DSpaceRESTv2Validator(response).validate(); if (!Array.isArray(response)) { throw new Error('Expected an Array, use deserialize() instead'); } - const normalized = response.map((resource) => { - return Object.assign({}, resource, this.normalizeLinks(resource._links)); - }); - - return Deserialize(normalized, this.modelType) as T[]; + return Deserialize(response, this.modelType) as T[]; } - - private normalizeLinks(links: any): any { - const normalizedLinks = links; - for (const link in normalizedLinks) { - if (Array.isArray(normalizedLinks[link])) { - normalizedLinks[link] = normalizedLinks[link].map((linkedResource) => { - return linkedResource.href; - }); - } else { - normalizedLinks[link] = normalizedLinks[link].href; - } - } - return normalizedLinks; - } - } diff --git a/src/app/core/eperson/eperson-data.service.ts b/src/app/core/eperson/eperson-data.service.ts new file mode 100644 index 0000000000..ef2e76c7c6 --- /dev/null +++ b/src/app/core/eperson/eperson-data.service.ts @@ -0,0 +1,38 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; +import { DataService } from '../data/data.service'; +import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { RequestService } from '../data/request.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { EPerson } from './models/eperson.model'; +import { EPERSON } from './models/eperson.resource-type'; + +/** + * A service to retrieve {@link EPerson}s from the REST API + */ +@Injectable() +@dataService(EPERSON) +export class EPersonDataService extends DataService { + + protected linkPath: 'epersons'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DSOChangeAnalyzer + ) { + super(); + } + +} diff --git a/src/app/core/eperson/eperson.service.ts b/src/app/core/eperson/eperson.service.ts deleted file mode 100644 index 81ae532e3b..0000000000 --- a/src/app/core/eperson/eperson.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Observable } from 'rxjs'; -import { FindListOptions } from '../data/request.models'; -import { DataService } from '../data/data.service'; -import { CacheableObject } from '../cache/object-cache.reducer'; - -/** - * An abstract class that provides methods to make HTTP request to eperson endpoint. - */ -export abstract class EpersonService extends DataService { - - public getBrowseEndpoint(options: FindListOptions): Observable { - return this.halService.getEndpoint(this.linkPath); - } -} diff --git a/src/app/core/eperson/group-eperson.service.ts b/src/app/core/eperson/group-data.service.ts similarity index 88% rename from src/app/core/eperson/group-eperson.service.ts rename to src/app/core/eperson/group-data.service.ts index c8a2a78917..2beeb588a9 100644 --- a/src/app/core/eperson/group-eperson.service.ts +++ b/src/app/core/eperson/group-data.service.ts @@ -4,8 +4,8 @@ import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; +import { DataService } from '../data/data.service'; -import { EpersonService } from './eperson.service'; import { RequestService } from '../data/request.service'; import { FindListOptions } from '../data/request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; @@ -17,20 +17,20 @@ import { SearchParam } from '../cache/models/search-param.model'; import { RemoteData } from '../data/remote-data'; import { PaginatedList } from '../data/paginated-list'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; /** * Provides methods to retrieve eperson group resources. */ -@Injectable() -export class GroupEpersonService extends EpersonService { +@Injectable({ + providedIn: 'root' +}) +export class GroupDataService extends DataService { protected linkPath = 'groups'; protected browseEndpoint = ''; constructor( protected comparator: DSOChangeAnalyzer, - protected dataBuildService: NormalizedObjectBuildService, protected http: HttpClient, protected notificationsService: NotificationsService, protected requestService: RequestService, diff --git a/src/app/core/eperson/models/eperson.model.ts b/src/app/core/eperson/models/eperson.model.ts index d99a059e8b..bb99022112 100644 --- a/src/app/core/eperson/models/eperson.model.ts +++ b/src/app/core/eperson/models/eperson.model.ts @@ -1,52 +1,60 @@ +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../../cache/builders/build-decorators'; +import { PaginatedList } from '../../data/paginated-list'; +import { RemoteData } from '../../data/remote-data'; import { DSpaceObject } from '../../shared/dspace-object.model'; +import { HALLink } from '../../shared/hal-link.model'; +import { EPERSON } from './eperson.resource-type'; import { Group } from './group.model'; -import { RemoteData } from '../../data/remote-data'; -import { PaginatedList } from '../../data/paginated-list'; -import { ResourceType } from '../../shared/resource-type'; +import { GROUP } from './group.resource-type'; +@typedObject +@inheritSerialization(DSpaceObject) export class EPerson extends DSpaceObject { - static type = new ResourceType('eperson'); + static type = EPERSON; /** * A string representing the unique handle of this Collection */ + @autoserialize public handle: string; - /** - * List of Groups that this EPerson belong to - */ - public groups: Observable>>; - /** * A string representing the netid of this EPerson */ + @autoserialize public netid: string; /** * A string representing the last active date for this EPerson */ + @autoserialize public lastActive: string; /** * A boolean representing if this EPerson can log in */ + @autoserialize public canLogIn: boolean; /** * The EPerson email address */ + @autoserialize public email: string; /** * A boolean representing if this EPerson require certificate */ + @autoserialize public requireCertificate: boolean; /** * A boolean representing if this EPerson registered itself */ + @autoserialize public selfRegistered: boolean; /** @@ -55,4 +63,17 @@ export class EPerson extends DSpaceObject { get name(): string { return this.firstMetadataValue('eperson.firstname') + ' ' + this.firstMetadataValue('eperson.lastname'); } + + _links: { + self: HALLink; + groups: HALLink; + }; + + /** + * The list of Groups this EPerson is part of + * Will be undefined unless the groups {@link HALLink} has been resolved. + */ + @link(GROUP, true) + public groups?: Observable>>; + } diff --git a/src/app/core/eperson/models/eperson.resource-type.ts b/src/app/core/eperson/models/eperson.resource-type.ts new file mode 100644 index 0000000000..8c91b3bca6 --- /dev/null +++ b/src/app/core/eperson/models/eperson.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for EPerson + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const EPERSON = new ResourceType('eperson'); diff --git a/src/app/core/eperson/models/group.model.ts b/src/app/core/eperson/models/group.model.ts index 9c14c20de7..5d531800b8 100644 --- a/src/app/core/eperson/models/group.model.ts +++ b/src/app/core/eperson/models/group.model.ts @@ -1,30 +1,44 @@ +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; - -import { DSpaceObject } from '../../shared/dspace-object.model'; +import { link, typedObject } from '../../cache/builders/build-decorators'; import { PaginatedList } from '../../data/paginated-list'; import { RemoteData } from '../../data/remote-data'; -import { ResourceType } from '../../shared/resource-type'; +import { DSpaceObject } from '../../shared/dspace-object.model'; +import { HALLink } from '../../shared/hal-link.model'; +import { GROUP } from './group.resource-type'; + +@typedObject +@inheritSerialization(DSpaceObject) export class Group extends DSpaceObject { - static type = new ResourceType('group'); - - /** - * List of Groups that this Group belong to - */ - public groups: Observable>>; + static type = GROUP; /** * A string representing the unique handle of this Group */ + @autoserialize public handle: string; /** - * A string representing the name of this Group + * A boolean denoting whether this Group is permanent */ - public name: string; + @autoserialize + public permanent: boolean; /** - * A string representing the name of this Group is permanent + * The {@link HALLink}s for this Group */ - public permanent: boolean; + @deserialize + _links: { + self: HALLink; + groups: HALLink; + }; + + /** + * The list of Groups this Group is part of + * Will be undefined unless the groups {@link HALLink} has been resolved. + */ + @link(GROUP, true) + public groups?: Observable>>; + } diff --git a/src/app/core/eperson/models/group.resource-type.ts b/src/app/core/eperson/models/group.resource-type.ts new file mode 100644 index 0000000000..ad4a8bbccb --- /dev/null +++ b/src/app/core/eperson/models/group.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for Group + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const GROUP = new ResourceType('group'); diff --git a/src/app/core/eperson/models/normalized-eperson.model.ts b/src/app/core/eperson/models/normalized-eperson.model.ts deleted file mode 100644 index 489bf259c6..0000000000 --- a/src/app/core/eperson/models/normalized-eperson.model.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; - -import { CacheableObject } from '../../cache/object-cache.reducer'; -import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; -import { EPerson } from './eperson.model'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { Group } from './group.model'; - -@mapsTo(EPerson) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedEPerson extends NormalizedDSpaceObject implements CacheableObject { - - /** - * A string representing the unique handle of this EPerson - */ - @autoserialize - public handle: string; - - /** - * List of Groups that this EPerson belong to - */ - @deserialize - @relationship(Group, true) - groups: string[]; - - /** - * A string representing the netid of this EPerson - */ - @autoserialize - public netid: string; - - /** - * A string representing the last active date for this EPerson - */ - @autoserialize - public lastActive: string; - - /** - * A boolean representing if this EPerson can log in - */ - @autoserialize - public canLogIn: boolean; - - /** - * The EPerson email address - */ - @autoserialize - public email: string; - - /** - * A boolean representing if this EPerson require certificate - */ - @autoserialize - public requireCertificate: boolean; - - /** - * A boolean representing if this EPerson registered itself - */ - @autoserialize - public selfRegistered: boolean; -} diff --git a/src/app/core/eperson/models/normalized-group.model.ts b/src/app/core/eperson/models/normalized-group.model.ts deleted file mode 100644 index 72b4e7b1a4..0000000000 --- a/src/app/core/eperson/models/normalized-group.model.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; - -import { CacheableObject } from '../../cache/object-cache.reducer'; -import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { Group } from './group.model'; - -@mapsTo(Group) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedGroup extends NormalizedDSpaceObject implements CacheableObject { - - /** - * List of Groups that this Group belong to - */ - @deserialize - @relationship(Group, true) - groups: string[]; - - /** - * A string representing the unique handle of this Group - */ - @autoserialize - public handle: string; - - /** - * A string representing the name of this Group - */ - @autoserialize - public name: string; - - /** - * A string representing the name of this Group is permanent - */ - @autoserialize - public permanent: boolean; -} diff --git a/src/app/core/eperson/models/workflowitem.resource-type.ts b/src/app/core/eperson/models/workflowitem.resource-type.ts new file mode 100644 index 0000000000..001b6b3f33 --- /dev/null +++ b/src/app/core/eperson/models/workflowitem.resource-type.ts @@ -0,0 +1,3 @@ +import { ResourceType } from '../../shared/resource-type'; + +export const WORKFLOWITEM = new ResourceType('workflowitem'); diff --git a/src/app/core/index/index.actions.ts b/src/app/core/index/index.actions.ts index 42804dbe26..d31f6ee2bd 100644 --- a/src/app/core/index/index.actions.ts +++ b/src/app/core/index/index.actions.ts @@ -91,4 +91,4 @@ export class RemoveFromIndexBySubstringAction implements Action { /** * A type to encompass all HrefIndexActions */ -export type IndexAction = AddToIndexAction | RemoveFromIndexByValueAction; +export type IndexAction = AddToIndexAction | RemoveFromIndexByValueAction | RemoveFromIndexBySubstringAction; diff --git a/src/app/core/index/index.effects.ts b/src/app/core/index/index.effects.ts index 61cf313ab1..c9f6eace8f 100644 --- a/src/app/core/index/index.effects.ts +++ b/src/app/core/index/index.effects.ts @@ -24,7 +24,7 @@ export class UUIDIndexEffects { return new AddToIndexAction( IndexName.OBJECT, action.payload.objectToCache.uuid, - action.payload.objectToCache.self + action.payload.objectToCache._links.self.href ); }) ); diff --git a/src/app/core/index/index.reducer.ts b/src/app/core/index/index.reducer.ts index b4cd8aa84b..616363ff7a 100644 --- a/src/app/core/index/index.reducer.ts +++ b/src/app/core/index/index.reducer.ts @@ -126,7 +126,7 @@ function removeFromIndexByValue(state: MetaIndexState, action: RemoveFromIndexBy * @return MetaIndexState * the new state */ -function removeFromIndexBySubstring(state: MetaIndexState, action: RemoveFromIndexByValueAction): MetaIndexState { +function removeFromIndexBySubstring(state: MetaIndexState, action: RemoveFromIndexByValueAction | RemoveFromIndexBySubstringAction): MetaIndexState { const subState = state[action.payload.name]; const newSubState = Object.create(null); for (const value in subState) { diff --git a/src/app/core/integration/integration-response-parsing.service.spec.ts b/src/app/core/integration/integration-response-parsing.service.spec.ts index 4187606265..8cc139744c 100644 --- a/src/app/core/integration/integration-response-parsing.service.spec.ts +++ b/src/app/core/integration/integration-response-parsing.service.spec.ts @@ -1,22 +1,21 @@ -import { ErrorResponse, IntegrationSuccessResponse } from '../cache/response.models'; - -import { ObjectCacheService } from '../cache/object-cache.service'; +import { Store } from '@ngrx/store'; import { GlobalConfig } from '../../../config/global-config.interface'; -import { Store } from '@ngrx/store'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { ErrorResponse, IntegrationSuccessResponse } from '../cache/response.models'; import { CoreState } from '../core.reducers'; -import { IntegrationResponseParsingService } from './integration-response-parsing.service'; -import { IntegrationRequest } from '../data/request.models'; -import { AuthorityValue } from './models/authority.value'; -import { PageInfo } from '../shared/page-info.model'; import { PaginatedList } from '../data/paginated-list'; +import { IntegrationRequest } from '../data/request.models'; +import { PageInfo } from '../shared/page-info.model'; +import { IntegrationResponseParsingService } from './integration-response-parsing.service'; +import { AuthorityValue } from './models/authority.value'; describe('IntegrationResponseParsingService', () => { let service: IntegrationResponseParsingService; const EnvConfig = {} as GlobalConfig; const store = {} as Store; - const objectCacheService = new ObjectCacheService(store); + const objectCacheService = new ObjectCacheService(store, undefined); const name = 'type'; const metadata = 'dc.type'; const query = ''; @@ -33,8 +32,16 @@ describe('IntegrationResponseParsingService', () => { let definitions; function initVars() { - pageInfo = Object.assign(new PageInfo(), { elementsPerPage: 5, totalElements: 5, totalPages: 1, currentPage: 1, self: 'https://rest.api/integration/authorities/type/entries'}); - definitions = new PaginatedList(pageInfo,[ + pageInfo = Object.assign(new PageInfo(), { + elementsPerPage: 5, + totalElements: 5, + totalPages: 1, + currentPage: 1, + _links: { + self: { href: 'https://rest.api/integration/authorities/type/entries' } + } + }); + definitions = new PaginatedList(pageInfo, [ Object.assign(new AuthorityValue(), { type: 'authority', display: 'One', diff --git a/src/app/core/integration/models/authority.resource-type.ts b/src/app/core/integration/models/authority.resource-type.ts new file mode 100644 index 0000000000..ec87ddc85f --- /dev/null +++ b/src/app/core/integration/models/authority.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for AuthorityValue + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const AUTHORITY_VALUE = new ResourceType('authority'); diff --git a/src/app/core/integration/models/authority.value.ts b/src/app/core/integration/models/authority.value.ts index 4c6a7c01cb..4e0183603b 100644 --- a/src/app/core/integration/models/authority.value.ts +++ b/src/app/core/integration/models/authority.value.ts @@ -1,41 +1,59 @@ -import { IntegrationModel } from './integration.model'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { isNotEmpty } from '../../../shared/empty.util'; import { PLACEHOLDER_PARENT_METADATA } from '../../../shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { OtherInformation } from '../../../shared/form/builder/models/form-field-metadata-value.model'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { HALLink } from '../../shared/hal-link.model'; import { MetadataValueInterface } from '../../shared/metadata.models'; -import { ResourceType } from '../../shared/resource-type'; +import { AUTHORITY_VALUE } from './authority.resource-type'; +import { IntegrationModel } from './integration.model'; /** * Class representing an authority object */ +@typedObject +@inheritSerialization(IntegrationModel) export class AuthorityValue extends IntegrationModel implements MetadataValueInterface { - static type = new ResourceType('authority'); + static type = AUTHORITY_VALUE; /** * The identifier of this authority */ + @autoserialize id: string; /** * The display value of this authority */ + @autoserialize display: string; /** * The value of this authority */ + @autoserialize value: string; /** * An object containing additional information related to this authority */ + @autoserialize otherInformation: OtherInformation; /** * The language code of this authority value */ + @autoserialize language: string; + /** + * The {@link HALLink}s for this AuthorityValue + */ + @deserialize + _links: { + self: HALLink, + }; + /** * This method checks if authority has an identifier value * diff --git a/src/app/core/integration/models/integration.model.ts b/src/app/core/integration/models/integration.model.ts index 3158abc7eb..d2f21a70c0 100644 --- a/src/app/core/integration/models/integration.model.ts +++ b/src/app/core/integration/models/integration.model.ts @@ -1,5 +1,6 @@ -import { autoserialize } from 'cerialize'; +import { autoserialize, deserialize } from 'cerialize'; import { CacheableObject } from '../../cache/object-cache.reducer'; +import { HALLink } from '../../shared/hal-link.model'; export abstract class IntegrationModel implements CacheableObject { @@ -12,9 +13,10 @@ export abstract class IntegrationModel implements CacheableObject { @autoserialize public type: any; - @autoserialize + @deserialize public _links: { - [name: string]: string + self: HALLink, + [name: string]: HALLink } } diff --git a/src/app/core/integration/models/normalized-authority-value.model.ts b/src/app/core/integration/models/normalized-authority-value.model.ts deleted file mode 100644 index 5ebb61281d..0000000000 --- a/src/app/core/integration/models/normalized-authority-value.model.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { IntegrationModel } from './integration.model'; -import { mapsTo } from '../../cache/builders/build-decorators'; -import { AuthorityValue } from './authority.value'; - -/** - * Normalized model class for an Authority Value - */ -@mapsTo(AuthorityValue) -@inheritSerialization(IntegrationModel) -export class NormalizedAuthorityValue extends IntegrationModel { - - @autoserialize - id: string; - - @autoserialize - display: string; - - @autoserialize - value: string; - - @autoserialize - otherInformation: any; - - @autoserialize - language: string; - -} diff --git a/src/app/core/metadata/metadata-field.model.ts b/src/app/core/metadata/metadata-field.model.ts index 45ac4b2051..ad7ec59b25 100644 --- a/src/app/core/metadata/metadata-field.model.ts +++ b/src/app/core/metadata/metadata-field.model.ts @@ -1,44 +1,69 @@ -import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { autoserialize, deserialize } from 'cerialize'; import { isNotEmpty } from '../../shared/empty.util'; -import { MetadataSchema } from './metadata-schema.model'; -import { ResourceType } from '../shared/resource-type'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { link, typedObject } from '../cache/builders/build-decorators'; import { GenericConstructor } from '../shared/generic-constructor'; +import { HALLink } from '../shared/hal-link.model'; +import { HALResource } from '../shared/hal-resource.model'; +import { ResourceType } from '../shared/resource-type'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { METADATA_FIELD } from './metadata-field.resource-type'; +import { MetadataSchema } from './metadata-schema.model'; /** * Class the represents a metadata field */ -export class MetadataField extends ListableObject { - static type = new ResourceType('metadatafield'); +@typedObject +export class MetadataField extends ListableObject implements HALResource { + static type = METADATA_FIELD; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The identifier of this metadata field */ + @autoserialize id: number; - /** - * The self link of this metadata field - */ - self: string; - /** * The element of this metadata field */ + @autoserialize element: string; /** * The qualifier of this metadata field */ + @autoserialize qualifier: string; /** * The scope note of this metadata field */ + @autoserialize scopeNote: string; /** - * The metadata schema object of this metadata field + * The {@link HALLink}s for this MetadataField */ - schema: MetadataSchema; + @deserialize + _links: { + self: HALLink, + schema: HALLink + }; + + /** + * The MetadataSchema for this MetadataField + * Will be undefined unless the schema {@link HALLink} has been resolved. + */ + // TODO the responseparsingservice assumes schemas are always embedded. This should use remotedata, and be a link instead. + // @link(METADATA_SCHEMA) + schema?: MetadataSchema; /** * Method to print this metadata field as a string diff --git a/src/app/core/metadata/metadata-field.resource-type.ts b/src/app/core/metadata/metadata-field.resource-type.ts new file mode 100644 index 0000000000..53cbedb1eb --- /dev/null +++ b/src/app/core/metadata/metadata-field.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../shared/resource-type'; + +/** + * The resource type for MetadataField + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const METADATA_FIELD = new ResourceType('metadatafield'); diff --git a/src/app/core/metadata/metadata-schema.model.ts b/src/app/core/metadata/metadata-schema.model.ts index 2059b21094..d4d94b8780 100644 --- a/src/app/core/metadata/metadata-schema.model.ts +++ b/src/app/core/metadata/metadata-schema.model.ts @@ -1,33 +1,50 @@ +import { autoserialize, deserialize } from 'cerialize'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; -import { ResourceType } from '../shared/resource-type'; +import { typedObject } from '../cache/builders/build-decorators'; import { GenericConstructor } from '../shared/generic-constructor'; +import { HALLink } from '../shared/hal-link.model'; +import { HALResource } from '../shared/hal-resource.model'; +import { ResourceType } from '../shared/resource-type'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { METADATA_SCHEMA } from './metadata-schema.resource-type'; /** * Class that represents a metadata schema */ -export class MetadataSchema extends ListableObject { - static type = new ResourceType('metadataschema'); +@typedObject +export class MetadataSchema extends ListableObject implements HALResource { + static type = METADATA_SCHEMA; /** * The unique identifier for this metadata schema */ + @autoserialize id: number; /** - * The REST link to itself + * The object type */ - self: string; + @excludeFromEquals + @autoserialize + type: ResourceType; /** * A unique prefix that defines this schema */ + @autoserialize prefix: string; /** * The namespace of this metadata schema */ + @autoserialize namespace: string; + @deserialize + _links: { + self: HALLink, + }; + /** * Method that returns as which type of object this object should be rendered */ diff --git a/src/app/core/metadata/metadata-schema.resource-type.ts b/src/app/core/metadata/metadata-schema.resource-type.ts new file mode 100644 index 0000000000..462c9957c7 --- /dev/null +++ b/src/app/core/metadata/metadata-schema.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../shared/resource-type'; + +/** + * The resource type for MetadataSchema + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const METADATA_SCHEMA = new ResourceType('metadataschema'); diff --git a/src/app/core/metadata/metadata.service.spec.ts b/src/app/core/metadata/metadata.service.spec.ts index 80ce33b370..e3f6c3401c 100644 --- a/src/app/core/metadata/metadata.service.spec.ts +++ b/src/app/core/metadata/metadata.service.spec.ts @@ -1,44 +1,58 @@ -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; - import { CommonModule, Location } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { Meta, MetaDefinition, Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; - -import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { RouterTestingModule } from '@angular/router/testing'; import { Store, StoreModule } from '@ngrx/store'; -import { Observable, of as observableOf } from 'rxjs'; -import { UUIDService } from '../shared/uuid.service'; -import { MetadataService } from './metadata.service'; - -import { CoreState } from '../core.reducers'; - -import { GlobalConfig } from '../../../config/global-config.interface'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { EmptyError } from 'rxjs/internal-compatibility'; import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config'; -import { ItemDataService } from '../data/item-data.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { RequestService } from '../data/request.service'; +import { GlobalConfig } from '../../../config/global-config.interface'; import { RemoteData } from '../../core/data/remote-data'; import { Item } from '../../core/shared/item.model'; -import { MockItem } from '../../shared/mocks/mock-item'; +import { + MockBitstream1, + MockBitstream2, + MockBitstreamFormat1, + MockBitstreamFormat2, + MockItem +} from '../../shared/mocks/mock-item'; import { MockTranslateLoader } from '../../shared/mocks/mock-translate-loader'; -import { BrowseService } from '../browse/browse.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { AuthService } from '../auth/auth.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { HttpClient } from '@angular/common/http'; -import { EmptyError } from 'rxjs/internal-compatibility'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; -import { MetadataValue } from '../shared/metadata.models'; import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; +import { AuthService } from '../auth/auth.service'; +import { BrowseService } from '../browse/browse.service'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; + +import { CoreState } from '../core.reducers'; +import { BitstreamDataService } from '../data/bitstream-data.service'; +import { BitstreamFormatDataService } from '../data/bitstream-format-data.service'; +import { CommunityDataService } from '../data/community-data.service'; +import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; + +import { ItemDataService } from '../data/item-data.service'; +import { PaginatedList } from '../data/paginated-list'; +import { FindListOptions } from '../data/request.models'; +import { RequestService } from '../data/request.service'; +import { BitstreamFormat } from '../shared/bitstream-format.model'; +import { Bitstream } from '../shared/bitstream.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { MetadataValue } from '../shared/metadata.models'; +import { PageInfo } from '../shared/page-info.model'; +import { UUIDService } from '../shared/uuid.service'; + +import { MetadataService } from './metadata.service'; /* tslint:disable:max-classes-per-file */ @Component({ @@ -50,13 +64,15 @@ class TestComponent { } } -@Component({ template: '' }) class DummyItemComponent { +@Component({ template: '' }) +class DummyItemComponent { constructor(private route: ActivatedRoute, private items: ItemDataService, private metadata: MetadataService) { this.route.params.subscribe((params) => { this.metadata.processRemoteData(this.items.findById(params.id)); }); } } + /* tslint:enable:max-classes-per-file */ describe('MetadataService', () => { @@ -88,10 +104,33 @@ describe('MetadataService', () => { store = new Store(undefined, undefined, undefined); spyOn(store, 'dispatch'); - objectCacheService = new ObjectCacheService(store); + objectCacheService = new ObjectCacheService(store, undefined); uuidService = new UUIDService(); requestService = new RequestService(objectCacheService, uuidService, store, undefined); - remoteDataBuildService = new RemoteDataBuildService(objectCacheService, requestService); + remoteDataBuildService = new RemoteDataBuildService(objectCacheService, undefined, requestService); + const mockBitstreamDataService = { + findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { + if (item.equals(MockItem)) { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [MockBitstream1, MockBitstream2])); + } else { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])); + } + }, + }; + const mockBitstreamFormatDataService = { + findByBitstream(bitstream: Bitstream): Observable> { + switch (bitstream) { + case MockBitstream1: + return createSuccessfulRemoteDataObject$(MockBitstreamFormat1); + break; + case MockBitstream2: + return createSuccessfulRemoteDataObject$(MockBitstreamFormat2); + break; + default: + return createSuccessfulRemoteDataObject$(new BitstreamFormat()); + } + } + }; TestBed.configureTestingModule({ imports: [ @@ -105,7 +144,12 @@ describe('MetadataService', () => { }), RouterTestingModule.withRoutes([ { path: 'items/:id', component: DummyItemComponent, pathMatch: 'full' }, - { path: 'other', component: DummyItemComponent, pathMatch: 'full', data: { title: 'Dummy Title', description: 'This is a dummy item component for testing!' } } + { + path: 'other', + component: DummyItemComponent, + pathMatch: 'full', + data: { title: 'Dummy Title', description: 'This is a dummy item component for testing!' } + } ]) ], declarations: [ @@ -121,8 +165,11 @@ describe('MetadataService', () => { { provide: AuthService, useValue: {} }, { provide: NotificationsService, useValue: {} }, { provide: HttpClient, useValue: {} }, - { provide: NormalizedObjectBuildService, useValue: {} }, { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamFormatDataService, useValue: mockBitstreamFormatDataService }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, Meta, Title, ItemDataService, @@ -193,7 +240,8 @@ describe('MetadataService', () => { describe('when the item has no bitstreams', () => { beforeEach(() => { - spyOn(MockItem, 'getFiles').and.returnValue(observableOf([])); + // this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL') + // spyOn(MockItem, 'getFiles').and.returnValue(observableOf([])); }); it('processRemoteData should not produce an EmptyError', fakeAsync(() => { @@ -212,7 +260,7 @@ describe('MetadataService', () => { const mockType = (mockItem: Item, type: string): Item => { const typedMockItem = Object.assign(new Item(), mockItem) as Item; - typedMockItem.metadata['dc.type'] = [ { value: type } ] as MetadataValue[]; + typedMockItem.metadata['dc.type'] = [{ value: type }] as MetadataValue[]; return typedMockItem; }; diff --git a/src/app/core/metadata/metadata.service.ts b/src/app/core/metadata/metadata.service.ts index 2b1cf4ffc1..1417005b9d 100644 --- a/src/app/core/metadata/metadata.service.ts +++ b/src/app/core/metadata/metadata.service.ts @@ -1,29 +1,25 @@ -import { - catchError, - distinctUntilKeyChanged, - filter, - first, - map, - take -} from 'rxjs/operators'; import { Inject, Injectable } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { Meta, MetaDefinition, Title } from '@angular/platform-browser'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable } from 'rxjs'; - -import { RemoteData } from '../data/remote-data'; -import { Bitstream } from '../shared/bitstream.model'; -import { CacheableObject } from '../cache/object-cache.reducer'; -import { DSpaceObject } from '../shared/dspace-object.model'; -import { Item } from '../shared/item.model'; +import { catchError, distinctUntilKeyChanged, filter, first, map, take } from 'rxjs/operators'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; -import { BitstreamFormat } from '../shared/bitstream-format.model'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { BitstreamDataService } from '../data/bitstream-data.service'; +import { BitstreamFormatDataService } from '../data/bitstream-format-data.service'; + +import { RemoteData } from '../data/remote-data'; +import { BitstreamFormat } from '../shared/bitstream-format.model'; +import { Bitstream } from '../shared/bitstream.model'; +import { DSpaceObject } from '../shared/dspace-object.model'; +import { Item } from '../shared/item.model'; +import { getFirstSucceededRemoteDataPayload, getFirstSucceededRemoteListPayload } from '../shared/operators'; @Injectable() export class MetadataService { @@ -39,6 +35,8 @@ export class MetadataService { private translate: TranslateService, private meta: Meta, private title: Title, + private bitstreamDataService: BitstreamDataService, + private bitstreamFormatDataService: BitstreamFormatDataService, @Inject(GLOBAL_CONFIG) private envConfig: GlobalConfig ) { // TODO: determine what open graph meta tags are needed and whether @@ -266,8 +264,9 @@ export class MetadataService { private setCitationPdfUrlTag(): void { if (this.currentObject.value instanceof Item) { const item = this.currentObject.value as Item; - item.getFiles() + this.bitstreamDataService.findAllByItemAndBundleName(item, 'ORIGINAL') .pipe( + getFirstSucceededRemoteListPayload(), first((files) => isNotEmpty(files)), catchError((error) => { console.debug(error.message); @@ -275,19 +274,13 @@ export class MetadataService { })) .subscribe((bitstreams: Bitstream[]) => { for (const bitstream of bitstreams) { - bitstream.format.pipe( - first(), - catchError((error: Error) => { - console.debug(error.message); - return [] - }), - map((rd: RemoteData) => rd.payload), - filter((format: BitstreamFormat) => hasValue(format))) - .subscribe((format: BitstreamFormat) => { - if (format.mimetype === 'application/pdf') { - this.addMetaTag('citation_pdf_url', bitstream.content); - } - }); + this.bitstreamFormatDataService.findByBitstream(bitstream).pipe( + getFirstSucceededRemoteDataPayload() + ).subscribe((format: BitstreamFormat) => { + if (format.mimetype === 'application/pdf') { + this.addMetaTag('citation_pdf_url', bitstream._links.content.href); + } + }); } }); } @@ -367,7 +360,7 @@ export class MetadataService { public clearMetaTags() { this.tagStore.forEach((tags: MetaDefinition[], property: string) => { - this.meta.removeTag("property='" + property + "'"); + this.meta.removeTag('property=\'' + property + '\''); }); this.tagStore.clear(); } diff --git a/src/app/core/metadata/normalized-metadata-field.model.ts b/src/app/core/metadata/normalized-metadata-field.model.ts deleted file mode 100644 index 3d8750778d..0000000000 --- a/src/app/core/metadata/normalized-metadata-field.model.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; -import { mapsTo, relationship } from '../cache/builders/build-decorators'; -import { MetadataField } from './metadata-field.model'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { MetadataSchema } from './metadata-schema.model'; - -/** - * Class the represents a normalized metadata field - */ -@mapsTo(MetadataField) -@inheritSerialization(NormalizedObject) -export class NormalizedMetadataField extends NormalizedObject { - - /** - * The identifier of this normalized metadata field - */ - @autoserialize - id: number; - - /** - * The self link of this normalized metadata field - */ - @autoserialize - self: string; - - /** - * The element of this normalized metadata field - */ - @autoserialize - element: string; - - /** - * The qualifier of this normalized metadata field - */ - @autoserialize - qualifier: string; - - /** - * The scope note of this normalized metadata field - */ - @autoserialize - scopeNote: string; - - /** - * The link to the metadata schema of this normalized metadata field - */ - @deserialize - @relationship(MetadataSchema) - schema: string; -} diff --git a/src/app/core/metadata/normalized-metadata-schema.model.ts b/src/app/core/metadata/normalized-metadata-schema.model.ts deleted file mode 100644 index 4b534725f4..0000000000 --- a/src/app/core/metadata/normalized-metadata-schema.model.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { mapsTo } from '../cache/builders/build-decorators'; -import { MetadataSchema } from './metadata-schema.model'; - -/** - * Normalized class for a DSpace MetadataSchema - */ -@mapsTo(MetadataSchema) -@inheritSerialization(NormalizedObject) -export class NormalizedMetadataSchema extends NormalizedObject { - /** - * The unique identifier for this schema - */ - @autoserialize - id: number; - - /** - * The REST link to itself - */ - @autoserialize - self: string; - - /** - * A unique prefix that defines this schema - */ - @autoserialize - prefix: string; - - /** - * The namespace for this schema - */ - @autoserialize - namespace: string; - -} diff --git a/src/app/core/registry/registry-bitstreamformats-response.model.ts b/src/app/core/registry/registry-bitstreamformats-response.model.ts index ddf926f3be..4da30b4ffc 100644 --- a/src/app/core/registry/registry-bitstreamformats-response.model.ts +++ b/src/app/core/registry/registry-bitstreamformats-response.model.ts @@ -1,16 +1,24 @@ import { autoserialize, deserialize } from 'cerialize'; +import { BITSTREAM_FORMAT } from '../shared/bitstream-format.resource-type'; +import { HALLink } from '../shared/hal-link.model'; import { PageInfo } from '../shared/page-info.model'; import { BitstreamFormat } from '../shared/bitstream-format.model'; -import { relationship } from '../cache/builders/build-decorators'; +import { link } from '../cache/builders/build-decorators'; export class RegistryBitstreamformatsResponse { - @deserialize - @relationship(BitstreamFormat, true) - bitstreamformats: BitstreamFormat[]; - @autoserialize page: PageInfo; - @autoserialize - self: string; + /** + * The {@link HALLink}s for this RegistryBitstreamformatsResponse + */ + @deserialize + _links: { + self: HALLink; + bitstreamformats: HALLink; + }; + + @link(BITSTREAM_FORMAT) + bitstreamformats?: BitstreamFormat[]; + } diff --git a/src/app/core/registry/registry-metadatafields-response.model.ts b/src/app/core/registry/registry-metadatafields-response.model.ts index 984603e42e..5dc492ab0f 100644 --- a/src/app/core/registry/registry-metadatafields-response.model.ts +++ b/src/app/core/registry/registry-metadatafields-response.model.ts @@ -1,20 +1,30 @@ -import { PageInfo } from '../shared/page-info.model'; import { autoserialize, deserialize } from 'cerialize'; -import { ResourceType } from '../shared/resource-type'; -import { relationship } from '../cache/builders/build-decorators'; -import { NormalizedMetadataField } from '../metadata/normalized-metadata-field.model'; +import { typedObject } from '../cache/builders/build-decorators'; import { MetadataField } from '../metadata/metadata-field.model'; +import { METADATA_FIELD } from '../metadata/metadata-field.resource-type'; +import { HALLink } from '../shared/hal-link.model'; +import { PageInfo } from '../shared/page-info.model'; +import { ResourceType } from '../shared/resource-type'; +import { excludeFromEquals } from '../utilities/equals.decorators'; /** * Class that represents a response with a registry's metadata fields */ +@typedObject export class RegistryMetadatafieldsResponse { - static type = new ResourceType('metadatafield'); + static type = METADATA_FIELD; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + /** * List of metadata fields in the response */ @deserialize - @relationship(MetadataField, true) metadatafields: MetadataField[]; /** @@ -28,4 +38,9 @@ export class RegistryMetadatafieldsResponse { */ @autoserialize self: string; + + @deserialize + _links: { + self: HALLink, + } } diff --git a/src/app/core/registry/registry-metadataschemas-response.model.ts b/src/app/core/registry/registry-metadataschemas-response.model.ts index fc53b354a5..7a485d8849 100644 --- a/src/app/core/registry/registry-metadataschemas-response.model.ts +++ b/src/app/core/registry/registry-metadataschemas-response.model.ts @@ -1,11 +1,9 @@ import { PageInfo } from '../shared/page-info.model'; import { autoserialize, deserialize } from 'cerialize'; import { MetadataSchema } from '../metadata/metadata-schema.model'; -import { relationship } from '../cache/builders/build-decorators'; export class RegistryMetadataschemasResponse { @deserialize - @relationship(MetadataSchema, true) metadataschemas: MetadataSchema[]; @autoserialize diff --git a/src/app/core/registry/registry.service.spec.ts b/src/app/core/registry/registry.service.spec.ts index 03a7c132de..b466693649 100644 --- a/src/app/core/registry/registry.service.spec.ts +++ b/src/app/core/registry/registry.service.spec.ts @@ -1,30 +1,10 @@ -import { TestBed } from '@angular/core/testing'; -import { RegistryService } from './registry.service'; import { CommonModule } from '@angular/common'; -import { RequestService } from '../data/request.service'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; -import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; -import { RequestEntry } from '../data/request.reducer'; -import { RemoteData } from '../data/remote-data'; -import { PageInfo } from '../shared/page-info.model'; -import { getMockRequestService } from '../../shared/mocks/mock-request.service'; - -import { - RegistryMetadatafieldsSuccessResponse, - RegistryMetadataschemasSuccessResponse, - RestResponse -} from '../cache/response.models'; import { Component } from '@angular/core'; -import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model'; -import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model'; -import { map } from 'rxjs/operators'; +import { TestBed } from '@angular/core/testing'; import { Store, StoreModule } from '@ngrx/store'; -import { MockStore } from '../../shared/testing/mock-store'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; import { TranslateModule } from '@ngx-translate/core'; +import { combineLatest as observableCombineLatest, Observable, of as observableOf } from 'rxjs'; +import { map } from 'rxjs/operators'; import { MetadataRegistryCancelFieldAction, MetadataRegistryCancelSchemaAction, @@ -37,12 +17,31 @@ import { MetadataRegistrySelectFieldAction, MetadataRegistrySelectSchemaAction } from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions'; -import { ResourceType } from '../shared/resource-type'; -import { MetadataSchema } from '../metadata/metadata-schema.model'; -import { MetadataField } from '../metadata/metadata-field.model'; +import { getMockRequestService } from '../../shared/mocks/mock-request.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; +import { MockStore } from '../../shared/testing/mock-store'; +import { NotificationsServiceStub } from '../../shared/testing/notifications-service-stub'; import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -@Component({template: ''}) +import { + RegistryMetadatafieldsSuccessResponse, + RegistryMetadataschemasSuccessResponse, + RestResponse +} from '../cache/response.models'; +import { RemoteData } from '../data/remote-data'; +import { RequestEntry } from '../data/request.reducer'; +import { RequestService } from '../data/request.service'; +import { MetadataField } from '../metadata/metadata-field.model'; +import { MetadataSchema } from '../metadata/metadata-schema.model'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { PageInfo } from '../shared/page-info.model'; +import { RegistryMetadatafieldsResponse } from './registry-metadatafields-response.model'; +import { RegistryMetadataschemasResponse } from './registry-metadataschemas-response.model'; +import { RegistryService } from './registry.service'; + +@Component({ template: '' }) class DummyComponent { } @@ -57,15 +56,18 @@ describe('RegistryService', () => { const mockSchemasList = [ Object.assign(new MetadataSchema(), { id: 1, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1', + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1' } + }, prefix: 'dc', namespace: 'http://dublincore.org/documents/dcmi-terms/', type: MetadataSchema.type -}), + }), Object.assign(new MetadataSchema(), { - id: 2, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2', + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2' } + }, prefix: 'mock', namespace: 'http://dspace.org/mockschema', type: MetadataSchema.type @@ -73,45 +75,53 @@ describe('RegistryService', () => { ]; const mockFieldsList = [ Object.assign(new MetadataField(), - { - id: 1, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8', - element: 'contributor', - qualifier: 'advisor', - scopeNote: null, - schema: mockSchemasList[0], - type: MetadataField.type - }), + { + id: 1, + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8' } + }, + element: 'contributor', + qualifier: 'advisor', + scopeNote: null, + schema: mockSchemasList[0], + type: MetadataField.type + }), Object.assign(new MetadataField(), { - id: 2, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9', - element: 'contributor', - qualifier: 'author', - scopeNote: null, - schema: mockSchemasList[0], - type: MetadataField.type - }), + id: 2, + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9' } + }, + element: 'contributor', + qualifier: 'author', + scopeNote: null, + schema: mockSchemasList[0], + type: MetadataField.type + }), Object.assign(new MetadataField(), { - id: 3, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10', - element: 'contributor', - qualifier: 'editor', - scopeNote: 'test scope note', - schema: mockSchemasList[1], - type: MetadataField.type - }), + id: 3, + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10' } + }, + element: 'contributor', + qualifier: 'editor', + scopeNote: 'test scope note', + schema: mockSchemasList[1], + type: MetadataField.type + }), Object.assign(new MetadataField(), { - id: 4, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11', - element: 'contributor', - qualifier: 'illustrator', - scopeNote: null, - schema: mockSchemasList[1], - type: MetadataField.type - }) + id: 4, + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11' } + }, + element: 'contributor', + qualifier: 'illustrator', + scopeNote: null, + schema: mockSchemasList[1], + type: MetadataField.type + }) ]; const pageInfo = new PageInfo(); @@ -130,7 +140,7 @@ describe('RegistryService', () => { toRemoteDataObservable: (requestEntryObs: Observable, payloadObs: Observable) => { return observableCombineLatest(requestEntryObs, payloadObs).pipe(map(([req, pay]) => { - return {req, pay}; + return { req, pay }; }) ); }, @@ -146,11 +156,11 @@ describe('RegistryService', () => { DummyComponent ], providers: [ - {provide: RequestService, useValue: getMockRequestService()}, - {provide: RemoteDataBuildService, useValue: rdbStub}, - {provide: HALEndpointService, useValue: halServiceStub}, - {provide: Store, useClass: MockStore}, - {provide: NotificationsService, useValue: new NotificationsServiceStub()}, + { provide: RequestService, useValue: getMockRequestService() }, + { provide: RemoteDataBuildService, useValue: rdbStub }, + { provide: HALEndpointService, useValue: halServiceStub }, + { provide: Store, useClass: MockStore }, + { provide: NotificationsService, useValue: new NotificationsServiceStub() }, RegistryService ] }); @@ -165,7 +175,7 @@ describe('RegistryService', () => { page: pageInfo }); const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo); - const responseEntry = Object.assign(new RequestEntry(), {response: response}); + const responseEntry = Object.assign(new RequestEntry(), { response: response }); beforeEach(() => { (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry)); @@ -194,7 +204,7 @@ describe('RegistryService', () => { page: pageInfo }); const response = new RegistryMetadataschemasSuccessResponse(queryResponse, 200, 'OK', pageInfo); - const responseEntry = Object.assign(new RequestEntry(), {response: response}); + const responseEntry = Object.assign(new RequestEntry(), { response: response }); beforeEach(() => { (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry)); @@ -223,7 +233,7 @@ describe('RegistryService', () => { page: pageInfo }); const response = new RegistryMetadatafieldsSuccessResponse(queryResponse, 200, 'OK', pageInfo); - const responseEntry = Object.assign(new RequestEntry(), {response: response}); + const responseEntry = Object.assign(new RequestEntry(), { response: response }); beforeEach(() => { (registryService as any).requestService.getByHref.and.returnValue(observableOf(responseEntry)); diff --git a/src/app/core/registry/registry.service.ts b/src/app/core/registry/registry.service.ts index 3c6de36492..fbc42b26f4 100644 --- a/src/app/core/registry/registry.service.ts +++ b/src/app/core/registry/registry.service.ts @@ -2,6 +2,7 @@ import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { Injectable } from '@angular/core'; import { RemoteData } from '../data/remote-data'; import { PaginatedList } from '../data/paginated-list'; +import { DSpaceSerializer } from '../dspace-rest-v2/dspace.serializer'; import { PageInfo } from '../shared/page-info.model'; import { CreateMetadataFieldRequest, @@ -48,8 +49,6 @@ import { MetadataRegistrySelectSchemaAction } from '../../+admin/admin-registries/metadata-registry/metadata-registry.actions'; import { distinctUntilChanged, flatMap, map, take, tap } from 'rxjs/operators'; -import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer'; -import { NormalizedMetadataSchema } from '../metadata/normalized-metadata-schema.model'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; @@ -57,7 +56,7 @@ import { HttpHeaders } from '@angular/common/http'; import { TranslateService } from '@ngx-translate/core'; import { MetadataSchema } from '../metadata/metadata-schema.model'; import { MetadataField } from '../metadata/metadata-field.model'; -import { getMapsToType } from '../cache/builders/build-decorators'; +import { getClassForType } from '../cache/builders/build-decorators'; const metadataRegistryStateSelector = (state: AppState) => state.metadataRegistry; const editMetadataSchemaSelector = createSelector(metadataRegistryStateSelector, (metadataState: MetadataRegistryState) => metadataState.editSchema); @@ -400,7 +399,7 @@ export class RegistryService { distinctUntilChanged() ); - const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema); + const serializedSchema = new DSpaceSerializer(getClassForType(MetadataSchema.type)).serialize(schema); const request$ = endpoint$.pipe( take(1), diff --git a/src/app/core/services/route.actions.ts b/src/app/core/services/route.actions.ts index 1f6381d2c6..1d3381e2ec 100644 --- a/src/app/core/services/route.actions.ts +++ b/src/app/core/services/route.actions.ts @@ -162,4 +162,5 @@ export type RouteActions = | AddQueryParameterAction | AddParameterAction | ResetRouteStateAction - | SetParameterAction; + | SetParameterAction + | SetQueryParameterAction; diff --git a/src/app/core/shared/bitstream-format.model.ts b/src/app/core/shared/bitstream-format.model.ts index 0e1279e978..8aeba1e3cd 100644 --- a/src/app/core/shared/bitstream-format.model.ts +++ b/src/app/core/shared/bitstream-format.model.ts @@ -1,52 +1,69 @@ -import { CacheableObject, TypedObject } from '../cache/object-cache.reducer'; -import { ResourceType } from './resource-type'; +import { autoserialize, deserialize, deserializeAs } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../cache/id-to-uuid-serializer'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { excludeFromEquals } from '../utilities/equals.decorators'; import { BitstreamFormatSupportLevel } from './bitstream-format-support-level'; +import { BITSTREAM_FORMAT } from './bitstream-format.resource-type'; +import { HALLink } from './hal-link.model'; +import { ResourceType } from './resource-type'; /** * Model class for a Bitstream Format */ +@typedObject export class BitstreamFormat implements CacheableObject { - static type = new ResourceType('bitstreamformat'); + static type = BITSTREAM_FORMAT; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; - bitstreamformat /** * Short description of this Bitstream Format */ + @autoserialize shortDescription: string; /** * Description of this Bitstream Format */ + @autoserialize description: string; /** * String representing the MIME type of this Bitstream Format */ + @autoserialize mimetype: string; /** * The level of support the system offers for this Bitstream Format */ + @autoserialize supportLevel: BitstreamFormatSupportLevel; /** * True if the Bitstream Format is used to store system information, rather than the content of items in the system */ + @autoserialize internal: boolean; /** * String representing this Bitstream Format's file extension */ + @autoserialize extensions: string[]; - /** - * The link to the rest endpoint where this Bitstream Format can be found - */ - self: string; - /** * Universally unique identifier for this Bitstream Format + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. */ + @deserializeAs(new IDToUUIDSerializer('bitstream-format'), 'id') uuid: string; /** @@ -54,6 +71,14 @@ export class BitstreamFormat implements CacheableObject { * Note that this ID is unique for bitstream formats, * but might not be unique across different object types */ + @autoserialize id: string; + /** + * The {@link HALLink}s for this BitstreamFormat + */ + @deserialize + _links: { + self: HALLink; + } } diff --git a/src/app/core/shared/bitstream-format.resource-type.ts b/src/app/core/shared/bitstream-format.resource-type.ts new file mode 100644 index 0000000000..b1184e2665 --- /dev/null +++ b/src/app/core/shared/bitstream-format.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for BitstreamFormat + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const BITSTREAM_FORMAT = new ResourceType('bitstreamformat'); diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts index 887f7d0843..231d44eeff 100644 --- a/src/app/core/shared/bitstream.model.ts +++ b/src/app/core/shared/bitstream.model.ts @@ -1,45 +1,60 @@ -import { DSpaceObject } from './dspace-object.model'; -import { RemoteData } from '../data/remote-data'; -import { Item } from './item.model'; -import { BitstreamFormat } from './bitstream-format.model'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; -import { ResourceType } from './resource-type'; +import { link, typedObject } from '../cache/builders/build-decorators'; +import { RemoteData } from '../data/remote-data'; +import { BitstreamFormat } from './bitstream-format.model'; +import { BITSTREAM_FORMAT } from './bitstream-format.resource-type'; +import { BITSTREAM } from './bitstream.resource-type'; +import { DSpaceObject } from './dspace-object.model'; +import { HALLink } from './hal-link.model'; +import { HALResource } from './hal-resource.model'; -export class Bitstream extends DSpaceObject { - static type = new ResourceType('bitstream'); +@typedObject +@inheritSerialization(DSpaceObject) +export class Bitstream extends DSpaceObject implements HALResource { + static type = BITSTREAM; /** * The size of this bitstream in bytes */ + @autoserialize sizeBytes: number; /** * The description of this Bitstream */ + @autoserialize description: string; /** * The name of the Bundle this Bitstream is part of */ + @autoserialize bundleName: string; /** - * An array of Bitstream Format of this Bitstream + * The {@link HALLink}s for this Bitstream */ - format: Observable>; + @deserialize + _links: { + self: HALLink; + bundle: HALLink; + format: HALLink; + content: HALLink; + }; /** - * An array of Items that are direct parents of this Bitstream + * The thumbnail for this Bitstream + * Needs to be resolved first, but isn't available as a {@link HALLink} yet + * Use BitstreamDataService.getThumbnailFor(…) for now. */ - parents: Observable>; + thumbnail?: Observable>; /** - * The Bundle that owns this Bitstream + * The BitstreamFormat of this Bitstream + * Will be undefined unless the format {@link HALLink} has been resolved. */ - owner: Observable>; + @link(BITSTREAM_FORMAT) + format?: Observable>; - /** - * The URL to retrieve this Bitstream's file - */ - content: string; } diff --git a/src/app/core/shared/bitstream.resource-type.ts b/src/app/core/shared/bitstream.resource-type.ts new file mode 100644 index 0000000000..d2ff21ae60 --- /dev/null +++ b/src/app/core/shared/bitstream.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Bitstream + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const BITSTREAM = new ResourceType('bitstream'); diff --git a/src/app/core/shared/browse-definition.model.ts b/src/app/core/shared/browse-definition.model.ts index 9fafe7e321..e1d0e0bf01 100644 --- a/src/app/core/shared/browse-definition.model.ts +++ b/src/app/core/shared/browse-definition.model.ts @@ -1,10 +1,22 @@ -import { autoserialize, autoserializeAs } from 'cerialize'; -import { SortOption } from './sort-option.model'; -import { ResourceType } from './resource-type'; +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; import { TypedObject } from '../cache/object-cache.reducer'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { BROWSE_DEFINITION } from './browse-definition.resource-type'; +import { HALLink } from './hal-link.model'; +import { ResourceType } from './resource-type'; +import { SortOption } from './sort-option.model'; +@typedObject export class BrowseDefinition implements TypedObject { - static type = new ResourceType('browse'); + static type = BROWSE_DEFINITION; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; @autoserialize id: string; @@ -21,8 +33,14 @@ export class BrowseDefinition implements TypedObject { @autoserializeAs('metadata') metadataKeys: string[]; - @autoserialize - _links: { - [name: string]: string + get self(): string { + return this._links.self.href; } + + @deserialize + _links: { + self: HALLink; + entries: HALLink; + items: HALLink; + }; } diff --git a/src/app/core/shared/browse-definition.resource-type.ts b/src/app/core/shared/browse-definition.resource-type.ts new file mode 100644 index 0000000000..f79ee1f020 --- /dev/null +++ b/src/app/core/shared/browse-definition.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for BrowseDefinition + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const BROWSE_DEFINITION = new ResourceType('browse'); diff --git a/src/app/core/shared/browse-entry.model.ts b/src/app/core/shared/browse-entry.model.ts index d6074de3f5..b5e971d069 100644 --- a/src/app/core/shared/browse-entry.model.ts +++ b/src/app/core/shared/browse-entry.model.ts @@ -1,37 +1,58 @@ +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { typedObject } from '../cache/builders/build-decorators'; import { TypedObject } from '../cache/object-cache.reducer'; -import { ResourceType } from './resource-type'; -import { GenericConstructor } from './generic-constructor'; import { excludeFromEquals } from '../utilities/equals.decorators'; +import { BROWSE_ENTRY } from './browse-entry.resource-type'; +import { GenericConstructor } from './generic-constructor'; +import { HALLink } from './hal-link.model'; +import { ResourceType } from './resource-type'; /** * Class object representing a browse entry - * This class is not normalized because browse entries do not have self links */ +@typedObject export class BrowseEntry extends ListableObject implements TypedObject { - static type = new ResourceType('browseEntry'); + static type = BROWSE_ENTRY; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The authority string of this browse entry */ + @autoserialize authority: string; /** * The value of this browse entry */ + @autoserialize value: string; /** * The language of the value of this browse entry */ + @autoserializeAs('valueLang') language: string; /** * The count of this browse entry */ @excludeFromEquals + @autoserialize count: number; + @deserialize + _links: { + self: HALLink; + entries: HALLink; + }; + /** * Method that returns as which type of object this object should be rendered */ diff --git a/src/app/core/shared/browse-entry.resource-type.ts b/src/app/core/shared/browse-entry.resource-type.ts new file mode 100644 index 0000000000..648f7ee31f --- /dev/null +++ b/src/app/core/shared/browse-entry.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for BrowseEntry + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const BROWSE_ENTRY = new ResourceType('browseEntry'); diff --git a/src/app/core/shared/bundle.model.ts b/src/app/core/shared/bundle.model.ts index dade7d12be..c1164f0fc4 100644 --- a/src/app/core/shared/bundle.model.ts +++ b/src/app/core/shared/bundle.model.ts @@ -1,37 +1,21 @@ +import { deserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; +import { BUNDLE } from './bundle.resource-type'; import { DSpaceObject } from './dspace-object.model'; -import { Bitstream } from './bitstream.model'; -import { Item } from './item.model'; -import { RemoteData } from '../data/remote-data'; -import { Observable } from 'rxjs'; -import { ResourceType } from './resource-type'; -import { PaginatedList } from '../data/paginated-list'; +import { HALLink } from './hal-link.model'; +@typedObject +@inheritSerialization(DSpaceObject) export class Bundle extends DSpaceObject { - static type = new ResourceType('bundle'); + static type = BUNDLE; /** - * The bundle's name + * The {@link HALLink}s for this Bundle */ - name: string; - - /** - * The primary bitstream of this Bundle - */ - primaryBitstream: Observable>; - - /** - * An array of Items that are direct parents of this Bundle - */ - parents: Observable>; - - /** - * The Item that owns this Bundle - */ - owner: Observable>; - - /** - * List of Bitstreams that are part of this Bundle - */ - bitstreams: Observable>>; - + @deserialize + _links: { + self: HALLink; + primaryBitstream: HALLink; + bitstreams: HALLink; + } } diff --git a/src/app/core/shared/bundle.resource-type.ts b/src/app/core/shared/bundle.resource-type.ts new file mode 100644 index 0000000000..18c2f1c1b9 --- /dev/null +++ b/src/app/core/shared/bundle.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Bundle + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const BUNDLE = new ResourceType('bundle'); diff --git a/src/app/core/shared/collection.model.ts b/src/app/core/shared/collection.model.ts index 642fe50736..d5c6221428 100644 --- a/src/app/core/shared/collection.model.ts +++ b/src/app/core/shared/collection.model.ts @@ -1,21 +1,64 @@ -import { DSpaceObject } from './dspace-object.model'; -import { Bitstream } from './bitstream.model'; -import { Item } from './item.model'; -import { RemoteData } from '../data/remote-data'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; -import { License } from './license.model'; -import { ResourcePolicy } from './resource-policy.model'; +import { link, typedObject } from '../cache/builders/build-decorators'; import { PaginatedList } from '../data/paginated-list'; -import { ResourceType } from './resource-type'; +import { RemoteData } from '../data/remote-data'; +import { Bitstream } from './bitstream.model'; +import { BITSTREAM } from './bitstream.resource-type'; +import { COLLECTION } from './collection.resource-type'; +import { DSpaceObject } from './dspace-object.model'; +import { HALLink } from './hal-link.model'; +import { License } from './license.model'; +import { LICENSE } from './license.resource-type'; +import { ResourcePolicy } from './resource-policy.model'; +import { RESOURCE_POLICY } from './resource-policy.resource-type'; +@typedObject +@inheritSerialization(DSpaceObject) export class Collection extends DSpaceObject { - static type = new ResourceType('collection'); + static type = COLLECTION; /** * A string representing the unique handle of this Collection */ + @autoserialize handle: string; + /** + * The {@link HALLink}s for this Collection + */ + @deserialize + _links: { + license: HALLink; + harvester: HALLink; + mappedItems: HALLink; + itemtemplate: HALLink; + defaultAccessConditions: HALLink; + logo: HALLink; + self: HALLink; + }; + + /** + * The license for this Collection + * Will be undefined unless the license {@link HALLink} has been resolved. + */ + @link(LICENSE) + license?: Observable>; + + /** + * The logo for this Collection + * Will be undefined unless the logo {@link HALLink} has been resolved. + */ + @link(BITSTREAM) + logo?: Observable>; + + /** + * The default access conditions for this Collection + * Will be undefined unless the defaultAccessConditions {@link HALLink} has been resolved. + */ + @link(RESOURCE_POLICY, true) + defaultAccessConditions?: Observable>>; + /** * The introductory text of this Collection * Corresponds to the metadata field dc.description @@ -55,31 +98,4 @@ export class Collection extends DSpaceObject { get sidebarText(): string { return this.firstMetadataValue('dc.description.tableofcontents'); } - - /** - * The deposit license of this Collection - */ - license: Observable>; - - /** - * The Bitstream that represents the logo of this Collection - */ - logo: Observable>; - - /** - * The default access conditions of this Collection - */ - defaultAccessConditions: Observable>>; - - /** - * An array of Collections that are direct parents of this Collection - */ - parents: Observable>; - - /** - * The Collection that owns this Collection - */ - owner: Observable>; - - items: Observable>; } diff --git a/src/app/core/shared/collection.resource-type.ts b/src/app/core/shared/collection.resource-type.ts new file mode 100644 index 0000000000..899b33f7d2 --- /dev/null +++ b/src/app/core/shared/collection.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Collection + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const COLLECTION = new ResourceType('collection'); diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts index b61ddfd7f9..703c4b3eef 100644 --- a/src/app/core/shared/community.model.ts +++ b/src/app/core/shared/community.model.ts @@ -1,19 +1,59 @@ -import { DSpaceObject } from './dspace-object.model'; -import { Bitstream } from './bitstream.model'; -import { Collection } from './collection.model'; -import { RemoteData } from '../data/remote-data'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../cache/builders/build-decorators'; import { PaginatedList } from '../data/paginated-list'; -import { ResourceType } from './resource-type'; +import { RemoteData } from '../data/remote-data'; +import { Bitstream } from './bitstream.model'; +import { BITSTREAM } from './bitstream.resource-type'; +import { Collection } from './collection.model'; +import { COLLECTION } from './collection.resource-type'; +import { COMMUNITY } from './community.resource-type'; +import { DSpaceObject } from './dspace-object.model'; +import { HALLink } from './hal-link.model'; +@typedObject +@inheritSerialization(DSpaceObject) export class Community extends DSpaceObject { - static type = new ResourceType('community'); + static type = COMMUNITY; /** * A string representing the unique handle of this Community */ + @autoserialize handle: string; + /** + * The {@link HALLink}s for this Community + */ + @deserialize + _links: { + collections: HALLink; + logo: HALLink; + subcommunities: HALLink; + self: HALLink; + }; + + /** + * The logo for this Community + * Will be undefined unless the logo {@link HALLink} has been resolved. + */ + @link(BITSTREAM) + logo?: Observable>; + + /** + * The list of Collections that are direct children of this Community + * Will be undefined unless the collections {@link HALLink} has been resolved. + */ + @link(COLLECTION, true) + collections?: Observable>>; + + /** + * The list of Communities that are direct children of this Community + * Will be undefined unless the subcommunities {@link HALLink} has been resolved. + */ + @link(COMMUNITY, true) + subcommunities?: Observable>>; + /** * The introductory text of this Community * Corresponds to the metadata field dc.description @@ -45,24 +85,4 @@ export class Community extends DSpaceObject { get sidebarText(): string { return this.firstMetadataValue('dc.description.tableofcontents'); } - - /** - * The Bitstream that represents the logo of this Community - */ - logo: Observable>; - - /** - * An array of Communities that are direct parents of this Community - */ - parents: Observable>; - - /** - * The Community that owns this Community - */ - owner: Observable>; - - collections: Observable>>; - - subcommunities: Observable>>; - } diff --git a/src/app/core/shared/community.resource-type.ts b/src/app/core/shared/community.resource-type.ts new file mode 100644 index 0000000000..2d5f74cafc --- /dev/null +++ b/src/app/core/shared/community.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Community + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const COMMUNITY = new ResourceType('community'); diff --git a/src/app/core/shared/content-source.model.ts b/src/app/core/shared/content-source.model.ts index cd53c2d81e..3e530b6a3a 100644 --- a/src/app/core/shared/content-source.model.ts +++ b/src/app/core/shared/content-source.model.ts @@ -1,4 +1,6 @@ import { autoserialize, autoserializeAs, deserializeAs, deserialize } from 'cerialize'; +import { HALLink } from './hal-link.model'; +import { HALResource } from './hal-resource.model'; import { MetadataConfig } from './metadata-config.model'; /** @@ -14,7 +16,7 @@ export enum ContentSourceHarvestType { /** * A model class that holds information about the Content Source of a Collection */ -export class ContentSource { +export class ContentSource implements HALResource { /** * Unique identifier, this is necessary to store the ContentSource in FieldUpdates * Because the ContentSource coming from the REST API doesn't have a UUID, we're using the selflink @@ -53,8 +55,10 @@ export class ContentSource { metadataConfigs: MetadataConfig[]; /** - * The REST link to itself + * The {@link HALLink}s for this ContentSource */ @deserialize - self: string; + _links: { + self: HALLink + } } diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index 4fec28d246..2e1afe9c8a 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -1,52 +1,72 @@ -import { Observable } from 'rxjs'; - +import { autoserialize, autoserializeAs, deserialize, deserializeAs } from 'cerialize'; +import { hasNoValue, isUndefined } from '../../shared/empty.util'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { typedObject } from '../cache/builders/build-decorators'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { DSPACE_OBJECT } from './dspace-object.resource-type'; +import { GenericConstructor } from './generic-constructor'; +import { HALLink } from './hal-link.model'; import { MetadataMap, + MetadataMapSerializer, MetadataValue, MetadataValueFilter, MetadatumViewModel } from './metadata.models'; import { Metadata } from './metadata.utils'; -import { hasNoValue, isUndefined } from '../../shared/empty.util'; -import { CacheableObject } from '../cache/object-cache.reducer'; -import { RemoteData } from '../data/remote-data'; -import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; -import { excludeFromEquals } from '../utilities/equals.decorators'; import { ResourceType } from './resource-type'; -import { GenericConstructor } from './generic-constructor'; /** * An abstract model class for a DSpaceObject. */ +@typedObject export class DSpaceObject extends ListableObject implements CacheableObject { /** * A string representing the kind of DSpaceObject, e.g. community, item, … */ - static type = new ResourceType('dspaceobject'); + static type = DSPACE_OBJECT; @excludeFromEquals + @deserializeAs('name') private _name: string; - @excludeFromEquals - self: string; - /** * The human-readable identifier of this DSpaceObject */ @excludeFromEquals + @autoserializeAs(String, 'uuid') id: string; /** * The universally unique identifier of this DSpaceObject */ + @autoserializeAs(String) uuid: string; /** * A string representing the kind of DSpaceObject, e.g. community, item, … */ @excludeFromEquals + @autoserialize type: ResourceType; + /** + * A shorthand to get this DSpaceObject's self link + */ + get self(): string { + return this._links.self.href; + } + + /** + * A shorthand to set this DSpaceObject's self link + */ + set self(v: string) { + this._links.self = { + href: v + }; + } + /** * The name for this DSpaceObject */ @@ -65,8 +85,14 @@ export class DSpaceObject extends ListableObject implements CacheableObject { * All metadata of this DSpaceObject */ @excludeFromEquals + @autoserializeAs(MetadataMapSerializer) metadata: MetadataMap; + @deserialize + _links: { + self: HALLink; + }; + /** * Retrieve the current metadata as a list of MetadatumViewModels */ @@ -74,18 +100,6 @@ export class DSpaceObject extends ListableObject implements CacheableObject { return Metadata.toViewModelList(this.metadata); } - /** - * An array of DSpaceObjects that are direct parents of this DSpaceObject - */ - @excludeFromEquals - parents: Observable>; - - /** - * The DSpaceObject that owns this DSpaceObject - */ - @excludeFromEquals - owner: Observable>; - /** * Gets all matching metadata in this DSpaceObject. * diff --git a/src/app/core/shared/dspace-object.resource-type.ts b/src/app/core/shared/dspace-object.resource-type.ts new file mode 100644 index 0000000000..7d2b445070 --- /dev/null +++ b/src/app/core/shared/dspace-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for DSpaceObject + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const DSPACE_OBJECT = new ResourceType('dspaceobject'); diff --git a/src/app/core/shared/external-source-entry.model.ts b/src/app/core/shared/external-source-entry.model.ts index 2451aa4d24..5836a01138 100644 --- a/src/app/core/shared/external-source-entry.model.ts +++ b/src/app/core/shared/external-source-entry.model.ts @@ -1,43 +1,64 @@ -import { MetadataMap } from './metadata.models'; -import { ResourceType } from './resource-type'; +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { typedObject } from '../cache/builders/build-decorators'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { EXTERNAL_SOURCE_ENTRY } from './external-source-entry.resource-type'; import { GenericConstructor } from './generic-constructor'; +import { HALLink } from './hal-link.model'; +import { MetadataMap, MetadataMapSerializer } from './metadata.models'; +import { ResourceType } from './resource-type'; /** * Model class for a single entry from an external source */ +@typedObject export class ExternalSourceEntry extends ListableObject { - static type = new ResourceType('externalSourceEntry'); + static type = EXTERNAL_SOURCE_ENTRY; /** * Unique identifier */ + @autoserialize id: string; + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; + /** * The value to display */ + @autoserialize display: string; /** * The value to store the entry with */ + @autoserialize value: string; /** * The ID of the external source this entry originates from */ + @autoserialize externalSource: string; /** * Metadata of the entry */ + @autoserializeAs(MetadataMapSerializer) metadata: MetadataMap; /** - * The link to the rest endpoint where this External Source Entry can be found + * The {@link HALLink}s for this ExternalSourceEntry */ - self: string; + @deserialize + _links: { + self: HALLink; + }; /** * Method that returns as which type of object this object should be rendered diff --git a/src/app/core/shared/external-source-entry.resource-type.ts b/src/app/core/shared/external-source-entry.resource-type.ts new file mode 100644 index 0000000000..0fc25a5e3f --- /dev/null +++ b/src/app/core/shared/external-source-entry.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for ResourceType + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const EXTERNAL_SOURCE_ENTRY = new ResourceType('externalSourceEntry'); diff --git a/src/app/core/shared/external-source.model.ts b/src/app/core/shared/external-source.model.ts index a158f18f5d..5005fbcd36 100644 --- a/src/app/core/shared/external-source.model.ts +++ b/src/app/core/shared/external-source.model.ts @@ -1,29 +1,49 @@ -import { ResourceType } from './resource-type'; +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; import { CacheableObject } from '../cache/object-cache.reducer'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { EXTERNAL_SOURCE } from './external-source.resource-type'; +import { HALLink } from './hal-link.model'; +import { ResourceType } from './resource-type'; /** * Model class for an external source */ +@typedObject export class ExternalSource extends CacheableObject { - static type = new ResourceType('externalsource'); + static type = EXTERNAL_SOURCE; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; /** * Unique identifier */ + @autoserialize id: string; /** * The name of this external source */ + @autoserialize name: string; /** * Is the source hierarchical? */ + @autoserialize hierarchical: boolean; /** - * The link to the rest endpoint where this External Source can be found + * The {@link HALLink}s for this ExternalSource */ - self: string; + @deserialize + _links: { + self: HALLink; + entries: HALLink; + } } diff --git a/src/app/core/shared/external-source.resource-type.ts b/src/app/core/shared/external-source.resource-type.ts new file mode 100644 index 0000000000..2cf07bd5fc --- /dev/null +++ b/src/app/core/shared/external-source.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for ExternalSource + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const EXTERNAL_SOURCE = new ResourceType('externalsource'); diff --git a/src/app/core/shared/hal-endpoint.service.spec.ts b/src/app/core/shared/hal-endpoint.service.spec.ts index 8b3011e7d7..cd03b6ec71 100644 --- a/src/app/core/shared/hal-endpoint.service.spec.ts +++ b/src/app/core/shared/hal-endpoint.service.spec.ts @@ -89,7 +89,7 @@ describe('HALEndpointService', () => { .returnValue(hot('a-', { a: 'https://rest.api/test' })); const result = service.getEndpoint(linkPath); - const expected = cold('b-', { b: endpointMap.test }); + const expected = cold('(b|)', { b: endpointMap.test }); expect(result).toBeObservable(expected); }); @@ -97,7 +97,7 @@ describe('HALEndpointService', () => { spyOn(service as any, 'getEndpointAt').and .returnValue(hot('a-', { a: undefined })); const result = service.getEndpoint('unknown'); - const expected = cold('b-', { b: undefined }); + const expected = cold('(b|)', { b: undefined }); expect(result).toBeObservable(expected); }); }); diff --git a/src/app/core/shared/hal-endpoint.service.ts b/src/app/core/shared/hal-endpoint.service.ts index 117cc074ca..530ac086d1 100644 --- a/src/app/core/shared/hal-endpoint.service.ts +++ b/src/app/core/shared/hal-endpoint.service.ts @@ -4,13 +4,14 @@ import { map, mergeMap, startWith, - switchMap, + switchMap, take, tap } from 'rxjs/operators'; +import { RequestEntry } from '../data/request.reducer'; import { RequestService } from '../data/request.service'; import { GlobalConfig } from '../../../config/global-config.interface'; import { EndpointMapRequest } from '../data/request.models'; -import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; +import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { Inject, Injectable } from '@angular/core'; import { GLOBAL_CONFIG } from '../../../config'; @@ -36,7 +37,11 @@ export class HALEndpointService { private getEndpointMapAt(href): Observable { const request = new EndpointMapRequest(this.requestService.generateRequestId(), href); - this.requestService.configure(request); + if (!this.requestService.isCachedOrPending(request)) { + // don't bother configuring the request if it's already cached or pending. + this.requestService.configure(request); + } + return this.requestService.getByHref(request.href).pipe( getResponseFromEntry(), map((response: EndpointMapSuccessResponse) => response.endpointMap), @@ -44,7 +49,7 @@ export class HALEndpointService { } public getEndpoint(linkPath: string, startHref?: string): Observable { - return this.getEndpointAt(startHref || this.getRootHref(), ...linkPath.split('/')); + return this.getEndpointAt(startHref || this.getRootHref(), ...linkPath.split('/')).pipe(take(1)); } /** @@ -71,10 +76,11 @@ export class HALEndpointService { ) as Observable; if (halNames.length === 1) { - return nextHref$; + return nextHref$.pipe(take(1)); } else { return nextHref$.pipe( - switchMap((nextHref) => this.getEndpointAt(nextHref, ...halNames.slice(1))) + switchMap((nextHref) => this.getEndpointAt(nextHref, ...halNames.slice(1))), + take(1) ); } } diff --git a/src/app/core/shared/hal-link.model.ts b/src/app/core/shared/hal-link.model.ts new file mode 100644 index 0000000000..88a136a4b2 --- /dev/null +++ b/src/app/core/shared/hal-link.model.ts @@ -0,0 +1,23 @@ +/** + * A single link in the _links section of a {@link HALResource} + */ +export class HALLink { + + /** + * The url of the {@link HALLink}'s target + */ + href: string; + + /** + * The name of the {@link HALLink} + */ + name?: string; + + /** + * A boolean indicating whether the href contains a template. + * + * e.g. if href is "http://haltalk.herokuapp.com/docs/{rel}" + * {rel} would be the template + */ + templated?: boolean +} diff --git a/src/app/core/shared/hal-resource.model.ts b/src/app/core/shared/hal-resource.model.ts new file mode 100644 index 0000000000..b6ef822a23 --- /dev/null +++ b/src/app/core/shared/hal-resource.model.ts @@ -0,0 +1,23 @@ +import { HALLink } from './hal-link.model'; + +/** + * Represents HAL resources. + * + * A HAL resource has a _links section with at least a self link. + */ +export class HALResource { + /** + * The {@link HALLink}s for this {@link HALResource} + */ + _links: { + /** + * The {@link HALLink} that refers to this {@link HALResource} + */ + self: HALLink + + /** + * {@link HALLink}s to related {@link HALResource}s + */ + [k: string]: HALLink; + }; +} diff --git a/src/app/core/shared/item-relationships/item-type.model.ts b/src/app/core/shared/item-relationships/item-type.model.ts index 0fc52b00a5..d41024cdaa 100644 --- a/src/app/core/shared/item-relationships/item-type.model.ts +++ b/src/app/core/shared/item-relationships/item-type.model.ts @@ -1,26 +1,48 @@ +import { autoserialize, deserialize, deserializeAs } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; import { CacheableObject } from '../../cache/object-cache.reducer'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { HALLink } from '../hal-link.model'; import { ResourceType } from '../resource-type'; +import { ITEM_TYPE } from './item-type.resource-type'; /** * Describes a type of Item */ +@typedObject export class ItemType implements CacheableObject { - static type = new ResourceType('entitytype'); + static type = ITEM_TYPE; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The identifier of this ItemType */ + @autoserialize id: string; + @autoserialize label: string; /** - * The link to the rest endpoint where this object can be found + * The universally unique identifier of this ItemType + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. */ - self: string; + @deserializeAs(new IDToUUIDSerializer(ItemType.type.value), 'id') + uuid: string; /** - * The universally unique identifier of this ItemType + * The {@link HALLink}s for this ItemType */ - uuid: string; + @deserialize + _links: { + self: HALLink, + }; } diff --git a/src/app/core/shared/item-relationships/item-type.resource-type.ts b/src/app/core/shared/item-relationships/item-type.resource-type.ts new file mode 100644 index 0000000000..616dc23b73 --- /dev/null +++ b/src/app/core/shared/item-relationships/item-type.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../resource-type'; + +/** + * The resource type for ItemType + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const ITEM_TYPE = new ResourceType('entitytype'); diff --git a/src/app/core/shared/item-relationships/relationship-type.model.ts b/src/app/core/shared/item-relationships/relationship-type.model.ts index 06ac94b041..fb62f685dd 100644 --- a/src/app/core/shared/item-relationships/relationship-type.model.ts +++ b/src/app/core/shared/item-relationships/relationship-type.model.ts @@ -1,72 +1,107 @@ +import { autoserialize, deserialize, deserializeAs } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; import { CacheableObject } from '../../cache/object-cache.reducer'; import { RemoteData } from '../../data/remote-data'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { HALLink } from '../hal-link.model'; import { ResourceType } from '../resource-type'; import { ItemType } from './item-type.model'; +import { ITEM_TYPE } from './item-type.resource-type'; +import { RELATIONSHIP_TYPE } from './relationship-type.resource-type'; /** * Describes a type of Relationship between multiple possible Items */ +@typedObject export class RelationshipType implements CacheableObject { - static type = new ResourceType('relationshiptype'); + static type = RELATIONSHIP_TYPE; /** - * The link to the rest endpoint where this object can be found + * The object type */ - self: string; + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The label that describes this RelationshipType */ + @autoserialize label: string; /** * The identifier of this RelationshipType */ + @autoserialize id: string; /** * The universally unique identifier of this RelationshipType + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. */ + @deserializeAs(new IDToUUIDSerializer(RelationshipType.type.value), 'id') uuid: string; /** * The label that describes the Relation to the left of this RelationshipType */ + @autoserialize leftwardType: string; /** * The maximum amount of Relationships allowed to the left of this RelationshipType */ + @autoserialize leftMaxCardinality: number; /** * The minimum amount of Relationships allowed to the left of this RelationshipType */ + @autoserialize leftMinCardinality: number; /** * The label that describes the Relation to the right of this RelationshipType */ + @autoserialize rightwardType: string; /** * The maximum amount of Relationships allowed to the right of this RelationshipType */ + @autoserialize rightMaxCardinality: number; /** * The minimum amount of Relationships allowed to the right of this RelationshipType */ + @autoserialize rightMinCardinality: number; /** - * The type of Item found to the left of this RelationshipType + * The {@link HALLink}s for this RelationshipType */ - leftType: Observable>; + @deserialize + _links: { + self: HALLink; + leftType: HALLink; + rightType: HALLink; + }; /** - * The type of Item found to the right of this RelationshipType + * The type of Item found on the left side of this RelationshipType + * Will be undefined unless the leftType {@link HALLink} has been resolved. */ - rightType: Observable>; + @link(ITEM_TYPE) + leftType?: Observable>; + + /** + * The type of Item found on the right side of this RelationshipType + * Will be undefined unless the rightType {@link HALLink} has been resolved. + */ + @link(ITEM_TYPE) + rightType?: Observable>; } diff --git a/src/app/core/shared/item-relationships/relationship-type.resource-type.ts b/src/app/core/shared/item-relationships/relationship-type.resource-type.ts new file mode 100644 index 0000000000..6f6300c38e --- /dev/null +++ b/src/app/core/shared/item-relationships/relationship-type.resource-type.ts @@ -0,0 +1,10 @@ +import { ResourceType } from '../resource-type'; + +/** + * The resource type for RelationshipType + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ + +export const RELATIONSHIP_TYPE = new ResourceType('relationshiptype'); diff --git a/src/app/core/shared/item-relationships/relationship.model.ts b/src/app/core/shared/item-relationships/relationship.model.ts index 2adcf42c04..97a5db9e37 100644 --- a/src/app/core/shared/item-relationships/relationship.model.ts +++ b/src/app/core/shared/item-relationships/relationship.model.ts @@ -1,63 +1,100 @@ +import { autoserialize, deserialize, serialize, deserializeAs } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; import { CacheableObject } from '../../cache/object-cache.reducer'; import { RemoteData } from '../../data/remote-data'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; +import { HALLink } from '../hal-link.model'; +import { Item } from '../item.model'; +import { ITEM } from '../item.resource-type'; import { ResourceType } from '../resource-type'; import { RelationshipType } from './relationship-type.model'; -import { Item } from '../item.model'; +import { RELATIONSHIP_TYPE } from './relationship-type.resource-type'; +import { RELATIONSHIP } from './relationship.resource-type'; /** * Describes a Relationship between two Items */ +@typedObject export class Relationship implements CacheableObject { - static type = new ResourceType('relationship'); + static type = RELATIONSHIP; /** - * The link to the rest endpoint where this object can be found + * The object type */ - self: string; + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The universally unique identifier of this Relationship + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. */ + @deserializeAs(new IDToUUIDSerializer(Relationship.type.value), 'id') uuid: string; /** * The identifier of this Relationship */ + @autoserialize id: string; - /** - * The item to the left of this relationship - */ - leftItem: Observable>; - - /** - * The item to the right of this relationship - */ - rightItem: Observable>; - /** * The place of the Item to the left side of this Relationship */ + @autoserialize leftPlace: number; /** * The place of the Item to the right side of this Relationship */ + @autoserialize rightPlace: number; /** * The name variant of the Item to the left side of this Relationship */ + @autoserialize leftwardValue: string; /** * The name variant of the Item to the right side of this Relationship */ + @autoserialize rightwardValue: string; /** - * The type of Relationship + * The {@link HALLink}s for this Relationship */ - relationshipType: Observable>; + @deserialize + _links: { + self: HALLink; + leftItem: HALLink; + rightItem: HALLink; + relationshipType: HALLink; + }; + + /** + * The item on the left side of this relationship + * Will be undefined unless the leftItem {@link HALLink} has been resolved. + */ + @link(ITEM) + leftItem?: Observable>; + + /** + * The item on the right side of this relationship + * Will be undefined unless the rightItem {@link HALLink} has been resolved. + */ + @link(ITEM) + rightItem?: Observable>; + + /** + * The RelationshipType for this Relationship + * Will be undefined unless the relationshipType {@link HALLink} has been resolved. + */ + @link(RELATIONSHIP_TYPE) + relationshipType?: Observable>; + } diff --git a/src/app/core/shared/item-relationships/relationship.resource-type.ts b/src/app/core/shared/item-relationships/relationship.resource-type.ts new file mode 100644 index 0000000000..f65f218d70 --- /dev/null +++ b/src/app/core/shared/item-relationships/relationship.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../resource-type'; + +/** + * The resource type for Relationship. + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const RELATIONSHIP = new ResourceType('relationship'); diff --git a/src/app/core/shared/item.model.spec.ts b/src/app/core/shared/item.model.spec.ts index 1cffcf568a..9a4e11e6fd 100644 --- a/src/app/core/shared/item.model.spec.ts +++ b/src/app/core/shared/item.model.spec.ts @@ -1,10 +1,6 @@ -import { Observable, of as observableOf } from 'rxjs'; +import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; import { Item } from './item.model'; -import { Bitstream } from './bitstream.model'; -import { isEmpty } from '../../shared/empty.util'; -import { first, map } from 'rxjs/operators'; -import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; describe('Item', () => { @@ -55,50 +51,4 @@ describe('Item', () => { item = Object.assign(new Item(), { bundles: remoteDataBundles }); }); - - it('should return the bitstreams related to this item with the specified bundle name', () => { - const bitObs: Observable = item.getBitstreamsByBundleName(thumbnailBundleName); - bitObs.pipe(first()).subscribe((bs) => - expect(bs.every((b) => b.name === thumbnailBundleName)).toBeTruthy()); - }); - - it('should return an empty array when no bitstreams with this bundleName exist for this item', () => { - const bs: Observable = item.getBitstreamsByBundleName(nonExistingBundleName); - bs.pipe(first()).subscribe((b) => expect(isEmpty(b)).toBeTruthy()); - }); - - describe('get thumbnail', () => { - beforeEach(() => { - spyOn(item, 'getBitstreamsByBundleName').and.returnValue(observableOf([remoteDataThumbnail])); - }); - - it('should return the thumbnail of this item', () => { - const path: string = thumbnailPath; - const bitstream: Observable = item.getThumbnail(); - bitstream.pipe(map((b) => expect(b.content).toBe(path))); - }); - }); - - describe('get files', () => { - beforeEach(() => { - spyOn(item, 'getBitstreamsByBundleName').and.returnValue(observableOf(bitstreams)); - }); - - it("should return all bitstreams with 'ORIGINAL' as bundleName", () => { - const paths = [bitstream1Path, bitstream2Path]; - - const files: Observable = item.getFiles(); - let index = 0; - files.pipe(map((f) => expect(f.length).toBe(2))); - files.subscribe( - (array) => array.forEach( - (file) => { - expect(file.content).toBe(paths[index]); - index++; - } - ) - ) - }); - - }); }); diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index bd304274ab..3fd35280da 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -1,122 +1,94 @@ -import { map, startWith, filter, switchMap } from 'rxjs/operators'; -import { Observable } from 'rxjs'; +import { autoserialize, autoserializeAs, deserialize, inheritSerialization } from 'cerialize'; +import { Observable } from 'rxjs/internal/Observable'; +import { isEmpty } from '../../shared/empty.util'; +import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { link, typedObject } from '../cache/builders/build-decorators'; +import { PaginatedList } from '../data/paginated-list'; +import { RemoteData } from '../data/remote-data'; +import { Bundle } from './bundle.model'; +import { BUNDLE } from './bundle.resource-type'; +import { Collection } from './collection.model'; +import { COLLECTION } from './collection.resource-type'; import { DSpaceObject } from './dspace-object.model'; -import { Collection } from './collection.model'; -import { RemoteData } from '../data/remote-data'; -import { Bitstream } from './bitstream.model'; -import { hasValueOperator, isNotEmpty, isEmpty } from '../../shared/empty.util'; -import { PaginatedList } from '../data/paginated-list'; -import { Relationship } from './item-relationships/relationship.model'; -import { ResourceType } from './resource-type'; -import { getAllSucceededRemoteData, getSucceededRemoteData } from './operators'; -import { Bundle } from './bundle.model'; import { GenericConstructor } from './generic-constructor'; -import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; -import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator'; +import { HALLink } from './hal-link.model'; +import { Relationship } from './item-relationships/relationship.model'; +import { RELATIONSHIP } from './item-relationships/relationship.resource-type'; +import { ITEM } from './item.resource-type'; /** * Class representing a DSpace Item */ +@typedObject +@inheritSerialization(DSpaceObject) export class Item extends DSpaceObject { - static type = new ResourceType('item'); + static type = ITEM; /** * A string representing the unique handle of this Item */ + @autoserialize handle: string; /** * The Date of the last modification of this Item */ + @deserialize lastModified: Date; /** * A boolean representing if this Item is currently archived or not */ + @autoserializeAs(Boolean, 'inArchive') isArchived: boolean; /** * A boolean representing if this Item is currently discoverable or not */ + @autoserializeAs(Boolean, 'discoverable') isDiscoverable: boolean; /** * A boolean representing if this Item is currently withdrawn or not */ + @autoserializeAs(Boolean, 'withdrawn') isWithdrawn: boolean; /** - * An array of Collections that are direct parents of this Item + * The {@link HALLink}s for this Item */ - parents: Observable>; + @deserialize + _links: { + mappedCollections: HALLink; + relationships: HALLink; + bundles: HALLink; + owningCollection: HALLink; + templateItemOf: HALLink; + self: HALLink; + }; /** - * The Collection that owns this Item + * The owning Collection for this Item + * Will be undefined unless the owningCollection {@link HALLink} has been resolved. */ - owningCollection: Observable>; - - get owner(): Observable> { - return this.owningCollection; - } + @link(COLLECTION) + owningCollection?: Observable>; /** - * Bitstream bundles within this item + * The list of Bundles inside this Item + * Will be undefined unless the bundles {@link HALLink} has been resolved. */ - bundles: Observable>>; - - relationships: Observable>>; + @link(BUNDLE, true) + bundles?: Observable>>; /** - * Retrieves the thumbnail of this item - * @returns {Observable} the primaryBitstream of the 'THUMBNAIL' bundle + * The list of Relationships this Item has with others + * Will be undefined unless the relationships {@link HALLink} has been resolved. */ - getThumbnail(): Observable { - // TODO: currently this just picks the first thumbnail - // should be adjusted when we have a way to determine - // the primary thumbnail from rest - return this.getBitstreamsByBundleName('THUMBNAIL').pipe( - filter((thumbnails) => isNotEmpty(thumbnails)), - map((thumbnails) => thumbnails[0]),) - } - - /** - * Retrieves the thumbnail for the given original of this item - * @returns {Observable} the primaryBitstream of the 'THUMBNAIL' bundle - */ - getThumbnailForOriginal(original: Bitstream): Observable { - return this.getBitstreamsByBundleName('THUMBNAIL').pipe( - map((files) => { - return files.find((thumbnail) => thumbnail.name.startsWith(original.name)) - }),startWith(undefined),); - } - - /** - * Retrieves all files that should be displayed on the item page of this item - * @returns {Observable>>} an array of all Bitstreams in the 'ORIGINAL' bundle - */ - getFiles(): Observable { - return this.getBitstreamsByBundleName('ORIGINAL'); - } - - /** - * Retrieves bitstreams by bundle name - * @param bundleName The name of the Bundle that should be returned - * @returns {Observable} the bitstreams with the given bundleName - * TODO now that bitstreams can be paginated this should move to the server - * see https://github.com/DSpace/dspace-angular/issues/332 - */ - getBitstreamsByBundleName(bundleName: string): Observable { - return this.bundles.pipe( - getSucceededRemoteData(), - map((rd: RemoteData>) => rd.payload.page.find((bundle: Bundle) => bundle.name === bundleName)), - hasValueOperator(), - switchMap((bundle: Bundle) => bundle.bitstreams), - getAllSucceededRemoteData(), - map((rd: RemoteData>) => rd.payload.page), - startWith([]) - ); - } + @link(RELATIONSHIP, true) + relationships?: Observable>>; /** * Method that returns as which type of object this object should be rendered diff --git a/src/app/core/shared/item.resource-type.ts b/src/app/core/shared/item.resource-type.ts new file mode 100644 index 0000000000..8371f6b9b5 --- /dev/null +++ b/src/app/core/shared/item.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Item. + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const ITEM = new ResourceType('item'); diff --git a/src/app/core/shared/license.model.ts b/src/app/core/shared/license.model.ts index fa49e1f430..2b2477c1f8 100644 --- a/src/app/core/shared/license.model.ts +++ b/src/app/core/shared/license.model.ts @@ -1,16 +1,22 @@ +import { autoserialize, inheritSerialization } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; import { DSpaceObject } from './dspace-object.model'; -import { ResourceType } from './resource-type'; +import { LICENSE } from './license.resource-type'; +@typedObject +@inheritSerialization(DSpaceObject) export class License extends DSpaceObject { - static type = new ResourceType('license'); + static type = LICENSE; /** * Is the license custom? */ + @autoserialize custom: boolean; /** * The text of the license */ + @autoserialize text: string; } diff --git a/src/app/core/shared/license.resource-type.ts b/src/app/core/shared/license.resource-type.ts new file mode 100644 index 0000000000..0e53525ac5 --- /dev/null +++ b/src/app/core/shared/license.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for License + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const LICENSE = new ResourceType('license'); diff --git a/src/app/core/shared/normalized-browse-entry.model.ts b/src/app/core/shared/normalized-browse-entry.model.ts deleted file mode 100644 index 949758cb67..0000000000 --- a/src/app/core/shared/normalized-browse-entry.model.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; -import { BrowseEntry } from './browse-entry.model'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; -import { mapsTo } from '../cache/builders/build-decorators'; - -/** - * Class object representing a browse entry - * This class is not normalized because browse entries do not have self links - */ -@mapsTo(BrowseEntry) -@inheritSerialization(NormalizedObject) -export class NormalizedBrowseEntry extends NormalizedObject { - /** - * The authority string of this browse entry - */ - @autoserialize - authority: string; - - /** - * The value of this browse entry - */ - @autoserialize - value: string; - - /** - * The language of the value of this browse entry - */ - @autoserializeAs('valueLang') - language: string; - - /** - * The count of this browse entry - */ - @autoserialize - count: number; -} diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 308e4f8a2d..14d101a448 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -1,16 +1,16 @@ +import { Router } from '@angular/router'; import { Observable } from 'rxjs'; -import { filter, find, flatMap, map, take, tap } from 'rxjs/operators'; +import { filter, find, flatMap, map, tap } from 'rxjs/operators'; import { hasValue, hasValueOperator, isNotEmpty } from '../../shared/empty.util'; +import { SearchResult } from '../../shared/search/search-result.model'; import { DSOSuccessResponse, RestResponse } from '../cache/response.models'; +import { PaginatedList } from '../data/paginated-list'; import { RemoteData } from '../data/remote-data'; import { RestRequest } from '../data/request.models'; import { RequestEntry } from '../data/request.reducer'; import { RequestService } from '../data/request.service'; import { BrowseDefinition } from './browse-definition.model'; import { DSpaceObject } from './dspace-object.model'; -import { PaginatedList } from '../data/paginated-list'; -import { SearchResult } from '../../shared/search/search-result.model'; -import { Router } from '@angular/router'; /** * This file contains custom RxJS operators that can be used in multiple places @@ -59,10 +59,92 @@ export const getRemoteDataPayload = () => (source: Observable>): Observable => source.pipe(map((remoteData: RemoteData) => remoteData.payload)); +export const getPaginatedListPayload = () => + (source: Observable>): Observable => + source.pipe(map((list: PaginatedList) => list.page)); + export const getSucceededRemoteData = () => (source: Observable>): Observable> => source.pipe(find((rd: RemoteData) => rd.hasSucceeded)); +/** + * Get the first successful remotely retrieved object + * + * You usually don't want to use this, it is a code smell. + * Work with the RemoteData object instead, that way you can + * handle loading and errors correctly. + * + * These operators were created as a first step in refactoring + * out all the instances where this is used incorrectly. + */ +export const getFirstSucceededRemoteDataPayload = () => + (source: Observable>): Observable => + source.pipe( + getSucceededRemoteData(), + getRemoteDataPayload() + ); + +/** + * Get the all successful remotely retrieved objects + * + * You usually don't want to use this, it is a code smell. + * Work with the RemoteData object instead, that way you can + * handle loading and errors correctly. + * + * These operators were created as a first step in refactoring + * out all the instances where this is used incorrectly. + */ +export const getAllSucceededRemoteDataPayload = () => + (source: Observable>): Observable => + source.pipe( + getAllSucceededRemoteData(), + getRemoteDataPayload() + ); + +/** + * Get the first successful remotely retrieved paginated list + * as an array + * + * You usually don't want to use this, it is a code smell. + * Work with the RemoteData object instead, that way you can + * handle loading and errors correctly. + * + * You also don't want to ignore pagination and simply use the + * page as an array. + * + * These operators were created as a first step in refactoring + * out all the instances where this is used incorrectly. + */ +export const getFirstSucceededRemoteListPayload = () => + (source: Observable>>): Observable => + source.pipe( + getSucceededRemoteData(), + getRemoteDataPayload(), + getPaginatedListPayload() + ); + +/** + * Get all successful remotely retrieved paginated lists + * as arrays + * + * You usually don't want to use this, it is a code smell. + * Work with the RemoteData object instead, that way you can + * handle loading and errors correctly. + * + * You also don't want to ignore pagination and simply use the + * page as an array. + * + * These operators were created as a first step in refactoring + * out all the instances where this is used incorrectly. + */ +export const getAllSucceededRemoteListPayload = () => + (source: Observable>>): Observable => + source.pipe( + getAllSucceededRemoteData(), + getRemoteDataPayload(), + getPaginatedListPayload() + ); + /** * Operator that checks if a remote data object contains a page not found error * When it does contain such an error, it will redirect the user to a page not found, without altering the current URL diff --git a/src/app/core/shared/page-info.model.ts b/src/app/core/shared/page-info.model.ts index 273510da60..ccb0aae471 100644 --- a/src/app/core/shared/page-info.model.ts +++ b/src/app/core/shared/page-info.model.ts @@ -1,10 +1,12 @@ -import { autoserialize, autoserializeAs } from 'cerialize'; +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; import { hasValue } from '../../shared/empty.util'; +import { HALLink } from './hal-link.model'; +import { HALResource } from './hal-resource.model'; /** * Represents the state of a paginated response */ -export class PageInfo { +export class PageInfo implements HALResource { /** * The number of elements on a page @@ -30,20 +32,17 @@ export class PageInfo { @autoserializeAs(Number, 'number') currentPage: number; - @autoserialize - last: string; - - @autoserialize - next: string; - - @autoserialize - prev: string; - - @autoserialize - first: string; - - @autoserialize - self: string; + /** + * The {@link HALLink}s for this PageInfo + */ + @deserialize + _links: { + first: HALLink; + prev: HALLink; + next: HALLink; + last: HALLink; + self: HALLink; + }; constructor( options?: { @@ -60,4 +59,41 @@ export class PageInfo { this.currentPage = options.currentPage; } } + + get self() { + return this._links.self.href; + } + + get last(): string { + if (hasValue(this._links) && hasValue(this._links.last)) { + return this._links.last.href; + } else { + return undefined; + } + } + + get next(): string { + if (hasValue(this._links) && hasValue(this._links.next)) { + return this._links.next.href; + } else { + return undefined; + } + } + + get prev(): string { + if (hasValue(this._links) && hasValue(this._links.prev)) { + return this._links.prev.href; + } else { + return undefined; + } + } + + get first(): string { + if (hasValue(this._links) && hasValue(this._links.first)) { + return this._links.first.href; + } else { + return undefined; + } + } + } diff --git a/src/app/core/shared/resource-policy.model.ts b/src/app/core/shared/resource-policy.model.ts index a80446a369..dd00a16e97 100644 --- a/src/app/core/shared/resource-policy.model.ts +++ b/src/app/core/shared/resource-policy.model.ts @@ -1,36 +1,58 @@ -import { CacheableObject } from '../cache/object-cache.reducer'; -import { ResourceType } from './resource-type'; +import { autoserialize, deserialize, deserializeAs } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../cache/id-to-uuid-serializer'; import { ActionType } from '../cache/models/action-type.model'; +import { CacheableObject } from '../cache/object-cache.reducer'; +import { excludeFromEquals } from '../utilities/equals.decorators'; +import { HALLink } from './hal-link.model'; +import { RESOURCE_POLICY } from './resource-policy.resource-type'; +import { ResourceType } from './resource-type'; /** * Model class for a Resource Policy */ +@typedObject export class ResourcePolicy implements CacheableObject { - static type = new ResourceType('resourcePolicy'); + static type = RESOURCE_POLICY; + + /** + * The object type + */ + @excludeFromEquals + @autoserialize + type: ResourceType; /** * The action that is allowed by this Resource Policy */ + @autoserialize action: ActionType; /** * The name for this Resource Policy */ + @autoserialize name: string; /** * The uuid of the Group this Resource Policy applies to */ + @autoserialize groupUUID: string; - /** - * The link to the rest endpoint where this Resource Policy can be found - */ - self: string; - /** * The universally unique identifier for this Resource Policy + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. */ + @deserializeAs(new IDToUUIDSerializer('resource-policy'), 'id') uuid: string; + /** + * The {@link HALLink}s for this ResourcePolicy + */ + @deserialize + _links: { + self: HALLink, + } } diff --git a/src/app/core/shared/resource-policy.resource-type.ts b/src/app/core/shared/resource-policy.resource-type.ts new file mode 100644 index 0000000000..1811a3a0d1 --- /dev/null +++ b/src/app/core/shared/resource-policy.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for ResourcePolicy + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const RESOURCE_POLICY = new ResourceType('resourcePolicy'); diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts index 141f261990..1a016e64f8 100644 --- a/src/app/core/shared/search/search.service.ts +++ b/src/app/core/shared/search/search.service.ts @@ -2,6 +2,8 @@ import { combineLatest as observableCombineLatest, Observable, of as observableO import { Injectable, OnDestroy } from '@angular/core'; import { NavigationExtras, Router } from '@angular/router'; import { first, map, switchMap, tap } from 'rxjs/operators'; +import { followLink } from '../../../shared/utils/follow-link-config.model'; +import { LinkService } from '../../cache/builders/link.service'; import { FacetConfigSuccessResponse, FacetValueSuccessResponse, SearchSuccessResponse } from '../../cache/response.models'; import { PaginatedList } from '../../data/paginated-list'; import { ResponseParsingService } from '../../data/parsing.service'; @@ -13,7 +15,6 @@ import { GenericConstructor } from '../generic-constructor'; import { HALEndpointService } from '../hal-endpoint.service'; import { URLCombiner } from '../../url-combiner/url-combiner'; import { hasValue, isEmpty, isNotEmpty, isNotUndefined } from '../../../shared/empty.util'; -import { NormalizedSearchResult } from '../../../shared/search/normalized-search-result.model'; import { SearchOptions } from '../../../shared/search/search-options.model'; import { SearchResult } from '../../../shared/search/search-result.model'; import { FacetValue } from '../../../shared/search/facet-value.model'; @@ -69,6 +70,7 @@ export class SearchService implements OnDestroy { private routeService: RouteService, protected requestService: RequestService, private rdb: RemoteDataBuildService, + private linkService: LinkService, private halService: HALEndpointService, private communityService: CommunityDataService, private dspaceObjectService: DSpaceObjectDataService @@ -167,8 +169,8 @@ export class SearchService implements OnDestroy { const dsoObs: Observable> = sqrObs.pipe( map((sqr: SearchQueryResponse) => { return sqr.objects - .filter((nsr: NormalizedSearchResult) => isNotUndefined(nsr.indexableObject)) - .map((nsr: NormalizedSearchResult) => new GetRequest(this.requestService.generateRequestId(), nsr.indexableObject)) + .filter((sr: SearchResult) => isNotUndefined(sr._links.indexableObject)) + .map((sr: SearchResult) => new GetRequest(this.requestService.generateRequestId(), sr._links.indexableObject.href)) }), // Send a request for each item to ensure fresh cache tap((reqs: RestRequest[]) => reqs.forEach((req: RestRequest) => this.requestService.configure(req))), @@ -179,7 +181,7 @@ export class SearchService implements OnDestroy { // Create search results again with the correct dso objects linked to each result const tDomainListObs = observableCombineLatest(sqrObs, dsoObs).pipe( map(([sqr, dsos]) => { - return sqr.objects.map((object: NormalizedSearchResult, index: number) => { + return sqr.objects.map((object: SearchResult, index: number) => { let co = DSpaceObject; if (dsos.payload[index]) { const constructor: GenericConstructor = dsos.payload[index].constructor as GenericConstructor; @@ -340,6 +342,7 @@ export class SearchService implements OnDestroy { switchMap((dsoRD: RemoteData) => { if ((dsoRD.payload as any).type === Community.type.value) { const community: Community = dsoRD.payload as Community; + this.linkService.resolveLinks(community, followLink('subcommunities'), followLink('collections')); return observableCombineLatest(community.subcommunities, community.collections).pipe( map(([subCommunities, collections]) => { /*if this is a community, we also need to show the direct children*/ diff --git a/src/app/core/shared/site.model.ts b/src/app/core/shared/site.model.ts index a191b2143f..befd4c1ae3 100644 --- a/src/app/core/shared/site.model.ts +++ b/src/app/core/shared/site.model.ts @@ -1,11 +1,15 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../cache/builders/build-decorators'; import { DSpaceObject } from './dspace-object.model'; -import { ResourceType } from './resource-type'; +import { SITE } from './site.resource-type'; /** * Model class for the Site object */ +@typedObject +@inheritSerialization(DSpaceObject) export class Site extends DSpaceObject { ​ - static type = new ResourceType('site'); + static type = SITE; ​ } diff --git a/src/app/core/shared/site.resource-type.ts b/src/app/core/shared/site.resource-type.ts new file mode 100644 index 0000000000..570697833f --- /dev/null +++ b/src/app/core/shared/site.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from './resource-type'; + +/** + * The resource type for Site + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const SITE = new ResourceType('site'); diff --git a/src/app/core/submission/models/normalized-submission-object.model.ts b/src/app/core/submission/models/normalized-submission-object.model.ts deleted file mode 100644 index f674ebdf72..0000000000 --- a/src/app/core/submission/models/normalized-submission-object.model.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize'; - -import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; -import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model'; -import { SubmissionObjectError } from './submission-object.model'; -import { DSpaceObject } from '../../shared/dspace-object.model'; - -/** - * An abstract model class for a NormalizedSubmissionObject. - */ -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedSubmissionObject extends NormalizedDSpaceObject { - - /** - * The workspaceitem/workflowitem identifier - */ - @autoserialize - id: string; - - /** - * The workspaceitem/workflowitem identifier - */ - @autoserializeAs(String, 'id') - uuid: string; - - /** - * The workspaceitem/workflowitem last modified date - */ - @autoserialize - lastModified: Date; - - /** - * The workspaceitem/workflowitem last sections data - */ - @autoserialize - sections: WorkspaceitemSectionsObject; - - /** - * The workspaceitem/workflowitem last sections errors - */ - @autoserialize - errors: SubmissionObjectError[]; -} diff --git a/src/app/core/submission/models/normalized-workflowitem.model.ts b/src/app/core/submission/models/normalized-workflowitem.model.ts deleted file mode 100644 index e96024b4ae..0000000000 --- a/src/app/core/submission/models/normalized-workflowitem.model.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; - -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { WorkflowItem } from './workflowitem.model'; -import { NormalizedSubmissionObject } from './normalized-submission-object.model'; -import { Collection } from '../../shared/collection.model'; -import { Item } from '../../shared/item.model'; -import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model'; -import { EPerson } from '../../eperson/models/eperson.model'; - -/** - * An model class for a NormalizedWorkflowItem. - */ -@mapsTo(WorkflowItem) -@inheritSerialization(NormalizedSubmissionObject) -export class NormalizedWorkflowItem extends NormalizedSubmissionObject { - - /** - * The collection this workflowitem belonging to - */ - @autoserialize - @relationship(Collection, false) - collection: string; - - /** - * The item created with this workflowitem - */ - @autoserialize - @relationship(Item, false) - item: string; - - /** - * The configuration object that define this workflowitem - */ - @autoserialize - @relationship(SubmissionDefinitionsModel, false) - submissionDefinition: string; - - /** - * The EPerson who submit this workflowitem - */ - @autoserialize - @relationship(EPerson, false) - submitter: string; - -} diff --git a/src/app/core/submission/models/normalized-workspaceitem.model.ts b/src/app/core/submission/models/normalized-workspaceitem.model.ts deleted file mode 100644 index 4275420191..0000000000 --- a/src/app/core/submission/models/normalized-workspaceitem.model.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; - -import { WorkspaceItem } from './workspaceitem.model'; -import { NormalizedSubmissionObject } from './normalized-submission-object.model'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; -import { Item } from '../../shared/item.model'; -import { Collection } from '../../shared/collection.model'; -import { SubmissionDefinitionModel } from '../../config/models/config-submission-definition.model'; -import { EPerson } from '../../eperson/models/eperson.model'; - -/** - * An model class for a NormalizedWorkspaceItem. - */ -@mapsTo(WorkspaceItem) -@inheritSerialization(NormalizedDSpaceObject) -@inheritSerialization(NormalizedSubmissionObject) -export class NormalizedWorkspaceItem extends NormalizedSubmissionObject { - - /** - * The collection this workspaceitem belonging to - */ - @autoserialize - @relationship(Collection, false) - collection: string; - - /** - * The item created with this workspaceitem - */ - @autoserialize - @relationship(Item, false) - item: string; - - /** - * The configuration object that define this workspaceitem - */ - @autoserialize - @relationship(SubmissionDefinitionModel, false) - submissionDefinition: string; - - /** - * The EPerson who submit this workspaceitem - */ - @autoserialize - @relationship(EPerson, false) - submitter: string; -} diff --git a/src/app/core/submission/models/submission-object.model.ts b/src/app/core/submission/models/submission-object.model.ts index 0b1110fa24..87ea19653d 100644 --- a/src/app/core/submission/models/submission-object.model.ts +++ b/src/app/core/submission/models/submission-object.model.ts @@ -1,12 +1,19 @@ +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; +import { link } from '../../cache/builders/build-decorators'; import { CacheableObject } from '../../cache/object-cache.reducer'; -import { DSpaceObject } from '../../shared/dspace-object.model'; -import { EPerson } from '../../eperson/models/eperson.model'; -import { RemoteData } from '../../data/remote-data'; -import { Collection } from '../../shared/collection.model'; -import { Item } from '../../shared/item.model'; import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model'; +import { RemoteData } from '../../data/remote-data'; +import { EPerson } from '../../eperson/models/eperson.model'; +import { EPERSON } from '../../eperson/models/eperson.resource-type'; +import { Collection } from '../../shared/collection.model'; +import { COLLECTION } from '../../shared/collection.resource-type'; +import { DSpaceObject } from '../../shared/dspace-object.model'; +import { HALLink } from '../../shared/hal-link.model'; +import { Item } from '../../shared/item.model'; +import { ITEM } from '../../shared/item.resource-type'; +import { excludeFromEquals } from '../../utilities/equals.decorators'; import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model'; export interface SubmissionObjectError { @@ -17,50 +24,72 @@ export interface SubmissionObjectError { /** * An abstract model class for a SubmissionObject. */ +@inheritSerialization(DSpaceObject) export abstract class SubmissionObject extends DSpaceObject implements CacheableObject { - /** - * The workspaceitem/workflowitem identifier - */ + @excludeFromEquals + @autoserialize id: string; /** - * The workspaceitem/workflowitem identifier - */ - uuid: string; - - /** - * The workspaceitem/workflowitem last modified date + * The SubmissionObject last modified date */ + @autoserialize lastModified: Date; /** * The collection this submission applies to + * Will be undefined unless the collection {@link HALLink} has been resolved. */ - collection: Observable> | Collection; + @link(COLLECTION) + collection?: Observable> | Collection; /** - * The submission item - */ - item: Observable> | Item; - - /** - * The workspaceitem/workflowitem last sections data + * The SubmissionObject's last section's data */ + @autoserialize sections: WorkspaceitemSectionsObject; /** - * The configuration object that define this submission - */ - submissionDefinition: Observable> | SubmissionDefinitionsModel; - - /** - * The workspaceitem submitter - */ - submitter: Observable> | EPerson; - - /** - * The workspaceitem/workflowitem last sections errors + * The SubmissionObject's last section's errors */ + @autoserialize errors: SubmissionObjectError[]; + + /** + * The {@link HALLink}s for this SubmissionObject + */ + @deserialize + _links: { + self: HALLink; + collection: HALLink; + item: HALLink; + submissionDefinition: HALLink; + submitter: HALLink; + }; + + get self(): string { + return this._links.self.href; + } + + /** + * The submission item + * Will be undefined unless the item {@link HALLink} has been resolved. + */ + @link(ITEM) + item?: Observable> | Item; + /** + * The configuration object that define this submission + * Will be undefined unless the submissionDefinition {@link HALLink} has been resolved. + */ + @link(SubmissionDefinitionsModel.type) + submissionDefinition?: Observable> | SubmissionDefinitionsModel; + + /** + * The submitter for this SubmissionObject + * Will be undefined unless the submitter {@link HALLink} has been resolved. + */ + @link(EPERSON) + submitter?: Observable> | EPerson; + } diff --git a/src/app/core/submission/models/workflowitem.model.ts b/src/app/core/submission/models/workflowitem.model.ts index 4cfc4d7fa1..b8054a66d0 100644 --- a/src/app/core/submission/models/workflowitem.model.ts +++ b/src/app/core/submission/models/workflowitem.model.ts @@ -1,9 +1,23 @@ -import { WorkspaceItem } from './workspaceitem.model'; -import { ResourceType } from '../../shared/resource-type'; +import { deserializeAs, inheritSerialization } from 'cerialize'; +import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; +import { WORKFLOWITEM } from '../../eperson/models/workflowitem.resource-type'; +import { SubmissionObject } from './submission-object.model'; /** * A model class for a WorkflowItem. */ -export class WorkflowItem extends WorkspaceItem { - static type = new ResourceType('workflowitem'); +@typedObject +@inheritSerialization(SubmissionObject) +@inheritLinkAnnotations(SubmissionObject) +export class WorkflowItem extends SubmissionObject { + static type = WORKFLOWITEM; + + /** + * The universally unique identifier of this WorkflowItem + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. + */ + @deserializeAs(new IDToUUIDSerializer(WorkflowItem.type.value), 'id') + uuid: string; } diff --git a/src/app/core/submission/models/workspaceitem.model.ts b/src/app/core/submission/models/workspaceitem.model.ts index c4bb5b7520..b29d8c0efa 100644 --- a/src/app/core/submission/models/workspaceitem.model.ts +++ b/src/app/core/submission/models/workspaceitem.model.ts @@ -1,10 +1,24 @@ +import { deserializeAs, inheritSerialization } from 'cerialize'; +import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators'; +import { IDToUUIDSerializer } from '../../cache/id-to-uuid-serializer'; +import { DSpaceObject } from '../../shared/dspace-object.model'; import { SubmissionObject } from './submission-object.model'; import { ResourceType } from '../../shared/resource-type'; /** * A model class for a WorkspaceItem. */ +@typedObject +@inheritSerialization(SubmissionObject) +@inheritLinkAnnotations(SubmissionObject) export class WorkspaceItem extends SubmissionObject { static type = new ResourceType('workspaceitem'); + /** + * The universally unique identifier of this WorkspaceItem + * This UUID is generated client-side and isn't used by the backend. + * It is based on the ID, so it will be the same for each refresh. + */ + @deserializeAs(new IDToUUIDSerializer(WorkspaceItem.type.value), 'id') + uuid: string; } diff --git a/src/app/core/submission/submission-object-data.service.spec.ts b/src/app/core/submission/submission-object-data.service.spec.ts index b7c06272e6..f46a465edb 100644 --- a/src/app/core/submission/submission-object-data.service.spec.ts +++ b/src/app/core/submission/submission-object-data.service.spec.ts @@ -45,7 +45,7 @@ describe('SubmissionObjectDataService', () => { service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService); }); - it('should forward the result of WorkspaceitemDataService.findById()', () => { + it('should forward the result of WorkspaceitemDataService.findByIdAndIDType()', () => { const result = service.findById(submissionId); expect(workspaceitemDataService.findById).toHaveBeenCalledWith(submissionId); expect(result).toBe(wsiResult); @@ -60,7 +60,7 @@ describe('SubmissionObjectDataService', () => { service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService); }); - it('should forward the result of WorkflowItemDataService.findById()', () => { + it('should forward the result of WorkflowItemDataService.findByIdAndIDType()', () => { const result = service.findById(submissionId); expect(workflowItemDataService.findById).toHaveBeenCalledWith(submissionId); expect(result).toBe(wfiResult); diff --git a/src/app/core/submission/submission-object-data.service.ts b/src/app/core/submission/submission-object-data.service.ts index 15ede18cb8..0b6d65c758 100644 --- a/src/app/core/submission/submission-object-data.service.ts +++ b/src/app/core/submission/submission-object-data.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { of as observableOf, Observable } from 'rxjs'; +import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { SubmissionService } from '../../submission/submission.service'; import { RemoteData } from '../data/remote-data'; import { RemoteDataError } from '../data/remote-data-error'; @@ -27,13 +28,14 @@ export class SubmissionObjectDataService { * Retrieve a submission object based on its ID. * * @param id The identifier of a submission object + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved */ - findById(id: string): Observable> { + findById(id: string, ...linksToFollow: Array>): Observable> { switch (this.submissionService.getSubmissionScope()) { case SubmissionScopeType.WorkspaceItem: - return this.workspaceitemDataService.findById(id); + return this.workspaceitemDataService.findById(id,...linksToFollow); case SubmissionScopeType.WorkflowItem: - return this.workflowItemDataService.findById(id); + return this.workflowItemDataService.findById(id,...linksToFollow); default: const error = new RemoteDataError( undefined, diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts index 8bc2971922..27a7e43c46 100644 --- a/src/app/core/submission/submission-response-parsing.service.ts +++ b/src/app/core/submission/submission-response-parsing.service.ts @@ -12,10 +12,10 @@ import { BaseResponseParsingService } from '../data/base-response-parsing.servic import { GLOBAL_CONFIG } from '../../../config'; import { GlobalConfig } from '../../../config/global-config.interface'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { NormalizedWorkspaceItem } from './models/normalized-workspaceitem.model'; -import { NormalizedWorkflowItem } from './models/normalized-workflowitem.model'; import { FormFieldMetadataValueObject } from '../../shared/form/builder/models/form-field-metadata-value.model'; import { SubmissionObject } from './models/submission-object.model'; +import { WorkflowItem } from './models/workflowitem.model'; +import { WorkspaceItem } from './models/workspaceitem.model'; /** * Export a function to check if object has same properties of FormFieldMetadataValueObject @@ -77,6 +77,18 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService protected toCache = false; + /** + * The submission assumes certain related HALResources will always be embedded. + * It only works if the responseparser finds these embedded resources, and directly + * attaches them to the requested object, instead of putting them in the cache and + * treating them as separate objects. This boolean was added to allow us to disable + * that behavior for the rest of the application, while keeping it for the submission. + * + * It should be removed after the submission has been refactored to treat embeds as + * resources that may need to be retrieved separately. + */ + protected shouldDirectlyAttachEmbeds = true; + constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected objectCache: ObjectCacheService, protected dsoParser: DSOResponseParsingService @@ -119,15 +131,15 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService */ protected processResponse(data: any, request: RestRequest): any[] { const dataDefinition = this.process(data, request); - const normalizedDefinition = Array.of(); + const definition = Array.of(); const processedList = Array.isArray(dataDefinition) ? dataDefinition : Array.of(dataDefinition); processedList.forEach((item) => { - let normalizedItem = Object.assign({}, item); - // In case data is an Instance of NormalizedWorkspaceItem normalize field value of all the section of type form - if (item instanceof NormalizedWorkspaceItem - || item instanceof NormalizedWorkflowItem) { + item = Object.assign({}, item); + // In case data is an Instance of WorkspaceItem normalize field value of all the section of type form + if (item instanceof WorkspaceItem + || item instanceof WorkflowItem) { if (item.sections) { const precessedSection = Object.create({}); // Iterate over all workspaceitem's sections @@ -137,35 +149,35 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService // When Upload section is disabled, add to submission only if there are files (!item.sections[sectionId].hasOwnProperty('files') || isNotEmpty((item.sections[sectionId] as any).files)))) { - const normalizedSectionData = Object.create({}); + const sectiondata = Object.create({}); // Iterate over all sections property Object.keys(item.sections[sectionId]) .forEach((metdadataId) => { const entry = item.sections[sectionId][metdadataId]; // If entry is not an array, for sure is not a section of type form if (Array.isArray(entry)) { - normalizedSectionData[metdadataId] = []; + sectiondata[metdadataId] = []; entry.forEach((valueItem, index) => { // Parse value and normalize it const normValue = normalizeSectionData(valueItem, index); if (isNotEmpty(normValue)) { - normalizedSectionData[metdadataId].push(normValue); + sectiondata[metdadataId].push(normValue); } }); } else { - normalizedSectionData[metdadataId] = entry; + sectiondata[metdadataId] = entry; } }); - precessedSection[sectionId] = normalizedSectionData; + precessedSection[sectionId] = sectiondata; } }); - normalizedItem = Object.assign({}, item, { sections: precessedSection }); + item = Object.assign({}, item, { sections: precessedSection }); } } - normalizedDefinition.push(normalizedItem); + definition.push(item); }); - return normalizedDefinition; + return definition; } } diff --git a/src/app/core/submission/submission-rest.service.spec.ts b/src/app/core/submission/submission-rest.service.spec.ts index eefc815435..68d7ff13f4 100644 --- a/src/app/core/submission/submission-rest.service.spec.ts +++ b/src/app/core/submission/submission-rest.service.spec.ts @@ -26,7 +26,7 @@ describe('SubmissionRestService test suite', () => { const resourceEndpoint = 'workspaceitems'; const resourceScope = '260'; const body = { test: new FormFieldMetadataValueObject('test')}; - const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope; + const resourceHref = resourceEndpointURL + '/' + resourceEndpoint + '/' + resourceScope + '?projection=full'; const timestampResponse = 1545994811992; function initTestService() { diff --git a/src/app/core/submission/submission-rest.service.ts b/src/app/core/submission/submission-rest.service.ts index 32ba070002..350874bc50 100644 --- a/src/app/core/submission/submission-rest.service.ts +++ b/src/app/core/submission/submission-rest.service.ts @@ -71,8 +71,9 @@ export class SubmissionRestService { */ protected getEndpointByIDHref(endpoint, resourceID, collectionId?: string): string { let url = isNotEmpty(resourceID) ? `${endpoint}/${resourceID}` : `${endpoint}`; + url = new URLCombiner(url, '?projection=full').toString(); if (collectionId) { - url = new URLCombiner(url, `?owningCollection=${collectionId}`).toString(); + url = new URLCombiner(url, `&owningCollection=${collectionId}`).toString(); } return url; } diff --git a/src/app/core/submission/workflowitem-data.service.ts b/src/app/core/submission/workflowitem-data.service.ts index 47195ed0a1..a2dfca5eb3 100644 --- a/src/app/core/submission/workflowitem-data.service.ts +++ b/src/app/core/submission/workflowitem-data.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; +import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { CoreState } from '../core.reducers'; import { DataService } from '../data/data.service'; @@ -9,7 +10,6 @@ import { RequestService } from '../data/request.service'; import { WorkflowItem } from './models/workflowitem.model'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { FindListOptions } from '../data/request.models'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; @@ -18,13 +18,13 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; * A service that provides methods to make REST requests with workflowitems endpoint. */ @Injectable() +@dataService(WorkflowItem.type) export class WorkflowItemDataService extends DataService { protected linkPath = 'workflowitems'; protected responseMsToLive = 10 * 1000; constructor( protected comparator: DSOChangeAnalyzer, - protected dataBuildService: NormalizedObjectBuildService, protected halService: HALEndpointService, protected http: HttpClient, protected notificationsService: NotificationsService, @@ -35,8 +35,4 @@ export class WorkflowItemDataService extends DataService { super(); } - public getBrowseEndpoint(options: FindListOptions) { - return this.halService.getEndpoint(this.linkPath); - } - } diff --git a/src/app/core/submission/workspaceitem-data.service.ts b/src/app/core/submission/workspaceitem-data.service.ts index 3f782b74a2..fcb85cc8b4 100644 --- a/src/app/core/submission/workspaceitem-data.service.ts +++ b/src/app/core/submission/workspaceitem-data.service.ts @@ -2,13 +2,13 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Store } from '@ngrx/store'; +import { dataService } from '../cache/builders/build-decorators'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; import { CoreState } from '../core.reducers'; import { DataService } from '../data/data.service'; import { RequestService } from '../data/request.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { FindListOptions } from '../data/request.models'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { ObjectCacheService } from '../cache/object-cache.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; @@ -18,13 +18,13 @@ import { WorkspaceItem } from './models/workspaceitem.model'; * A service that provides methods to make REST requests with workspaceitems endpoint. */ @Injectable() +@dataService(WorkspaceItem.type) export class WorkspaceitemDataService extends DataService { protected linkPath = 'workspaceitems'; protected responseMsToLive = 10 * 1000; constructor( protected comparator: DSOChangeAnalyzer, - protected dataBuildService: NormalizedObjectBuildService, protected halService: HALEndpointService, protected http: HttpClient, protected notificationsService: NotificationsService, @@ -35,8 +35,4 @@ export class WorkspaceitemDataService extends DataService { super(); } - public getBrowseEndpoint(options: FindListOptions) { - return this.halService.getEndpoint(this.linkPath); - } - } diff --git a/src/app/core/tasks/claimed-task-data.service.spec.ts b/src/app/core/tasks/claimed-task-data.service.spec.ts index a7be0830ec..90d449b22b 100644 --- a/src/app/core/tasks/claimed-task-data.service.spec.ts +++ b/src/app/core/tasks/claimed-task-data.service.spec.ts @@ -6,7 +6,6 @@ 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'; @@ -22,9 +21,6 @@ describe('ClaimedTaskDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = { - normalize: (object) => object - } as NormalizedObjectBuildService; const objectCache = { addPatch: () => { /* empty */ @@ -39,7 +35,6 @@ describe('ClaimedTaskDataService', () => { return new ClaimedTaskDataService( requestService, rdbService, - dataBuildService, store, objectCache, halService, diff --git a/src/app/core/tasks/claimed-task-data.service.ts b/src/app/core/tasks/claimed-task-data.service.ts index 76e5e769d7..0a9de20530 100644 --- a/src/app/core/tasks/claimed-task-data.service.ts +++ b/src/app/core/tasks/claimed-task-data.service.ts @@ -1,25 +1,26 @@ -import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; - -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { CoreState } from '../core.reducers'; -import { RequestService } from '../data/request.service'; -import { ClaimedTask } from './models/claimed-task-object.model'; -import { TasksService } from './tasks.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { RequestService } from '../data/request.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { ClaimedTask } from './models/claimed-task-object.model'; +import { CLAIMED_TASK } from './models/claimed-task-object.resource-type'; import { ProcessTaskResponse } from './models/process-task-response'; +import { TasksService } from './tasks.service'; /** * The service handling all REST requests for ClaimedTask */ @Injectable() +@dataService(CLAIMED_TASK) export class ClaimedTaskDataService extends TasksService { protected responseMsToLive = 10 * 1000; @@ -34,7 +35,7 @@ export class ClaimedTaskDataService extends TasksService { * * @param {RequestService} requestService * @param {RemoteDataBuildService} rdbService - * @param {NormalizedObjectBuildService} dataBuildService + * @param {NormalizedObjectBuildService} linkService * @param {Store} store * @param {ObjectCacheService} objectCache * @param {HALEndpointService} halService @@ -45,7 +46,6 @@ export class ClaimedTaskDataService extends TasksService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, 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 2f427f586f..9ec28bc2e0 100644 --- a/src/app/core/tasks/models/claimed-task-object.model.ts +++ b/src/app/core/tasks/models/claimed-task-object.model.ts @@ -1,9 +1,14 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { DSpaceObject } from '../../shared/dspace-object.model'; +import { CLAIMED_TASK } from './claimed-task-object.resource-type'; import { TaskObject } from './task-object.model'; -import { ResourceType } from '../../shared/resource-type'; /** * A model class for a ClaimedTask. */ +@typedObject +@inheritSerialization(DSpaceObject) export class ClaimedTask extends TaskObject { - static type = new ResourceType('claimedtask'); + static type = CLAIMED_TASK; } diff --git a/src/app/core/tasks/models/claimed-task-object.resource-type.ts b/src/app/core/tasks/models/claimed-task-object.resource-type.ts new file mode 100644 index 0000000000..9ad48fb229 --- /dev/null +++ b/src/app/core/tasks/models/claimed-task-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for ClaimedTask + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const CLAIMED_TASK = new ResourceType('claimedtask'); 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 deleted file mode 100644 index d43a277f02..0000000000 --- a/src/app/core/tasks/models/normalized-claimed-task-object.model.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { NormalizedTaskObject } from './normalized-task-object.model'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { autoserialize, inheritSerialization } from 'cerialize'; -import { ClaimedTask } from './claimed-task-object.model'; -import { EPerson } from '../../eperson/models/eperson.model'; -import { Group } from '../../eperson/models/group.model'; -import { WorkflowItem } from '../../submission/models/workflowitem.model'; - -/** - * A normalized model class for a ClaimedTask. - */ -@mapsTo(ClaimedTask) -@inheritSerialization(NormalizedTaskObject) -export class NormalizedClaimedTask extends NormalizedTaskObject { - /** - * The task identifier - */ - @autoserialize - id: string; - - /** - * The workflow step - */ - @autoserialize - step: string; - - /** - * The task action type - */ - @autoserialize - action: string; - - /** - * The eperson object for this task - */ - @autoserialize - @relationship(EPerson, false) - eperson: string; - - /** - * The group object for this task - */ - @autoserialize - @relationship(Group, false) - group: string; - - /** - * The workflowitem object whom this task is related - */ - @autoserialize - @relationship(WorkflowItem, false) - workflowitem: string; - -} 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 deleted file mode 100644 index bfc782f182..0000000000 --- a/src/app/core/tasks/models/normalized-pool-task-object.model.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NormalizedTaskObject } from './normalized-task-object.model'; -import { PoolTask } from './pool-task-object.model'; -import { autoserialize, inheritSerialization } from 'cerialize'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { Group } from '../../eperson/models/group.model'; -import { WorkflowItem } from '../../submission/models/workflowitem.model'; - -/** - * A normalized model class for a PoolTask. - */ -@mapsTo(PoolTask) -@inheritSerialization(NormalizedTaskObject) -export class NormalizedPoolTask extends NormalizedTaskObject { - /** - * The task identifier - */ - @autoserialize - id: string; - - /** - * The workflow step - */ - @autoserialize - step: string; - - /** - * The task action type - */ - @autoserialize - action: string; - - /** - * The group object for this task - */ - @autoserialize - @relationship(Group, false) - group: string; - - /** - * The workflowitem object whom this task is related - */ - @autoserialize - @relationship(WorkflowItem, false) - workflowitem: string; -} diff --git a/src/app/core/tasks/models/normalized-task-object.model.ts b/src/app/core/tasks/models/normalized-task-object.model.ts deleted file mode 100644 index 2c96b95393..0000000000 --- a/src/app/core/tasks/models/normalized-task-object.model.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { mapsTo, relationship } from '../../cache/builders/build-decorators'; -import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; -import { TaskObject } from './task-object.model'; -import { DSpaceObject } from '../../shared/dspace-object.model'; -import { Group } from '../../eperson/models/group.model'; -import { EPerson } from '../../eperson/models/eperson.model'; -import { WorkflowItem } from '../../submission/models/workflowitem.model'; - -/** - * An abstract normalized model class for a TaskObject. - */ -@mapsTo(TaskObject) -@inheritSerialization(NormalizedDSpaceObject) -export class NormalizedTaskObject extends NormalizedDSpaceObject { - - /** - * The task identifier - */ - @autoserialize - id: string; - - /** - * The workflow step - */ - @autoserialize - step: string; - - /** - * The task action type - */ - @autoserialize - action: string; - - /** - * The eperson object for this task - */ - @autoserialize - @relationship(EPerson, false) - eperson: string; - - /** - * The group object for this task - */ - @autoserialize - @relationship(Group, false) - group: string; - - /** - * The workflowitem object whom this task is related - */ - @autoserialize - @relationship(WorkflowItem, false) - workflowitem: string; -} 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 876b62373d..04fe572502 100644 --- a/src/app/core/tasks/models/pool-task-object.model.ts +++ b/src/app/core/tasks/models/pool-task-object.model.ts @@ -1,9 +1,13 @@ +import { inheritSerialization } from 'cerialize'; +import { typedObject } from '../../cache/builders/build-decorators'; +import { POOL_TASK } from './pool-task-object.resource-type'; import { TaskObject } from './task-object.model'; -import { ResourceType } from '../../shared/resource-type'; /** * A model class for a PoolTask. */ +@typedObject +@inheritSerialization(TaskObject) export class PoolTask extends TaskObject { - static type = new ResourceType('pooltask'); + static type = POOL_TASK; } diff --git a/src/app/core/tasks/models/pool-task-object.resource-type.ts b/src/app/core/tasks/models/pool-task-object.resource-type.ts new file mode 100644 index 0000000000..cab8ec1607 --- /dev/null +++ b/src/app/core/tasks/models/pool-task-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for PoolTask + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const POOL_TASK = new ResourceType('pooltask'); diff --git a/src/app/core/tasks/models/task-object.model.ts b/src/app/core/tasks/models/task-object.model.ts index 1f37548b04..ac659ca9e5 100644 --- a/src/app/core/tasks/models/task-object.model.ts +++ b/src/app/core/tasks/models/task-object.model.ts @@ -1,46 +1,74 @@ +import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { Observable } from 'rxjs'; +import { link, typedObject } from '../../cache/builders/build-decorators'; import { CacheableObject } from '../../cache/object-cache.reducer'; -import { DSpaceObject } from '../../shared/dspace-object.model'; import { RemoteData } from '../../data/remote-data'; -import { WorkflowItem } from '../../submission/models/workflowitem.model'; -import { ResourceType } from '../../shared/resource-type'; import { EPerson } from '../../eperson/models/eperson.model'; +import { EPERSON } from '../../eperson/models/eperson.resource-type'; import { Group } from '../../eperson/models/group.model'; +import { GROUP } from '../../eperson/models/group.resource-type'; +import { DSpaceObject } from '../../shared/dspace-object.model'; +import { HALLink } from '../../shared/hal-link.model'; +import { WorkflowItem } from '../../submission/models/workflowitem.model'; +import { TASK_OBJECT } from './task-object.resource-type'; /** * An abstract model class for a TaskObject. */ +@typedObject +@inheritSerialization(DSpaceObject) export class TaskObject extends DSpaceObject implements CacheableObject { - static type = new ResourceType('taskobject'); + static type = TASK_OBJECT; /** * The task identifier */ + @autoserialize id: string; /** * The workflow step */ + @autoserialize step: string; /** * The task action type */ + @autoserialize action: string; /** - * The group of this task + * The {@link HALLink}s for this TaskObject */ - eperson: Observable>; + @deserialize + _links: { + self: HALLink; + eperson: HALLink; + group: HALLink; + workflowitem: HALLink; + }; /** - * The group of this task + * The EPerson for this task + * Will be undefined unless the eperson {@link HALLink} has been resolved. */ - group: Observable>; + @link(EPERSON) + eperson?: Observable>; /** - * The workflowitem object whom this task is related + * The Group for this task + * Will be undefined unless the group {@link HALLink} has been resolved. */ - workflowitem: Observable> | WorkflowItem; + @link(GROUP) + group?: Observable>; + + /** + * The WorkflowItem for this task + * Will be undefined unless the workflowitem {@link HALLink} has been resolved. + */ + @link(WorkflowItem.type) + workflowitem?: Observable> | WorkflowItem; + } diff --git a/src/app/core/tasks/models/task-object.resource-type.ts b/src/app/core/tasks/models/task-object.resource-type.ts new file mode 100644 index 0000000000..d25e27ee94 --- /dev/null +++ b/src/app/core/tasks/models/task-object.resource-type.ts @@ -0,0 +1,9 @@ +import { ResourceType } from '../../shared/resource-type'; + +/** + * The resource type for TaskObject + * + * Needs to be in a separate file to prevent circular + * dependencies in webpack. + */ +export const TASK_OBJECT = new ResourceType('taskobject'); diff --git a/src/app/core/tasks/pool-task-data.service.spec.ts b/src/app/core/tasks/pool-task-data.service.spec.ts index 7f40c6e89c..70ae4c7a91 100644 --- a/src/app/core/tasks/pool-task-data.service.spec.ts +++ b/src/app/core/tasks/pool-task-data.service.spec.ts @@ -6,7 +6,6 @@ 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'; @@ -22,9 +21,6 @@ describe('PoolTaskDataService', () => { const notificationsService = {} as NotificationsService; const http = {} as HttpClient; const comparator = {} as any; - const dataBuildService = { - normalize: (object) => object - } as NormalizedObjectBuildService; const objectCache = { addPatch: () => { /* empty */ @@ -39,7 +35,6 @@ describe('PoolTaskDataService', () => { return new PoolTaskDataService( requestService, rdbService, - dataBuildService, store, objectCache, halService, diff --git a/src/app/core/tasks/pool-task-data.service.ts b/src/app/core/tasks/pool-task-data.service.ts index 0e7704336d..f08274b5f1 100644 --- a/src/app/core/tasks/pool-task-data.service.ts +++ b/src/app/core/tasks/pool-task-data.service.ts @@ -1,25 +1,26 @@ -import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; - -import { Observable } from 'rxjs'; +import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; -import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { CoreState } from '../core.reducers'; -import { RequestService } from '../data/request.service'; -import { PoolTask } from './models/pool-task-object.model'; -import { TasksService } from './tasks.service'; -import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; -import { ObjectCacheService } from '../cache/object-cache.service'; +import { Observable } from 'rxjs'; import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { CoreState } from '../core.reducers'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { RequestService } from '../data/request.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { PoolTask } from './models/pool-task-object.model'; +import { POOL_TASK } from './models/pool-task-object.resource-type'; import { ProcessTaskResponse } from './models/process-task-response'; +import { TasksService } from './tasks.service'; /** * The service handling all REST requests for PoolTask */ @Injectable() +@dataService(POOL_TASK) export class PoolTaskDataService extends TasksService { /** @@ -34,7 +35,7 @@ export class PoolTaskDataService extends TasksService { * * @param {RequestService} requestService * @param {RemoteDataBuildService} rdbService - * @param {NormalizedObjectBuildService} dataBuildService + * @param {NormalizedObjectBuildService} linkService * @param {Store} store * @param {ObjectCacheService} objectCache * @param {HALEndpointService} halService @@ -45,7 +46,6 @@ export class PoolTaskDataService extends TasksService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, diff --git a/src/app/core/tasks/tasks.service.spec.ts b/src/app/core/tasks/tasks.service.spec.ts index 3ca9b8ea8f..782a950b2d 100644 --- a/src/app/core/tasks/tasks.service.spec.ts +++ b/src/app/core/tasks/tasks.service.spec.ts @@ -9,7 +9,6 @@ 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'; @@ -18,7 +17,6 @@ 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'; @@ -33,7 +31,6 @@ class TestService extends TasksService { constructor( protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected dataBuildService: NormalizedObjectBuildService, protected store: Store, protected objectCache: ObjectCacheService, protected halService: HALEndpointService, @@ -44,11 +41,8 @@ class TestService extends TasksService { } } -class NormalizedTestTaskObject extends NormalizedTaskObject { -} - -class DummyChangeAnalyzer implements ChangeAnalyzer { - diff(object1: NormalizedTestTaskObject, object2: NormalizedTestTaskObject): Operation[] { +class DummyChangeAnalyzer implements ChangeAnalyzer { + diff(object1: TestTask, object2: TestTask): Operation[] { return compare((object1 as any).metadata, (object2 as any).metadata); } @@ -66,9 +60,6 @@ describe('TasksService', () => { 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 */ @@ -83,7 +74,6 @@ describe('TasksService', () => { return new TestService( requestService, rdbService, - dataBuildService, store, objectCache, halService, diff --git a/src/app/core/tasks/tasks.service.ts b/src/app/core/tasks/tasks.service.ts index cf23bfd74b..0eae88e96c 100644 --- a/src/app/core/tasks/tasks.service.ts +++ b/src/app/core/tasks/tasks.service.ts @@ -18,10 +18,6 @@ import { CacheableObject } from '../cache/object-cache.reducer'; */ export abstract class TasksService extends DataService { - public getBrowseEndpoint(options: FindListOptions): Observable { - return this.halService.getEndpoint(this.linkPath); - } - /** * Fetch a RestRequest * diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html index 18ff77bf23..af339109c6 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html @@ -2,13 +2,13 @@
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html index 07e50eb6fb..2c7f24662a 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -2,13 +2,13 @@
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html index 394e5241e1..d6b9c4a62e 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -2,13 +2,13 @@
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html index 87312f8784..cdfa6293c4 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html @@ -4,7 +4,7 @@
- +
- +
- + ; @@ -43,6 +57,11 @@ const mockItem: Item = Object.assign(new Item(), { }); describe('JournalComponent', () => { + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot({ @@ -53,14 +72,25 @@ describe('JournalComponent', () => { })], declarations: [JournalComponent, GenericItemPageFieldComponent, TruncatePipe], providers: [ - {provide: ItemDataService, useValue: {}}, - {provide: TruncatableService, useValue: {}}, - {provide: RelationshipService, useValue: {}} + { provide: ItemDataService, useValue: {} }, + { provide: TruncatableService, useValue: {} }, + { provide: RelationshipService, useValue: {} }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(JournalComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} + set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html index 5c42be2b24..0fb1ec02f8 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html @@ -2,13 +2,13 @@
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html index b7eed7c8b4..321ecd4a47 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html @@ -3,13 +3,13 @@
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html index f3a0dea81f..c39de6bc2a 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -2,13 +2,13 @@
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html index 1b23d567f5..784000b446 100644 --- a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html @@ -4,7 +4,7 @@
- +
- +
- + diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts b/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts index 6792000fd0..72857654ce 100644 --- a/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts @@ -1,14 +1,12 @@ -import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { PageInfo } from '../../../../core/shared/page-info.model'; -import { ProjectComponent } from './project.component'; -import { of as observableOf } from 'rxjs'; import { createRelationshipsObservable, getItemPageFieldsTest } from '../../../../+item-page/simple/item-types/shared/item.component.spec'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { Item } from '../../../../core/shared/item.model'; +import { PageInfo } from '../../../../core/shared/page-info.model'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; +import { ProjectComponent } from './project.component'; const mockItem: Item = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html index 0977413722..d8a4e744e4 100644 --- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html @@ -9,5 +9,5 @@ + [tooltip]="metadataRepresentation.allMetadata(['organization.legalName']).length > 0 ? descTemplate : null"> diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts index 7d27b605ec..37cbe47c72 100644 --- a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts @@ -23,7 +23,7 @@ describe('OrgUnitItemMetadataListElementComponent', () => { declarations: [OrgUnitItemMetadataListElementComponent], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(OrgUnitItemMetadataListElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } + // set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html index b0fa714371..93165c24cd 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html @@ -1,6 +1,6 @@
- +
; @@ -79,6 +91,11 @@ function init() { describe('OrgUnitSearchResultListSubmissionElementComponent', () => { beforeEach(async(() => { init(); + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; TestBed.configureTestingModule({ declarations: [OrgUnitSearchResultListSubmissionElementComponent, TruncatePipe], providers: [ @@ -89,7 +106,16 @@ describe('OrgUnitSearchResultListSubmissionElementComponent', () => { { provide: NgbModal, useValue: {} }, { provide: ItemDataService, useValue: {} }, { provide: SelectableListService, useValue: {} }, - { provide: Store, useValue: {} } + { provide: Store, useValue: {} }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, ], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts index cbddb8d6f9..96f28a799b 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts @@ -1,4 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/internal/Observable'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { getFirstSucceededRemoteDataPayload } from '../../../../../core/shared/operators'; import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; @@ -37,6 +41,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes private translateService: TranslateService, private modalService: NgbModal, private itemDataService: ItemDataService, + private bitstreamDataService: BitstreamDataService, private selectableListService: SelectableListService) { super(truncatableService); } @@ -95,4 +100,11 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes modalComp.value = value; return modalRef.result; } + + // TODO refactor to return RemoteData, and thumbnail template to deal with loading + getThumbnail(): Observable { + return this.bitstreamDataService.getThumbnailFor(this.dso).pipe( + getFirstSucceededRemoteDataPayload() + ); + } } diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html index df93c2f4f3..25c091d386 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.html @@ -1,6 +1,6 @@
- +
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts index a21f0ec075..0949ebea7e 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.spec.ts @@ -1,21 +1,33 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { of as observableOf } from 'rxjs'; -import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; -import { PersonSearchResultListSubmissionElementComponent } from './person-search-result-list-submission-element.component'; -import { Item } from '../../../../../core/shared/item.model'; -import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; -import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; -import { RelationshipService } from '../../../../../core/data/relationship.service'; -import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; -import { TranslateService } from '@ngx-translate/core'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ItemDataService } from '../../../../../core/data/item-data.service'; -import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; import { Store } from '@ngrx/store'; -import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { TranslateService } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../../core/cache/object-cache.service'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { CommunityDataService } from '../../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../../core/data/dso-change-analyzer.service'; +import { ItemDataService } from '../../../../../core/data/item-data.service'; import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { RelationshipService } from '../../../../../core/data/relationship.service'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service'; +import { Item } from '../../../../../core/shared/item.model'; +import { UUIDService } from '../../../../../core/shared/uuid.service'; +import { NotificationsService } from '../../../../../shared/notifications/notifications.service'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { PersonSearchResultListSubmissionElementComponent } from './person-search-result-list-submission-element.component'; let personListElementComponent: PersonSearchResultListSubmissionElementComponent; let fixture: ComponentFixture; @@ -71,6 +83,11 @@ function init() { } describe('PersonSearchResultListElementSubmissionComponent', () => { + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; beforeEach(async(() => { init(); TestBed.configureTestingModule({ @@ -83,7 +100,16 @@ describe('PersonSearchResultListElementSubmissionComponent', () => { { provide: NgbModal, useValue: {} }, { provide: ItemDataService, useValue: {} }, { provide: SelectableListService, useValue: {} }, - { provide: Store, useValue: {}} + { provide: Store, useValue: {}}, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, ], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts index 37fd77649b..83761c6c20 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts @@ -1,4 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/internal/Observable'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { getFirstSucceededRemoteDataPayload } from '../../../../../core/shared/operators'; import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; @@ -37,6 +41,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu private translateService: TranslateService, private modalService: NgbModal, private itemDataService: ItemDataService, + private bitstreamDataService: BitstreamDataService, private selectableListService: SelectableListService) { super(truncatableService); } @@ -95,4 +100,11 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu modalComp.value = value; return modalRef.result; } + + // TODO refactor to return RemoteData, and thumbnail template to deal with loading + getThumbnail(): Observable { + return this.bitstreamDataService.getThumbnailFor(this.dso).pipe( + getFirstSucceededRemoteDataPayload() + ); + } } diff --git a/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts index b5043ea2d6..e3c73617f1 100644 --- a/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts +++ b/src/app/entity-groups/research-entities/submission/name-variant-modal/name-variant-modal.component.spec.ts @@ -18,7 +18,7 @@ describe('NameVariantModalComponent', () => { init(); TestBed.configureTestingModule({ declarations: [NameVariantModalComponent], - imports: [NgbModule.forRoot(), TranslateModule.forRoot()], + imports: [NgbModule, TranslateModule.forRoot()], providers: [{ provide: NgbActiveModal, useValue: modal }] }) .compileComponents(); diff --git a/src/app/search-navbar/search-navbar.component.ts b/src/app/search-navbar/search-navbar.component.ts index 1bedfb73ef..01329c1cbe 100644 --- a/src/app/search-navbar/search-navbar.component.ts +++ b/src/app/search-navbar/search-navbar.component.ts @@ -22,7 +22,7 @@ export class SearchNavbarComponent { isExpanded = 'collapsed'; // Search input field - @ViewChild('searchInput') searchField: ElementRef; + @ViewChild('searchInput', {static: false}) searchField: ElementRef; constructor(private formBuilder: FormBuilder, private router: Router, private searchService: SearchService) { this.searchForm = this.formBuilder.group(({ diff --git a/src/app/shared/browse-by/browse-by.component.spec.ts b/src/app/shared/browse-by/browse-by.component.spec.ts index 5592b88c86..51db888c4b 100644 --- a/src/app/shared/browse-by/browse-by.component.spec.ts +++ b/src/app/shared/browse-by/browse-by.component.spec.ts @@ -51,7 +51,7 @@ describe('BrowseByComponent', () => { CommonModule, TranslateModule.forRoot(), SharedModule, - NgbModule.forRoot(), + NgbModule, StoreModule.forRoot({}), TranslateModule.forRoot({ loader: { diff --git a/src/app/shared/chips/chips.component.spec.ts b/src/app/shared/chips/chips.component.spec.ts index 6dbecf5165..facfc8061b 100644 --- a/src/app/shared/chips/chips.component.spec.ts +++ b/src/app/shared/chips/chips.component.spec.ts @@ -6,16 +6,16 @@ import { Chips } from './models/chips.model'; import { UploaderService } from '../uploader/uploader.service'; import { ChipsComponent } from './chips.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { SortablejsModule } from 'angular-sortablejs'; import { By } from '@angular/platform-browser'; import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model'; -import { createTestComponent, hasClass } from '../testing/utils'; +import { createTestComponent } from '../testing/utils'; import { AuthorityConfidenceStateDirective } from '../authority-confidence/authority-confidence-state.directive'; import { TranslateModule } from '@ngx-translate/core'; import { GlobalConfig } from '../../../config/global-config.interface'; import { GLOBAL_CONFIG } from '../../../config'; import { MOCK_SUBMISSION_CONFIG } from '../testing/mock-submission-config'; import { ConfidenceType } from '../../core/integration/models/confidence-type'; +import { SortablejsModule } from 'ngx-sortablejs'; describe('ChipsComponent test suite', () => { @@ -32,7 +32,7 @@ describe('ChipsComponent test suite', () => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, SortablejsModule.forRoot({animation: 150}), TranslateModule.forRoot() ], diff --git a/src/app/shared/chips/chips.component.ts b/src/app/shared/chips/chips.component.ts index 1283decc9f..82bb8f0f72 100644 --- a/src/app/shared/chips/chips.component.ts +++ b/src/app/shared/chips/chips.component.ts @@ -1,13 +1,13 @@ import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, } from '@angular/core'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; -import { SortablejsOptions } from 'angular-sortablejs'; import { isObject } from 'lodash'; import { Chips } from './models/chips.model'; import { ChipsItem } from './models/chips-item.model'; import { UploaderService } from '../uploader/uploader.service'; import { TranslateService } from '@ngx-translate/core'; +import { Options } from 'sortablejs'; @Component({ selector: 'ds-chips', @@ -25,7 +25,7 @@ export class ChipsComponent implements OnChanges { @Output() remove: EventEmitter = new EventEmitter(); @Output() change: EventEmitter = new EventEmitter(); - options: SortablejsOptions; + options: Options; dragged = -1; tipText: string[]; diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts index 58488f721a..06f9843c6d 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.spec.ts @@ -1,27 +1,27 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; import { Location } from '@angular/common'; -import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl, FormGroup } from '@angular/forms'; -import { Community } from '../../../core/shared/community.model'; -import { ComColFormComponent } from './comcol-form.component'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { hasValue } from '../../empty.util'; -import { VarDirective } from '../../utils/var.directive'; -import { NotificationsService } from '../../notifications/notifications.service'; -import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; -import { AuthService } from '../../../core/auth/auth.service'; -import { AuthServiceMock } from '../../mocks/mock-auth.service'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; +import { TranslateModule } from '@ngx-translate/core'; import { of as observableOf } from 'rxjs'; -import { RemoteData } from '../../../core/data/remote-data'; -import { RestRequestMethod } from '../../../core/data/rest-request-method'; +import { AuthService } from '../../../core/auth/auth.service'; +import { ObjectCacheService } from '../../../core/cache/object-cache.service'; import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; +import { RemoteData } from '../../../core/data/remote-data'; import { RequestError } from '../../../core/data/request.models'; import { RequestService } from '../../../core/data/request.service'; -import { ObjectCacheService } from '../../../core/cache/object-cache.service'; -import { By } from '@angular/platform-browser'; +import { RestRequestMethod } from '../../../core/data/rest-request-method'; +import { Community } from '../../../core/shared/community.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { hasValue } from '../../empty.util'; +import { AuthServiceMock } from '../../mocks/mock-auth.service'; +import { NotificationsService } from '../../notifications/notifications.service'; +import { NotificationsServiceStub } from '../../testing/notifications-service-stub'; +import { VarDirective } from '../../utils/var.directive'; +import { ComColFormComponent } from './comcol-form.component'; describe('ComColFormComponent', () => { let comp: ComColFormComponent; @@ -43,10 +43,10 @@ describe('ComColFormComponent', () => { const dcRandom = 'dc.random'; const dcAbstract = 'dc.description.abstract'; - const titleMD = { [dcTitle]: [ { value: 'Community Title', language: null } ] }; - const randomMD = { [dcRandom]: [ { value: 'Random metadata excluded from form', language: null } ] }; - const abstractMD = { [dcAbstract]: [ { value: 'Community description', language: null } ] }; - const newTitleMD = { [dcTitle]: [ { value: 'New Community Title', language: null } ] }; + const titleMD = { [dcTitle]: [{ value: 'Community Title', language: null }] }; + const randomMD = { [dcRandom]: [{ value: 'Random metadata excluded from form', language: null }] }; + const abstractMD = { [dcAbstract]: [{ value: 'Community description', language: null }] }; + const newTitleMD = { [dcTitle]: [{ value: 'New Community Title', language: null }] }; const formModel = [ new DynamicInputModel({ id: 'title', @@ -96,7 +96,9 @@ describe('ComColFormComponent', () => { describe('when the dso doesn\'t contain an ID (newly created)', () => { beforeEach(() => { - initComponent(new Community()); + initComponent(Object.assign(new Community(), { + _links: { self: { href: 'community-self' } } + })); }); it('should initialize the uploadFilesOptions with a placeholder url', () => { @@ -119,7 +121,6 @@ describe('ComColFormComponent', () => { } } ); - comp.onSubmit(); expect(comp.submitForm.emit).toHaveBeenCalledWith( @@ -191,7 +192,8 @@ describe('ComColFormComponent', () => { beforeEach(() => { initComponent(Object.assign(new Community(), { id: 'community-id', - logo: observableOf(new RemoteData(false, false, true, null, undefined)) + logo: observableOf(new RemoteData(false, false, true, null, undefined)), + _links: { self: { href: 'community-self' } } })); }); @@ -208,7 +210,8 @@ describe('ComColFormComponent', () => { beforeEach(() => { initComponent(Object.assign(new Community(), { id: 'community-id', - logo: observableOf(new RemoteData(false, false, true, null, {})) + logo: observableOf(new RemoteData(false, false, true, null, {})), + _links: { self: { href: 'community-self' } } })); }); @@ -239,7 +242,7 @@ describe('ComColFormComponent', () => { }); describe('when dsoService.deleteLogo returns an error response', () => { - const response = new ErrorResponse(new RequestError('errorMessage')); + const response = new ErrorResponse(new RequestError('this error was purposely thrown, to test error notifications')); beforeEach(() => { spyOn(dsoService, 'deleteLogo').and.returnValue(observableOf(response)); @@ -313,9 +316,9 @@ describe('ComColFormComponent', () => { comp.formModel = []; comp.dso = dso; (comp as any).type = Community.type; - comp.uploaderComponent = Object.assign({ - uploader: {} - }); + comp.uploaderComponent = {uploader: {}} as any; + + console.log(comp); (comp as any).dsoService = dsoService; fixture.detectChanges(); location = (comp as any).location; diff --git a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts index 435ef61d72..35c6f50969 100644 --- a/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts +++ b/src/app/shared/comcol-forms/comcol-form/comcol-form.component.ts @@ -1,34 +1,30 @@ -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { Location } from '@angular/common'; -import { - DynamicFormControlModel, - DynamicFormService, - DynamicInputModel -} from '@ng-dynamic-forms/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; +import { DynamicFormControlModel, DynamicFormService, DynamicInputModel } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; +import { FileUploader } from 'ng2-file-upload'; +import { combineLatest as observableCombineLatest } from 'rxjs'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { Subscription } from 'rxjs/internal/Subscription'; +import { AuthService } from '../../../core/auth/auth.service'; +import { ObjectCacheService } from '../../../core/cache/object-cache.service'; +import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { RemoteData } from '../../../core/data/remote-data'; +import { RequestService } from '../../../core/data/request.service'; +import { RestRequestMethod } from '../../../core/data/rest-request-method'; +import { Bitstream } from '../../../core/shared/bitstream.model'; +import { Collection } from '../../../core/shared/collection.model'; +import { Community } from '../../../core/shared/community.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { MetadataMap, MetadataValue } from '../../../core/shared/metadata.models'; import { ResourceType } from '../../../core/shared/resource-type'; import { hasValue, isNotEmpty } from '../../empty.util'; -import { UploaderOptions } from '../../uploader/uploader-options.model'; import { NotificationsService } from '../../notifications/notifications.service'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { Subscription } from 'rxjs/internal/Subscription'; -import { AuthService } from '../../../core/auth/auth.service'; -import { Community } from '../../../core/shared/community.model'; -import { Collection } from '../../../core/shared/collection.model'; +import { UploaderOptions } from '../../uploader/uploader-options.model'; import { UploaderComponent } from '../../uploader/uploader.component'; -import { FileUploader } from 'ng2-file-upload'; -import { ErrorResponse, RestResponse } from '../../../core/cache/response.models'; -import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; -import { RemoteData } from '../../../core/data/remote-data'; -import { Bitstream } from '../../../core/shared/bitstream.model'; -import { combineLatest as observableCombineLatest } from 'rxjs'; -import { RestRequestMethod } from '../../../core/data/rest-request-method'; -import { RequestService } from '../../../core/data/request.service'; -import { ObjectCacheService } from '../../../core/cache/object-cache.service'; /** * A form for creating and editing Communities or Collections @@ -43,7 +39,7 @@ export class ComColFormComponent implements OnInit, OnDe /** * The logo uploader component */ - @ViewChild(UploaderComponent) uploaderComponent: UploaderComponent; + @ViewChild(UploaderComponent, {static: true}) uploaderComponent: UploaderComponent; /** * DSpaceObject that the form represents @@ -253,8 +249,8 @@ export class ComColFormComponent implements OnInit, OnDe * Refresh the object's cache to ensure the latest version */ private refreshCache() { - this.requestService.removeByHrefSubstring(this.dso.self); - this.objectCache.remove(this.dso.self); + this.requestService.removeByHrefSubstring(this.dso._links.self.href); + this.objectCache.remove(this.dso._links.self.href); } /** diff --git a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts index 7b23c59498..e9373aff47 100644 --- a/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -1,19 +1,18 @@ import { Component, OnInit } from '@angular/core'; -import { Community } from '../../../core/shared/community.model'; -import { CommunityDataService } from '../../../core/data/community-data.service'; -import { Observable } from 'rxjs'; -import { RouteService } from '../../../core/services/route.service'; -import { ActivatedRoute, Router } from '@angular/router'; -import { RemoteData } from '../../../core/data/remote-data'; -import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util'; -import { take } from 'rxjs/operators'; -import { getSucceededRemoteData } from '../../../core/shared/operators'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { DataService } from '../../../core/data/data.service'; -import { ComColDataService } from '../../../core/data/comcol-data.service'; -import { NotificationsService } from '../../notifications/notifications.service'; +import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { take } from 'rxjs/operators'; +import { ComColDataService } from '../../../core/data/comcol-data.service'; +import { CommunityDataService } from '../../../core/data/community-data.service'; +import { RemoteData } from '../../../core/data/remote-data'; +import { RouteService } from '../../../core/services/route.service'; +import { Community } from '../../../core/shared/community.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { getSucceededRemoteData } from '../../../core/shared/operators'; import { ResourceType } from '../../../core/shared/resource-type'; +import { hasValue, isNotEmpty, isNotUndefined } from '../../empty.util'; +import { NotificationsService } from '../../notifications/notifications.service'; /** * Component representing the create page for communities and collections diff --git a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts index 5711aa4e70..84454c4250 100644 --- a/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts +++ b/src/app/shared/comcol-forms/edit-comcol-page/comcol-metadata/comcol-metadata.component.spec.ts @@ -1,21 +1,20 @@ -import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { CommunityDataService } from '../../../../core/data/community-data.service'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Community } from '../../../../core/shared/community.model'; -import { of as observableOf } from 'rxjs/internal/observable/of'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { TranslateModule } from '@ngx-translate/core'; -import { SharedModule } from '../../../shared.module'; import { CommonModule } from '@angular/common'; -import { RouterTestingModule } from '@angular/router/testing'; -import { DataService } from '../../../../core/data/data.service'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComcolMetadataComponent } from './comcol-metadata.component'; -import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../testing/utils'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs/internal/observable/of'; import { ComColDataService } from '../../../../core/data/comcol-data.service'; -import { NotificationsServiceStub } from '../../../testing/notifications-service-stub'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { Community } from '../../../../core/shared/community.model'; +import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { NotificationsService } from '../../../notifications/notifications.service'; +import { SharedModule } from '../../../shared.module'; +import { NotificationsServiceStub } from '../../../testing/notifications-service-stub'; +import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../testing/utils'; +import { ComcolMetadataComponent } from './comcol-metadata.component'; describe('ComColMetadataComponent', () => { let comp: ComcolMetadataComponent; diff --git a/src/app/shared/comcol-page-logo/comcol-page-logo.component.html b/src/app/shared/comcol-page-logo/comcol-page-logo.component.html index 4bd7369f06..057c358223 100644 --- a/src/app/shared/comcol-page-logo/comcol-page-logo.component.html +++ b/src/app/shared/comcol-page-logo/comcol-page-logo.component.html @@ -1,3 +1,3 @@ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss index 5b808b9cfd..4e58759f4e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.scss @@ -9,7 +9,7 @@ justify-content: center; } -:host /deep/ .custom-select { +:host ::ng-deep .custom-select { -webkit-appearance: none; -moz-appearance: none; appearance: none; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts index 91c1dbc085..75ea88735f 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.spec.ts @@ -160,7 +160,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => { imports: [ FormsModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, DynamicFormsCoreModule.forRoot(), SharedModule, TranslateModule.forRoot(), diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 466ad8ac2a..4d26f3948d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -29,13 +29,13 @@ import { DYNAMIC_FORM_CONTROL_TYPE_SELECT, DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA, DYNAMIC_FORM_CONTROL_TYPE_TIMEPICKER, - DynamicDatePickerModel, + DynamicDatePickerModel, DynamicFormComponentService, DynamicFormControl, DynamicFormControlContainerComponent, DynamicFormControlEvent, - DynamicFormControlModel, DynamicFormInstancesService, + DynamicFormControlModel, DynamicFormLayout, - DynamicFormLayoutService, + DynamicFormLayoutService, DynamicFormRelationService, DynamicFormValidationService, DynamicTemplateDirective, } from '@ng-dynamic-forms/core'; @@ -50,6 +50,7 @@ import { DynamicNGBootstrapTimePickerComponent } from '@ng-dynamic-forms/ui-ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; +import { followLink } from '../../../utils/follow-link-config.model'; import { Reorderable, ReorderableRelationship @@ -201,32 +202,32 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo @Output('dfFocus') focus: EventEmitter = new EventEmitter(); @Output('ngbEvent') customEvent: EventEmitter = new EventEmitter(); /* tslint:enable:no-output-rename */ - @ViewChild('componentViewContainer', { read: ViewContainerRef }) componentViewContainerRef: ViewContainerRef; + @ViewChild('componentViewContainer', { read: ViewContainerRef, static: true}) componentViewContainerRef: ViewContainerRef; private showErrorMessagesPreviousStage: boolean; get componentType(): Type | null { - return this.layoutService.getCustomComponentType(this.model) || dsDynamicFormControlMapFn(this.model); + return dsDynamicFormControlMapFn(this.model); } constructor( protected componentFactoryResolver: ComponentFactoryResolver, - protected dynamicFormInstanceService: DynamicFormInstancesService, + protected dynamicFormComponentService: DynamicFormComponentService, protected layoutService: DynamicFormLayoutService, protected validationService: DynamicFormValidationService, protected translateService: TranslateService, + protected relationService: DynamicFormRelationService, private modalService: NgbModal, - private relationService: RelationshipService, + private relationshipService: RelationshipService, private selectableListService: SelectableListService, private itemService: ItemDataService, - private relationshipService: RelationshipService, private zone: NgZone, private store: Store, private submissionObjectService: SubmissionObjectDataService, private ref: ChangeDetectorRef ) { - super(componentFactoryResolver, layoutService, validationService, dynamicFormInstanceService); + super(componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService); } /** @@ -240,7 +241,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo this.listId = 'list-' + this.model.relationship.relationshipType; const submissionObject$ = this.submissionObjectService - .findById(this.model.submissionId).pipe( + .findById(this.model.submissionId, followLink('item'), followLink('collection')).pipe( getAllSucceededRemoteData(), getRemoteDataPayload() ); @@ -251,7 +252,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo this.subs.push(item$.subscribe((item) => this.item = item)); this.subs.push(collection$.subscribe((collection) => this.collection = collection)); this.reorderables$ = item$.pipe( - switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType) + switchMap((item) => this.relationshipService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType, undefined, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')) .pipe( getAllSucceededRemoteData(), getRemoteDataPayload(), @@ -283,9 +284,12 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo this.ref.detectChanges(); })); - this.relationService.getRelatedItemsByLabel(this.item, this.model.relationship.relationshipType).pipe( + item$.pipe( + switchMap((item) => this.relationshipService.getRelatedItemsByLabel(item, this.model.relationship.relationshipType)), map((items: RemoteData>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))), - ).subscribe((relatedItems: Array>) => this.selectableListService.select(this.listId, relatedItems)); + ).subscribe((relatedItems: Array>) => { + this.selectableListService.select(this.listId, relatedItems) + }); } } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts index da7f5637dd..327859e0ea 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.spec.ts @@ -26,7 +26,7 @@ describe('DsDatePickerInlineComponent test suite', () => { ReactiveFormsModule, NoopAnimationsModule, TextMaskModule, - NgbDatepickerModule.forRoot(), + NgbDatepickerModule, DynamicFormsCoreModule.forRoot() ], declarations: [DsDatePickerInlineComponent] diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts index f51c2f78f4..73375a85a2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component.ts @@ -24,7 +24,7 @@ export class DsDatePickerInlineComponent extends DynamicFormControlComponent { @Output() change: EventEmitter = new EventEmitter(); @Output() focus: EventEmitter = new EventEmitter(); - @ViewChild(NgbDatepicker) ngbDatePicker: NgbDatepicker; + @ViewChild(NgbDatepicker, {static: false}) ngbDatePicker: NgbDatepicker; constructor(protected layoutService: DynamicFormLayoutService, protected validationService: DynamicFormValidationService, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts index 8f40c4f85f..ad54925880 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.spec.ts @@ -43,7 +43,7 @@ describe('DsDatePickerComponent test suite', () => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot() + NgbModule ], declarations: [ DsDatePickerComponent, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts index 1b3bcb5a59..e312444625 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.spec.ts @@ -88,7 +88,7 @@ describe('DsDynamicListComponent test suite', () => { DynamicFormsNGBootstrapUIModule, FormsModule, ReactiveFormsModule, - NgbModule.forRoot() + NgbModule ], declarations: [ DsDynamicListComponent, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss index 3af258db79..e1ba2442e5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss @@ -2,7 +2,7 @@ display:none } -:host /deep/ .dropdown-menu { +:host ::ng-deep .dropdown-menu { left: 0 !important; width: 100% !important; max-height: $dropdown-menu-max-height; @@ -10,10 +10,10 @@ overflow-x: hidden; } -:host /deep/ .dropdown-item.active, -:host /deep/ .dropdown-item:active, -:host /deep/ .dropdown-item:focus, -:host /deep/ .dropdown-item:hover { +:host ::ng-deep .dropdown-item.active, +:host ::ng-deep .dropdown-item:active, +:host ::ng-deep .dropdown-item:focus, +:host ::ng-deep .dropdown-item:hover { color: $dropdown-link-hover-color !important; background-color: $dropdown-link-hover-bg !important; } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts index b0ed3a1dc2..c1f8ad69ba 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.spec.ts @@ -160,7 +160,7 @@ describe('Dynamic Lookup component', () => { FormsModule, InfiniteScrollModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts index 75d30d9d79..eb0f8f76f9 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.spec.ts @@ -113,7 +113,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => { BrowserAnimationsModule, FormsModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, StoreModule.forRoot({}), TranslateModule.forRoot() ], diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts index ea62eeb4ce..5f96e957ac 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components.ts @@ -65,7 +65,7 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent private selectedChipItem: ChipsItem; private subs: Subscription[] = []; - @ViewChild('formRef') private formRef: FormComponent; + @ViewChild('formRef', {static: false}) private formRef: FormComponent; constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, private authorityService: AuthorityService, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts index ab923a58fa..16446e624e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts @@ -64,7 +64,7 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => { FormsModule, InfiniteScrollModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss index a657d3eeb6..032596207a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.scss @@ -8,7 +8,7 @@ padding-right: 100%; } -:host /deep/ .dropdown-menu { +:host ::ng-deep .dropdown-menu { width: 100% !important; max-height: $dropdown-menu-max-height; overflow-y: scroll; @@ -17,10 +17,10 @@ margin-top: $spacer !important; } -:host /deep/ .dropdown-item.active, -:host /deep/ .dropdown-item:active, -:host /deep/ .dropdown-item:focus, -:host /deep/ .dropdown-item:hover { +:host ::ng-deep .dropdown-item.active, +:host ::ng-deep .dropdown-item:active, +:host ::ng-deep .dropdown-item:focus, +:host ::ng-deep .dropdown-item:hover { color: $dropdown-link-hover-color !important; background-color: $dropdown-link-hover-bg !important; } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts index 9aeada5032..dcc4eaf9c9 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/tag/dynamic-tag.component.spec.ts @@ -85,7 +85,7 @@ describe('DsDynamicTagComponent test suite', () => { DynamicFormsCoreModule, DynamicFormsNGBootstrapUIModule, FormsModule, - NgbModule.forRoot(), + NgbModule, ReactiveFormsModule, ], declarations: [ 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 a44a20d4bd..c976454dd9 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 @@ -33,7 +33,7 @@ export class DsDynamicTagComponent extends DynamicFormControlComponent implement @Output() change: EventEmitter = new EventEmitter(); @Output() focus: EventEmitter = new EventEmitter(); - @ViewChild('instance') instance: NgbTypeahead; + @ViewChild('instance', {static: false}) instance: NgbTypeahead; chips: Chips; hasAuthority: boolean; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss index fe20afe1ce..3857d96e78 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.scss @@ -1,18 +1,18 @@ -:host /deep/ .dropdown-menu { +:host ::ng-deep .dropdown-menu { width: 100% !important; max-height: $dropdown-menu-max-height; overflow-y: auto !important; overflow-x: hidden; } -:host /deep/ .dropdown-item { +:host ::ng-deep .dropdown-item { border-bottom: $dropdown-border-width solid $dropdown-border-color; } -:host /deep/ .dropdown-item.active, -:host /deep/ .dropdown-item:active, -:host /deep/ .dropdown-item:focus, -:host /deep/ .dropdown-item:hover { +:host ::ng-deep .dropdown-item.active, +:host ::ng-deep .dropdown-item:active, +:host ::ng-deep .dropdown-item:focus, +:host ::ng-deep .dropdown-item:hover { color: $dropdown-link-hover-color !important; background-color: $dropdown-link-hover-bg !important; } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts index 47b83ed2f9..4b1e2d8703 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.spec.ts @@ -70,7 +70,7 @@ describe('DsDynamicTypeaheadComponent test suite', () => { DynamicFormsCoreModule, DynamicFormsNGBootstrapUIModule, FormsModule, - NgbModule.forRoot(), + NgbModule, ReactiveFormsModule, TranslateModule.forRoot() ], diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts index 136d1db1c2..791704a7ca 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts @@ -31,7 +31,7 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp @Output() change: EventEmitter = new EventEmitter(); @Output() focus: EventEmitter = new EventEmitter(); - @ViewChild('instance') instance: NgbTypeahead; + @ViewChild('instance', {static: false}) instance: NgbTypeahead; searching = false; searchOptions: IntegrationSearchOptions; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts index d1b289bf11..3fbe372699 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.spec.ts @@ -79,7 +79,7 @@ describe('DsDynamicLookupRelationModalComponent', () => { init(); TestBed.configureTestingModule({ declarations: [DsDynamicLookupRelationModalComponent], - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot()], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule], providers: [ { provide: SearchConfigurationService, useValue: { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts index 00242ad9ce..06a0cf2ac7 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts @@ -95,7 +95,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { init(); TestBed.configureTestingModule({ declarations: [DsDynamicLookupRelationExternalSourceTabComponent, VarDirective], - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot(), BrowserAnimationsModule], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule, BrowserAnimationsModule], providers: [ { provide: SearchConfigurationService, useValue: { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts index 5248f95573..264b3f945a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts @@ -67,7 +67,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { init(); TestBed.configureTestingModule({ declarations: [ExternalSourceEntryImportModalComponent], - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule.forRoot()], + imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), NgbModule], providers: [ { provide: LookupRelationService, useValue: lookupRelationService }, { provide: SelectableListService, useValue: selectService }, diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts index ea0957f689..972abb68b5 100644 --- a/src/app/shared/form/builder/form-builder.service.spec.ts +++ b/src/app/shared/form/builder/form-builder.service.spec.ts @@ -276,7 +276,7 @@ describe('FormBuilderService test suite', () => { { fields: [ { - input: {type: 'lookup'}, + input: { type: 'lookup' }, label: 'Journal', mandatory: 'false', repeatable: false, @@ -291,7 +291,7 @@ describe('FormBuilderService test suite', () => { languageCodes: [] } as FormFieldModel, { - input: {type: 'onebox'}, + input: { type: 'onebox' }, label: 'Issue', mandatory: 'false', repeatable: false, @@ -304,7 +304,7 @@ describe('FormBuilderService test suite', () => { languageCodes: [] } as FormFieldModel, { - input: {type: 'name'}, + input: { type: 'name' }, label: 'Name', mandatory: 'false', repeatable: false, @@ -322,24 +322,24 @@ describe('FormBuilderService test suite', () => { fields: [ { hints: 'If the item has any identification numbers or codes associated with↵ it, please enter the types and the actual numbers or codes.', - input: {type: 'onebox'}, + input: { type: 'onebox' }, label: 'Identifiers', languageCodes: [], mandatory: 'false', repeatable: false, selectableMetadata: [ - {metadata: 'dc.identifier.issn', label: 'ISSN'}, - {metadata: 'dc.identifier.other', label: 'Other'}, - {metadata: 'dc.identifier.ismn', label: 'ISMN'}, - {metadata: 'dc.identifier.govdoc', label: 'Gov\'t Doc #'}, - {metadata: 'dc.identifier.uri', label: 'URI'}, - {metadata: 'dc.identifier.isbn', label: 'ISBN'}, - {metadata: 'dc.identifier.doi', label: 'DOI'}, - {metadata: 'dc.identifier.pmid', label: 'PubMed ID'}, - {metadata: 'dc.identifier.arxiv', label: 'arXiv'} + { metadata: 'dc.identifier.issn', label: 'ISSN' }, + { metadata: 'dc.identifier.other', label: 'Other' }, + { metadata: 'dc.identifier.ismn', label: 'ISMN' }, + { metadata: 'dc.identifier.govdoc', label: 'Gov\'t Doc #' }, + { metadata: 'dc.identifier.uri', label: 'URI' }, + { metadata: 'dc.identifier.isbn', label: 'ISBN' }, + { metadata: 'dc.identifier.doi', label: 'DOI' }, + { metadata: 'dc.identifier.pmid', label: 'PubMed ID' }, + { metadata: 'dc.identifier.arxiv', label: 'arXiv' } ] }, { - input: {type: 'onebox'}, + input: { type: 'onebox' }, label: 'Publisher', mandatory: 'false', repeatable: false, @@ -356,7 +356,7 @@ describe('FormBuilderService test suite', () => { { fields: [ { - input: {type: 'onebox'}, + input: { type: 'onebox' }, label: 'Conference', mandatory: 'false', repeatable: false, @@ -373,10 +373,14 @@ describe('FormBuilderService test suite', () => { ] } as FormRowModel ], - self: 'testFormConfiguration.url', + self: { + href: 'testFormConfiguration.url' + }, type: 'submissionform', _links: { - self: 'testFormConfiguration.url' + self: { + href: 'testFormConfiguration.url' + } } } as any; }); diff --git a/src/app/shared/form/builder/models/form-field-previous-value-object.ts b/src/app/shared/form/builder/models/form-field-previous-value-object.ts index f0ead99f91..ca4a47c089 100644 --- a/src/app/shared/form/builder/models/form-field-previous-value-object.ts +++ b/src/app/shared/form/builder/models/form-field-previous-value-object.ts @@ -14,7 +14,7 @@ export class FormFieldPreviousValueObject { return this._path; } - set path(path: any[]) { + set path(path: string | string[]) { this._path = path; } diff --git a/src/app/shared/form/form.component.spec.ts b/src/app/shared/form/form.component.spec.ts index 3342db37ae..f0617c5c0a 100644 --- a/src/app/shared/form/form.component.spec.ts +++ b/src/app/shared/form/form.component.spec.ts @@ -142,7 +142,7 @@ describe('FormComponent test suite', () => { CommonModule, FormsModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, StoreModule.forRoot({}), TranslateModule.forRoot() ], diff --git a/src/app/shared/input-suggestions/input-suggestions.component.ts b/src/app/shared/input-suggestions/input-suggestions.component.ts index 7f8d0741de..ad052672c8 100644 --- a/src/app/shared/input-suggestions/input-suggestions.component.ts +++ b/src/app/shared/input-suggestions/input-suggestions.component.ts @@ -92,7 +92,7 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange /** * Reference to the input field component */ - @ViewChild('inputField') queryInput: ElementRef; + @ViewChild('inputField', {static: false}) queryInput: ElementRef; /** * Reference to the suggestion components */ diff --git a/src/app/shared/loading/loading.component.scss b/src/app/shared/loading/loading.component.scss index c9ccb5b2fa..e2287cdc8b 100644 --- a/src/app/shared/loading/loading.component.scss +++ b/src/app/shared/loading/loading.component.scss @@ -58,10 +58,10 @@ span.l-10 {-webkit-animation-delay: 0s;animation-delay: 0s;-ms-animation-delay: 100% {opacity: 0;} } -@-keyframes loader { - 0% {-transform: translateX(-30px); opacity: 0;} +@keyframes loader { + 0% {transform: translateX(-30px); opacity: 0;} 25% {opacity: 1;} - 50% {-transform: translateX(30px); opacity: 0;} + 50% {transform: translateX(30px); opacity: 0;} 100% {opacity: 0;} } @@ -70,4 +70,4 @@ span.l-10 {-webkit-animation-delay: 0s;animation-delay: 0s;-ms-animation-delay: 25% {opacity: 1;} 50% {-ms-transform: translateX(30px); opacity: 0;} 100% {opacity: 0;} -} \ No newline at end of file +} diff --git a/src/app/shared/menu/menu.actions.ts b/src/app/shared/menu/menu.actions.ts index 0c1533ed3b..00275441d6 100644 --- a/src/app/shared/menu/menu.actions.ts +++ b/src/app/shared/menu/menu.actions.ts @@ -223,4 +223,6 @@ export type MenuAction = | ActivateMenuSectionAction | DeactivateMenuSectionAction | ToggleActiveMenuSectionAction + | CollapseMenuPreviewAction + | ExpandMenuPreviewAction /* tslint:enable:max-classes-per-file */ diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts index eb385b5afd..86bede6789 100644 --- a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts +++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts @@ -28,7 +28,7 @@ export class MetadataRepresentationLoaderComponent implements OnInit { /** * Directive to determine where the dynamic child component is located */ - @ViewChild(MetadataRepresentationDirective) mdRepDirective: MetadataRepresentationDirective; + @ViewChild(MetadataRepresentationDirective, {static: true}) mdRepDirective: MetadataRepresentationDirective; constructor(private componentFactoryResolver: ComponentFactoryResolver) { } diff --git a/src/app/shared/mocks/mock-item.ts b/src/app/shared/mocks/mock-item.ts index 3b77b630c5..a5b6a45d4a 100644 --- a/src/app/shared/mocks/mock-item.ts +++ b/src/app/shared/mocks/mock-item.ts @@ -1,11 +1,86 @@ -import {of as observableOf, Observable } from 'rxjs'; +import { of as observableOf } from 'rxjs'; +import { BitstreamFormat } from '../../core/shared/bitstream-format.model'; +import { Bitstream } from '../../core/shared/bitstream.model'; import { Item } from '../../core/shared/item.model'; -import { RemoteData } from '../../core/data/remote-data'; -import { Bitstream } from '../../core/shared/bitstream.model'; -import { PaginatedList } from '../../core/data/paginated-list'; import { createPaginatedList, createSuccessfulRemoteDataObject$ } from '../testing/utils'; +export const MockBitstreamFormat1: BitstreamFormat = Object.assign(new BitstreamFormat(), { + shortDescription: 'Microsoft Word XML', + description: 'Microsoft Word XML', + mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + supportLevel: 0, + internal: false, + extensions: null, + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10' + } + } +}); + +export const MockBitstreamFormat2: BitstreamFormat = Object.assign(new BitstreamFormat(), { + shortDescription: 'Adobe PDF', + description: 'Adobe Portable Document Format', + mimetype: 'application/pdf', + supportLevel: 0, + internal: false, + extensions: null, + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4' + } + } +}); + +export const MockBitstream1: Bitstream = Object.assign(new Bitstream(), + { + sizeBytes: 10201, + content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content', + format: observableOf(MockBitstreamFormat1), + bundleName: 'ORIGINAL', + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713' + } + }, + id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713', + uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713', + type: 'bitstream', + metadata: { + 'dc.title': [ + { + language: null, + value: 'test_word.docx' + } + ] + } + }); + +export const MockBitstream2: Bitstream = Object.assign(new Bitstream(), { + sizeBytes: 31302, + content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content', + format: observableOf(MockBitstreamFormat2), + bundleName: 'ORIGINAL', + id: '99b00f3c-1cc6-4689-8158-91965bee6b28', + uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28', + type: 'bitstream', + _links: { + self: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28' }, + content: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content' }, + format: { href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4' }, + bundle: { href: '' } + }, + metadata: { + 'dc.title': [ + { + language: null, + value: 'test_pdf.pdf' + } + ] + } +}); + /* tslint:disable:no-shadowed-variable */ export const MockItem: Item = Object.assign(new Item(), { handle: '10673/6', @@ -17,7 +92,11 @@ export const MockItem: Item = Object.assign(new Item(), { { name: 'ORIGINAL', bitstreams: observableOf(Object.assign({ - self: 'dspace-angular://aggregated/object/1507836003548', + _links: { + self: { + href: 'dspace-angular://aggregated/object/1507836003548', + } + }, requestPending: false, responsePending: false, isSuccessful: true, @@ -39,82 +118,18 @@ export const MockItem: Item = Object.assign(new Item(), { currentPage: 2 }, page: [ - { - sizeBytes: 10201, - content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713/content', - format: observableOf({ - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10', - requestPending: false, - responsePending: false, - isSuccessful: true, - errorMessage: '', - statusCode: '202', - pageInfo: {}, - payload: { - shortDescription: 'Microsoft Word XML', - description: 'Microsoft Word XML', - mimetype: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - supportLevel: 0, - internal: false, - extensions: null, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/10' - } - }), - bundleName: 'ORIGINAL', - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/cf9b0c8e-a1eb-4b65-afd0-567366448713', - id: 'cf9b0c8e-a1eb-4b65-afd0-567366448713', - uuid: 'cf9b0c8e-a1eb-4b65-afd0-567366448713', - type: 'bitstream', - metadata: { - 'dc.title': [ - { - language: null, - value: 'test_word.docx' - } - ] - } - }, - { - sizeBytes: 31302, - content: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28/content', - format: observableOf({ - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4', - requestPending: false, - responsePending: false, - isSuccessful: true, - errorMessage: '', - statusCode: '202', - pageInfo: {}, - payload: { - shortDescription: 'Adobe PDF', - description: 'Adobe Portable Document Format', - mimetype: 'application/pdf', - supportLevel: 0, - internal: false, - extensions: null, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreamformats/4' - } - }), - bundleName: 'ORIGINAL', - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/99b00f3c-1cc6-4689-8158-91965bee6b28', - id: '99b00f3c-1cc6-4689-8158-91965bee6b28', - uuid: '99b00f3c-1cc6-4689-8158-91965bee6b28', - type: 'bitstream', - metadata: { - 'dc.title': [ - { - language: null, - value: 'test_pdf.pdf' - } - ] - } - } + MockBitstream1, + MockBitstream2 ] } })) } ])), - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357', + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f357' + } + }, id: '0ec7ff22-f211-40ab-a69e-c819b0b1f357', uuid: '0ec7ff22-f211-40ab-a69e-c819b0b1f357', type: 'item', @@ -219,7 +234,11 @@ export const MockItem: Item = Object.assign(new Item(), { ] }, owningCollection: observableOf({ - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', + _links: { + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' + } + }, requestPending: false, responsePending: false, isSuccessful: true, @@ -228,5 +247,6 @@ export const MockItem: Item = Object.assign(new Item(), { pageInfo: {}, payload: [] } - )}); + ) +}); /* tslint:enable:no-shadowed-variable */ diff --git a/src/app/shared/mocks/mock-link-service.ts b/src/app/shared/mocks/mock-link-service.ts new file mode 100644 index 0000000000..d50640a629 --- /dev/null +++ b/src/app/shared/mocks/mock-link-service.ts @@ -0,0 +1,9 @@ +import { LinkService } from '../../core/cache/builders/link.service'; + +export function getMockLinkService(): LinkService { + return jasmine.createSpyObj('linkService', { + resolveLinks: jasmine.createSpy('resolveLinks'), + resolveLink: jasmine.createSpy('resolveLink'), + removeResolvedLinks: jasmine.createSpy('removeResolvedLinks') + }); +} diff --git a/src/app/shared/mocks/mock-remote-data-build.service.ts b/src/app/shared/mocks/mock-remote-data-build.service.ts index 2e492daf14..2dff033a26 100644 --- a/src/app/shared/mocks/mock-remote-data-build.service.ts +++ b/src/app/shared/mocks/mock-remote-data-build.service.ts @@ -1,13 +1,12 @@ -import { Observable, of as observableOf } from 'rxjs'; +import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; +import { PaginatedList } from '../../core/data/paginated-list'; import { RemoteData } from '../../core/data/remote-data'; import { RequestEntry } from '../../core/data/request.reducer'; -import { hasValue } from '../empty.util'; -import { NormalizedObject } from '../../core/cache/models/normalized-object.model'; -import { createSuccessfulRemoteDataObject$ } from '../testing/utils'; -import { PaginatedList } from '../../core/data/paginated-list'; import { PageInfo } from '../../core/shared/page-info.model'; +import { hasValue } from '../empty.util'; +import { createSuccessfulRemoteDataObject$ } from '../testing/utils'; export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observable>, buildList$?: Observable>>): RemoteDataBuildService { return { @@ -22,7 +21,6 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab } }, buildSingle: (href$: string | Observable) => createSuccessfulRemoteDataObject$({}), - build: (normalized: NormalizedObject) => Object.create({}), buildList: (href$: string | Observable) => { if (hasValue(buildList$)) { return buildList$; @@ -33,3 +31,38 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab } as RemoteDataBuildService; } + +export function getMockRemoteDataBuildServiceHrefMap(toRemoteDataObservable$?: Observable>, buildListHrefMap$?: { [href: string]: Observable>>; }): RemoteDataBuildService { + return { + toRemoteDataObservable: (requestEntry$: Observable, payload$: Observable) => { + + if (hasValue(toRemoteDataObservable$)) { + return toRemoteDataObservable$; + } else { + return payload$.pipe(map((payload) => ({ + payload + } as RemoteData))) + } + }, + buildSingle: (href$: string | Observable) => createSuccessfulRemoteDataObject$({}), + buildList: (href$: string | Observable) => { + if (typeof href$ === 'string') { + if (hasValue(buildListHrefMap$[href$])) { + return buildListHrefMap$[href$]; + } else { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])) + } + } + href$.pipe( + map((href: string) => { + if (hasValue(buildListHrefMap$[href])) { + return buildListHrefMap$[href]; + } else { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])) + } + }) + ); + } + } as RemoteDataBuildService; + +} diff --git a/src/app/shared/mocks/mock-request.service.ts b/src/app/shared/mocks/mock-request.service.ts index 103ab14d88..23101b6feb 100644 --- a/src/app/shared/mocks/mock-request.service.ts +++ b/src/app/shared/mocks/mock-request.service.ts @@ -10,6 +10,7 @@ export function getMockRequestService(requestEntry$: Observable = getByHref: requestEntry$, getByUUID: requestEntry$, uriEncodeBody: jasmine.createSpy('uriEncodeBody'), + isCachedOrPending: false, hasByHrefObservable: observableOf(false), /* tslint:disable:no-empty */ removeByHrefSubstring: () => {} diff --git a/src/app/shared/mocks/mock-submission.ts b/src/app/shared/mocks/mock-submission.ts index a97d2fb31a..082eec4c71 100644 --- a/src/app/shared/mocks/mock-submission.ts +++ b/src/app/shared/mocks/mock-submission.ts @@ -1,15 +1,16 @@ -import { SubmissionObjectState } from '../../submission/objects/submission-objects.reducer'; import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model'; import { PaginatedList } from '../../core/data/paginated-list'; -import { PageInfo } from '../../core/shared/page-info.model'; -import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model'; import { Group } from '../../core/eperson/models/group.model'; +import { PageInfo } from '../../core/shared/page-info.model'; +import { SubmissionObjectState } from '../../submission/objects/submission-objects.reducer'; +import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model'; export const mockSectionsData = { - traditionalpageone:{ + traditionalpageone: { 'dc.title': [ - new FormFieldMetadataValueObject('test', null, null, 'test' ) - ]}, + new FormFieldMetadataValueObject('test', null, null, 'test') + ] + }, license: { url: null, acceptanceDate: null, @@ -21,14 +22,16 @@ export const mockSectionsData = { }; export const mockSectionsDataTwo = { - traditionalpageone:{ + traditionalpageone: { 'dc.title': [ - new FormFieldMetadataValueObject('test', null, null, 'test' ) - ]}, - traditionalpagetwo:{ + new FormFieldMetadataValueObject('test', null, null, 'test') + ] + }, + traditionalpagetwo: { 'dc.relation': [ - new FormFieldMetadataValueObject('test', null, null, 'test' ) - ]}, + new FormFieldMetadataValueObject('test', null, null, 'test') + ] + }, license: { url: null, acceptanceDate: null, @@ -68,14 +71,14 @@ export const mockUploadResponse1Errors = { ] }; -export const mockUploadResponse1ParsedErrors: any = { +export const mockUploadResponse1ParsedErrors: any = { traditionalpageone: [ { path: '/sections/traditionalpageone/dc.title', message: 'error.validation.required' }, { path: '/sections/traditionalpageone/dc.date.issued', message: 'error.validation.required' } ] }; -export const mockLicenseParsedErrors: any = { +export const mockLicenseParsedErrors: any = { license: [ { path: '/sections/license', message: 'error.validation.license.notgranted' } ] @@ -124,20 +127,18 @@ export const mockSubmissionRestResponse = [ content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', format: [], bundleName: null, - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425', id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', type: 'bitstream', name: null, metadata: [], _links: { - content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', - format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format', - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' + content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' }, + format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' } } } ], - self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', id: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', uuid: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', type: 'collection', @@ -180,10 +181,10 @@ export const mockSubmissionRestResponse = [ } ], _links: { - license: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license', - defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions', - logo: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo', - self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' + license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' }, + defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' }, + logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' } } } ], @@ -195,17 +196,16 @@ export const mockSubmissionRestResponse = [ isDiscoverable: true, isWithdrawn: false, bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams', - self: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5', id: '6f344222-6980-4738-8192-b808d79af8a5', uuid: '6f344222-6980-4738-8192-b808d79af8a5', type: 'item', name: null, metadata: [], _links: { - bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams', - owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/owningCollection', - templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/templateItemOf', - self: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5' + bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/bitstreams' }, + owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/owningCollection' }, + templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5/templateItemOf' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/6f344222-6980-4738-8192-b808d79af8a5' } } } ], @@ -223,9 +223,9 @@ export const mockSubmissionRestResponse = [ }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, { mandatory: true, @@ -236,9 +236,9 @@ export const mockSubmissionRestResponse = [ }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, { header: 'submit.progressbar.describe.stepone', @@ -246,10 +246,9 @@ export const mockSubmissionRestResponse = [ sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, { header: 'submit.progressbar.describe.steptwo', @@ -257,10 +256,9 @@ export const mockSubmissionRestResponse = [ sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, { header: 'submit.progressbar.upload', @@ -268,10 +266,9 @@ export const mockSubmissionRestResponse = [ sectionType: 'upload', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, { header: 'submit.progressbar.license', @@ -283,31 +280,29 @@ export const mockSubmissionRestResponse = [ }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' } ], name: 'traditional', type: 'submissiondefinition', _links: { - collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections', - sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' + collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' }, + sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } ], submitter: [], errors: [], - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826', type: 'workspaceitem', _links: { - collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection', - item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item', - submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition', - submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter', - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' + collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' }, + item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' }, + submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' }, + submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' } } } ]; @@ -329,10 +324,9 @@ export const mockSubmissionObject = { groupUUID: '11cc35e5-a11d-4b64-b5b9-0052a5d15509', id: 20, uuid: 'resource-policy-20', - self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20', type: 'resourcePolicy', _links: { - self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' + self: { href: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' } } } ] @@ -342,19 +336,17 @@ export const mockSubmissionObject = { content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format', bundleName: null, - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425', id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', type: 'bitstream', name: null, metadata: [], _links: { - content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', - format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format', - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' + content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' }, + format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' } } }, - self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', id: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', uuid: '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb', type: 'collection', @@ -397,10 +389,10 @@ export const mockSubmissionObject = { } ], _links: { - license: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license', - defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions', - logo: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo', - self: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' + license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' }, + defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' }, + logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb' } } }, item: { @@ -419,17 +411,16 @@ export const mockSubmissionObject = { }, page: [] }, - self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270', id: 'cae8af78-c874-4468-af79-e6c996aa8270', uuid: 'cae8af78-c874-4468-af79-e6c996aa8270', type: 'item', name: null, metadata: [], _links: { - bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams', - owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection', - templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf', - self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' + bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams' }, + owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection' }, + templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' } } }, submissionDefinition: { @@ -451,9 +442,9 @@ export const mockSubmissionObject = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, { header: 'submit.progressbar.describe.stepone', @@ -461,10 +452,9 @@ export const mockSubmissionObject = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, { header: 'submit.progressbar.describe.steptwo', @@ -472,10 +462,9 @@ export const mockSubmissionObject = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, { header: 'submit.progressbar.upload', @@ -483,10 +472,9 @@ export const mockSubmissionObject = { sectionType: 'upload', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, { header: 'submit.progressbar.license', @@ -498,20 +486,19 @@ export const mockSubmissionObject = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' } ] }, name: 'traditional', type: 'submissiondefinition', _links: { - collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections', - sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' + collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' }, + sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional', collections: { pageInfo: { elementsPerPage: 0, @@ -531,7 +518,6 @@ export const mockSubmissionObject = { email: 'dspacedemo+submit@gmail.com', requireCertificate: false, selfRegistered: false, - self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5', id: '99423c27-b642-5tg6-a9cd-6d910e68dca5', uuid: '99423c27-b642-5tg6-a9cd-6d910e68dca5', type: 'eperson', @@ -549,7 +535,7 @@ export const mockSubmissionObject = { } ], _links: { - self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5' + self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-5tg6-a9cd-6d910e68dca5' } } }, id: 826, @@ -573,14 +559,13 @@ export const mockSubmissionObject = { ] } ], - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826', type: 'workspaceitem', _links: { - collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection', - item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item', - submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition', - submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter', - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' + collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' }, + item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' }, + submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' }, + submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' } } }; @@ -601,10 +586,9 @@ export const mockSubmissionObjectNew = { groupUUID: '11cc35e5-a11d-4b64-b5b9-0052a5d15509', id: 20, uuid: 'resource-policy-20', - self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20', type: 'resourcePolicy', _links: { - self: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' + self: { href: 'https://rest.api/dspace-spring-rest/api/authz/resourcePolicies/20' } } } ] @@ -614,19 +598,17 @@ export const mockSubmissionObjectNew = { content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format', bundleName: null, - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425', id: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', uuid: '3f859425-ffbd-4b0e-bf91-bfeb458a7425', type: 'bitstream', name: null, metadata: [], _links: { - content: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content', - format: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format', - self: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' + content: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/content' }, + format: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425/format' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/bitstreams/3f859425-ffbd-4b0e-bf91-bfeb458a7425' } } }, - self: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb', id: '45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb', uuid: '45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb', type: 'collection', @@ -669,10 +651,10 @@ export const mockSubmissionObjectNew = { } ], _links: { - license: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/license', - defaultAccessConditions: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions', - logo: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo', - self: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb' + license: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/license' }, + defaultAccessConditions: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/defaultAccessConditions' }, + logo: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb/logo' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/collections/45f2f3f1-ba1f-4f36-908a-3f1ea9a557eb' } } }, item: { @@ -691,17 +673,16 @@ export const mockSubmissionObjectNew = { }, page: [] }, - self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270', id: 'cae8af78-c874-4468-af79-e6c996aa8270', uuid: 'cae8af78-c874-4468-af79-e6c996aa8270', type: 'item', name: null, metadata: [], _links: { - bitstreams: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams', - owningCollection: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection', - templateItemOf: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf', - self: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' + bitstreams: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/bitstreams' }, + owningCollection: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/owningCollection' }, + templateItemOf: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270/templateItemOf' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/core/items/cae8af78-c874-4468-af79-e6c996aa8270' } } }, submissionDefinition: { @@ -723,9 +704,9 @@ export const mockSubmissionObjectNew = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, { header: 'submit.progressbar.describe.stepone', @@ -733,10 +714,9 @@ export const mockSubmissionObjectNew = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, { header: 'submit.progressbar.describe.steptwo', @@ -744,10 +724,9 @@ export const mockSubmissionObjectNew = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, { header: 'submit.progressbar.upload', @@ -755,10 +734,9 @@ export const mockSubmissionObjectNew = { sectionType: 'upload', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, { header: 'submit.progressbar.license', @@ -770,20 +748,19 @@ export const mockSubmissionObjectNew = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' } ] }, name: 'traditionaltwo', type: 'submissiondefinition', _links: { - collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections', - sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' + collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' }, + sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional', collections: { pageInfo: { elementsPerPage: 0, @@ -803,7 +780,6 @@ export const mockSubmissionObjectNew = { email: 'dspacedemo+submit@gmail.com', requireCertificate: false, selfRegistered: false, - self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5', id: '99423c27-b642-4bb9-a9cd-45gh23e68dca5', uuid: '99423c27-b642-4bb9-a9cd-45gh23e68dca5', type: 'eperson', @@ -821,21 +797,20 @@ export const mockSubmissionObjectNew = { } ], _links: { - self: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5' + self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/epersons/99423c27-b642-4bb9-a9cd-45gh23e68dca5' } } }, id: 826, lastModified: '2019-01-09T10:17:33.738+0000', sections: {}, errors: [], - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826', type: 'workspaceitem', _links: { - collection: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection', - item: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item', - submissionDefinition: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition', - submitter: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter', - self: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' + collection: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/collection' }, + item: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/item' }, + submissionDefinition: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submissionDefinition' }, + submitter: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826/submitter' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826' } } }; @@ -857,9 +832,9 @@ export const mockSubmissionDefinitionResponse = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, { mandatory: true, @@ -870,9 +845,9 @@ export const mockSubmissionDefinitionResponse = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, { header: 'submit.progressbar.describe.stepone', @@ -880,10 +855,9 @@ export const mockSubmissionDefinitionResponse = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, { header: 'submit.progressbar.describe.steptwo', @@ -891,10 +865,9 @@ export const mockSubmissionDefinitionResponse = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, { header: 'submit.progressbar.upload', @@ -902,10 +875,9 @@ export const mockSubmissionDefinitionResponse = { sectionType: 'upload', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, { header: 'submit.progressbar.license', @@ -917,24 +889,23 @@ export const mockSubmissionDefinitionResponse = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' } ], name: 'traditional', type: 'submissiondefinition', _links: { - collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections', - sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' + collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' }, + sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } as any; export const mockSubmissionDefinition: SubmissionDefinitionsModel = { isDefault: true, - sections: new PaginatedList(new PageInfo(),[ + sections: new PaginatedList(new PageInfo(), [ { mandatory: true, sectionType: 'utils', @@ -944,9 +915,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/extraction' }, { mandatory: true, @@ -957,9 +928,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/collection' }, { header: 'submit.progressbar.describe.stepone', @@ -967,10 +938,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpageone' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpageone' }, { header: 'submit.progressbar.describe.steptwo', @@ -978,10 +948,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { sectionType: 'submission-form', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/traditionalpagetwo' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/traditionalpagetwo' }, { header: 'submit.progressbar.upload', @@ -989,10 +958,9 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { sectionType: 'upload', type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload', - config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, + config: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/upload' }, { header: 'submit.progressbar.license', @@ -1004,19 +972,18 @@ export const mockSubmissionDefinition: SubmissionDefinitionsModel = { }, type: 'submissionsection', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' }, + config: '' }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionsections/license' } ]), name: 'traditional', type: 'submissiondefinition', _links: { - collections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections', - sections: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections', - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' + collections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/collections' }, + sections: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional/sections' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissiondefinitions/traditional' } as any; export const mockSubmissionState: SubmissionObjectState = Object.assign({}, { @@ -1321,19 +1288,17 @@ export const mockUploadConfigResponse = { name: 'bitstream-metadata', type: 'submissionform', _links: { - self: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata' + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/bitstream-metadata' }, required: true, maxSize: 536870912, name: 'upload', type: 'submissionupload', _links: { - metadata: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload/metadata', - self: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' + metadata: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload/metadata' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' } }, - self: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload' }; // Clone the object and change one property @@ -1372,15 +1337,14 @@ export const mockAccessConditionOptions = [ export const mockGroup = Object.assign(new Group(), { handle: null, permanent: true, - self: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1', id: '123456-g', uuid: '123456-g', type: 'group', name: 'Anonymous', metadata: [], _links: { - groups: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1/groups', - self: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1' + groups: { href: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1/groups' }, + self: { href: 'https://rest.api/dspace-spring-rest/api/eperson/groups/123456-g1' } }, groups: { pageInfo: { 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 index d7e0b53748..0e5102d538 100644 --- 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 @@ -18,7 +18,7 @@ describe('ClaimedTaskActionsRejectComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, ReactiveFormsModule, TranslateModule.forRoot({ loader: { @@ -75,7 +75,7 @@ describe('ClaimedTaskActionsRejectComponent', () => { expect(span).toBeDefined(); }); - it('should call openRejectModal on reject button click', fakeAsync(() => { + it('should call openRejectModal on reject button click', () => { spyOn(component.rejectForm, 'reset'); const btn = fixture.debugElement.query(By.css('.btn-danger')); btn.nativeElement.click(); @@ -85,9 +85,9 @@ describe('ClaimedTaskActionsRejectComponent', () => { expect(component.modalRef).toBeDefined(); component.modalRef.close() - })); + }); - it('should call confirmReject on form submit', fakeAsync(() => { + it('should call confirmReject on form submit', () => { spyOn(component.reject, 'emit'); const btn = fixture.debugElement.query(By.css('.btn-danger')); @@ -104,5 +104,5 @@ describe('ClaimedTaskActionsRejectComponent', () => { expect(component.reject.emit).toHaveBeenCalled(); }); - })); + }); }); 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 index ac2d911a2c..8950966e26 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.spec.ts @@ -72,7 +72,7 @@ describe('WorkspaceitemActionsComponent', () => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, @@ -128,7 +128,7 @@ describe('WorkspaceitemActionsComponent', () => { expect(btn).toBeDefined(); }); - it('should call confirmDiscard on discard confirmation', fakeAsync(() => { + it('should call confirmDiscard on discard confirmation', () => { mockDataService.delete.and.returnValue(observableOf(true)); spyOn(component, 'reload'); const btn = fixture.debugElement.query(By.css('.btn-danger')); @@ -144,7 +144,7 @@ describe('WorkspaceitemActionsComponent', () => { 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')}); diff --git a/src/app/shared/number-picker/number-picker.component.spec.ts b/src/app/shared/number-picker/number-picker.component.spec.ts index 3703be97df..82d4329bec 100644 --- a/src/app/shared/number-picker/number-picker.component.spec.ts +++ b/src/app/shared/number-picker/number-picker.component.spec.ts @@ -24,7 +24,7 @@ describe('NumberPickerComponent test suite', () => { imports: [ FormsModule, ReactiveFormsModule, - NgbModule.forRoot() + NgbModule ], declarations: [ NumberPickerComponent, diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts index 25232efa1d..4e6e206ddd 100644 --- a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts @@ -1,4 +1,4 @@ -import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, ComponentFactoryResolver, ContentChild, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; import { ListableObject } from '../listable-object.model'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { Context } from '../../../../core/shared/context.model'; @@ -49,7 +49,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit { /** * Directive hook used to place the dynamic child component */ - @ViewChild(ListableObjectDirective) listableObjectDirective: ListableObjectDirective; + @ViewChild(ListableObjectDirective, {static: true}) listableObjectDirective: ListableObjectDirective; constructor(private componentFactoryResolver: ComponentFactoryResolver) { } 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 index 84be0c1b05..5e0c483982 100644 --- 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 @@ -1,23 +1,38 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpClient } from '@angular/common/http'; 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 { Store } from '@ngrx/store'; 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 { ItemDetailPreviewFieldComponent } from './item-detail-preview-field/item-detail-preview-field.component'; -import { FileSizePipe } from '../../../utils/file-size-pipe'; -import { VarDirective } from '../../../utils/var.directive'; +import { of as observableOf } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { FindListOptions } from '../../../../core/data/request.models'; +import { Bitstream } from '../../../../core/shared/bitstream.model'; import { FileService } from '../../../../core/shared/file.service'; import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; -import { HALEndpointServiceStub } from '../../../testing/hal-endpoint-service-stub'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; +import { Item } from '../../../../core/shared/item.model'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { UUIDService } from '../../../../core/shared/uuid.service'; +import { MockTranslateLoader } from '../../../mocks/mock-translate-loader'; +import { NotificationsService } from '../../../notifications/notifications.service'; +import { HALEndpointServiceStub } from '../../../testing/hal-endpoint-service-stub'; +import { createSuccessfulRemoteDataObject$ } from '../../../testing/utils'; +import { FileSizePipe } from '../../../utils/file-size-pipe'; +import { FollowLinkConfig } from '../../../utils/follow-link-config.model'; + +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { VarDirective } from '../../../utils/var.directive'; +import { ItemDetailPreviewFieldComponent } from './item-detail-preview-field/item-detail-preview-field.component'; +import { ItemDetailPreviewComponent } from './item-detail-preview.component'; function getMockFileService(): FileService { return jasmine.createSpyObj('FileService', { @@ -60,6 +75,14 @@ const mockItem: Item = Object.assign(new Item(), { }); describe('ItemDetailPreviewComponent', () => { + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + }, + findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])); + }, + }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -74,7 +97,18 @@ describe('ItemDetailPreviewComponent', () => { declarations: [ItemDetailPreviewComponent, ItemDetailPreviewFieldComponent, TruncatePipe, FileSizePipe, VarDirective], providers: [ { provide: FileService, useValue: getMockFileService() }, - { provide: HALEndpointService, useValue: new HALEndpointServiceStub('workspaceitems') } + { provide: HALEndpointService, useValue: new HALEndpointServiceStub('workspaceitems') }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ItemDetailPreviewComponent, { @@ -88,7 +122,7 @@ describe('ItemDetailPreviewComponent', () => { component.object = { hitHighlights: {} } as any; component.item = mockItem; component.separator = ', '; - spyOn(component.item, 'getFiles').and.returnValue(mockItem.bundles as any); + // spyOn(component.item, 'getFiles').and.returnValue(mockItem.bundles as any); fixture.detectChanges(); })); 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 9a8f5ebeec..859a13c0ac 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 @@ -1,9 +1,18 @@ import { Component, Input } from '@angular/core'; import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; +import { first, map } from 'rxjs/operators'; +import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; +import { RemoteData } from '../../../../core/data/remote-data'; import { Item } from '../../../../core/shared/item.model'; +import { + getAllSucceededRemoteListPayload, + getFirstSucceededRemoteDataPayload, + getFirstSucceededRemoteListPayload, + getRemoteDataPayload, + getSucceededRemoteData +} from '../../../../core/shared/operators'; 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'; @@ -64,15 +73,16 @@ export class ItemDetailPreviewComponent { * @param {HALEndpointService} halService */ constructor(private fileService: FileService, - private halService: HALEndpointService) { + private halService: HALEndpointService, + private bitstreamDataService: BitstreamDataService) { } /** * Initialize all instance variables */ ngOnInit() { - this.thumbnail$ = this.item.getThumbnail(); - this.bitstreams$ = this.item.getFiles(); + this.thumbnail$ = this.getThumbnail(); + this.bitstreams$ = this.getFiles(); } /** @@ -86,4 +96,20 @@ export class ItemDetailPreviewComponent { this.fileService.downloadFile(fileUrl); }); } + + // TODO refactor this method to return RemoteData, and the template to deal with loading and errors + getThumbnail(): Observable { + return this.bitstreamDataService.getThumbnailFor(this.item).pipe( + getFirstSucceededRemoteDataPayload() + ); + } + + // TODO refactor this method to return RemoteData, and the template to deal with loading and errors + getFiles(): Observable { + return this.bitstreamDataService + .findAllByItemAndBundleName(this.item, 'ORIGINAL', { elementsPerPage: Number.MAX_SAFE_INTEGER }) + .pipe( + getFirstSucceededRemoteListPayload() + ); + } } diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts index 170ca34b42..719341a286 100644 --- a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts @@ -1,11 +1,11 @@ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; - -import { GridThumbnailComponent } from './grid-thumbnail.component'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; import { Bitstream } from '../../../core/shared/bitstream.model'; import { SafeUrlPipe } from '../../utils/safe-url-pipe'; +import { GridThumbnailComponent } from './grid-thumbnail.component'; + describe('GridThumbnailComponent', () => { let comp: GridThumbnailComponent; let fixture: ComponentFixture; @@ -26,14 +26,22 @@ describe('GridThumbnailComponent', () => { }); it('should display image', () => { - comp.thumbnail = new Bitstream(); - comp.thumbnail.content = 'test.url'; + const thumbnail = new Bitstream(); + thumbnail._links = { + self: { href: 'self.url' }, + bundle: { href: 'bundle.url' }, + format: { href: 'format.url' }, + content: { href: 'content.url' }, + }; + comp.thumbnail = thumbnail; fixture.detectChanges(); const image: HTMLElement = de.query(By.css('img')).nativeElement; - expect(image.getAttribute('src')).toBe(comp.thumbnail.content); + expect(image.getAttribute('src')).toBe(comp.thumbnail._links.content.href); }); it('should display placeholder', () => { + const thumbnail = new Bitstream(); + comp.thumbnail = thumbnail; fixture.detectChanges(); const image: HTMLElement = de.query(By.css('img')).nativeElement; expect(image.getAttribute('src')).toBe(comp.defaultImage); diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts index 6ae0c2d37e..4622483f2f 100644 --- a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts @@ -30,8 +30,8 @@ export class GridThumbnailComponent implements OnInit { } ngOnInit(): void { - if (hasValue(this.thumbnail) && this.thumbnail.content) { - this.src = this.thumbnail.content; + if (hasValue(this.thumbnail) && hasValue(this.thumbnail._links) && this.thumbnail._links.content.href) { + this.src = this.thumbnail._links.content.href; } else { this.src = this.defaultImage } 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 07f3960d55..c14e3f6df1 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 @@ -1,12 +1,22 @@ -import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { of as observableOf } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Store } from '@ngrx/store'; +import { of as observableOf } from 'rxjs'; +import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service'; import { Collection } from '../../../../core/shared/collection.model'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; +import { UUIDService } from '../../../../core/shared/uuid.service'; +import { NotificationsService } from '../../../notifications/notifications.service'; import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component'; let collectionSearchResultGridElementComponent: CollectionSearchResultGridElementComponent; let fixture: ComponentFixture; @@ -47,7 +57,17 @@ describe('CollectionSearchResultGridElementComponent', () => { declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) } + { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, ], schemas: [ NO_ERRORS_SCHEMA ] 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 567b2e1d0e..0ea72b52d5 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 @@ -1,12 +1,22 @@ -import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { of as observableOf } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Store } from '@ngrx/store'; +import { of as observableOf } from 'rxjs'; +import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../core/cache/object-cache.service'; +import { CommunityDataService } from '../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service'; import { Community } from '../../../../core/shared/community.model'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; +import { UUIDService } from '../../../../core/shared/uuid.service'; +import { NotificationsService } from '../../../notifications/notifications.service'; import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component'; let communitySearchResultGridElementComponent: CommunitySearchResultGridElementComponent; let fixture: ComponentFixture; @@ -47,7 +57,17 @@ describe('CommunitySearchResultGridElementComponent', () => { declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) } + { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, ], schemas: [ NO_ERRORS_SCHEMA ] diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html index a00e30cbcd..41c16c6eab 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html @@ -3,13 +3,13 @@
- +
- +
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts index 69e50c7300..47531e044c 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts @@ -1,15 +1,29 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TruncatePipe } from '../../../../utils/truncate.pipe'; -import { TruncatableService } from '../../../../truncatable/truncatable.service'; +import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs/internal/Observable'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; -import { Item } from '../../../../../core/shared/item.model'; -import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils'; +import { RemoteDataBuildService } from '../../../../../core/cache/builders/remote-data-build.service'; +import { ObjectCacheService } from '../../../../../core/cache/object-cache.service'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { CommunityDataService } from '../../../../../core/data/community-data.service'; +import { DefaultChangeAnalyzer } from '../../../../../core/data/default-change-analyzer.service'; +import { DSOChangeAnalyzer } from '../../../../../core/data/dso-change-analyzer.service'; import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { HALEndpointService } from '../../../../../core/shared/hal-endpoint.service'; +import { Item } from '../../../../../core/shared/item.model'; import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { UUIDService } from '../../../../../core/shared/uuid.service'; +import { NotificationsService } from '../../../../notifications/notifications.service'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils'; +import { TruncatableService } from '../../../../truncatable/truncatable.service'; +import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { PublicationSearchResultGridElementComponent } from './publication-search-result-grid-element.component'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); @@ -78,12 +92,29 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet isCollapsed: (id: number) => observableOf(true), }; + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], declarations: [component, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, + { provide: ObjectCacheService, useValue: {} }, + { provide: UUIDService, useValue: {} }, + { provide: Store, useValue: {} }, + { provide: RemoteDataBuildService, useValue: {} }, + { provide: CommunityDataService, useValue: {} }, + { provide: HALEndpointService, useValue: {} }, + { provide: HttpClient, useValue: {} }, + { provide: DSOChangeAnalyzer, useValue: {} }, + { provide: NotificationsService, useValue: {} }, + { provide: DefaultChangeAnalyzer, useValue: {} }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(component, { diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss index dc9f9b3969..efc4d3c414 100644 --- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss @@ -1,5 +1,5 @@ :host { - /deep/ em { + ::ng-deep em { font-weight: bold; font-style: normal; } 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 8587e91302..dc05f78e40 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 @@ -1,12 +1,15 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; import { SearchResult } from '../../search/search-result.model'; +import { BitstreamDataService } from '../../../core/data/bitstream-data.service'; +import { Bitstream } from '../../../core/shared/bitstream.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { Metadata } from '../../../core/shared/metadata.utils'; +import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; +import { hasValue } from '../../empty.util'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; import { TruncatableService } from '../../truncatable/truncatable.service'; -import { Observable } from 'rxjs'; -import { Metadata } from '../../../core/shared/metadata.utils'; -import { hasValue } from '../../empty.util'; @Component({ selector: 'ds-search-result-grid-element', @@ -24,7 +27,10 @@ export class SearchResultGridElementComponent, K exten */ isCollapsed$: Observable; - public constructor(protected truncatableService: TruncatableService) { + public constructor( + protected truncatableService: TruncatableService, + protected bitstreamDataService: BitstreamDataService + ) { super(); if (hasValue(this.object)) { this.isCollapsed$ = this.isCollapsed(); @@ -63,4 +69,11 @@ export class SearchResultGridElementComponent, K exten private isCollapsed(): Observable { return this.truncatableService.isCollapsed(this.dso.id); } + + // TODO refactor to return RemoteData, and thumbnail template to deal with loading + getThumbnail(): Observable { + return this.bitstreamDataService.getThumbnailFor(this.dso as any).pipe( + getFirstSucceededRemoteDataPayload() + ); + } } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html index 782c5f9e56..ced2846b4b 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html @@ -1,6 +1,11 @@ - - - + + + + + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts index f5521001ff..9cbbd666cd 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts @@ -3,14 +3,18 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; +import { take } from 'rxjs/operators'; +import { LinkService } from '../../../../core/cache/builders/link.service'; +import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; +import { getMockLinkService } from '../../../mocks/mock-link-service'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; -import { WorkflowItemSearchResultListElementComponent } from './workflow-item-search-result-list-element.component'; import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { WorkflowItemSearchResultListElementComponent } from './workflow-item-search-result-list-element.component'; let component: WorkflowItemSearchResultListElementComponent; let fixture: ComponentFixture; @@ -52,13 +56,18 @@ const item = Object.assign(new Item(), { const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkflowItem(), { item: observableOf(rd) }); +let linkService; + describe('WorkflowItemSearchResultListElementComponent', () => { beforeEach(async(() => { + linkService = getMockLinkService(); TestBed.configureTestingModule({ imports: [NoopAnimationsModule], declarations: [WorkflowItemSearchResultListElementComponent], providers: [ { provide: TruncatableService, useValue: {} }, + { provide: ItemDataService, useValue: {} }, + { provide: LinkService, useValue: linkService }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(WorkflowItemSearchResultListElementComponent, { @@ -76,8 +85,12 @@ describe('WorkflowItemSearchResultListElementComponent', () => { fixture.detectChanges(); }); - it('should init item properly', () => { - expect(component.item).toEqual(item); + it('should init item properly', (done) => { + component.item$.pipe(take(1)).subscribe((i) => { + expect(linkService.resolveLink).toHaveBeenCalled(); + expect(i).toBe(item); + done(); + }); }); it('should have properly status', () => { diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts index faf03425f0..432f69f28c 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts @@ -1,16 +1,19 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; -import { find } from 'rxjs/operators'; +import { find, map } from 'rxjs/operators'; +import { LinkService } from '../../../../core/cache/builders/link.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { Item } from '../../../../core/shared/item.model'; import { ViewMode } from '../../../../core/shared/view-mode.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { isNotUndefined } from '../../../empty.util'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; -import { Item } from '../../../../core/shared/item.model'; -import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { isNotUndefined } from '../../../empty.util'; import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { followLink } from '../../../utils/follow-link-config.model'; import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; /** @@ -28,18 +31,26 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi /** * The item object that belonging to the result object */ - public item: Item; + public item$: Observable; /** * Represent item's status */ public status = MyDspaceItemStatusType.WORKFLOW; + constructor( + protected truncatableService: TruncatableService, + protected linkService: LinkService + ) { + super(truncatableService); + } + /** * Initialize all instance variables */ ngOnInit() { super.ngOnInit(); + this.linkService.resolveLink(this.dso, followLink('item')); this.initItem(this.dso.item as Observable> ); } @@ -47,11 +58,10 @@ export class WorkflowItemSearchResultListElementComponent extends SearchResultLi * Retrieve item from result object */ initItem(item$: Observable>) { - item$.pipe( - find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) - ).subscribe((rd: RemoteData) => { - this.item = rd.payload; - }); + this.item$ = item$.pipe( + find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)), + map((rd: RemoteData) => rd.payload) + ); } } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html index 79a31770d6..8966b4b1d8 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html @@ -1,7 +1,11 @@ - + + - + + + diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts index faf4a3b1be..441800c8db 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts @@ -3,14 +3,18 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; +import { take } from 'rxjs/operators'; +import { LinkService } from '../../../../core/cache/builders/link.service'; +import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; -import { WorkspaceItemSearchResultListElementComponent } from './workspace-item-search-result-list-element.component'; import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; +import { getMockLinkService } from '../../../mocks/mock-link-service'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { WorkspaceItemSearchResultListElementComponent } from './workspace-item-search-result-list-element.component'; let component: WorkspaceItemSearchResultListElementComponent; let fixture: ComponentFixture; @@ -51,14 +55,18 @@ const item = Object.assign(new Item(), { }); const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd) }); +let linkService; describe('WorkspaceItemSearchResultListElementComponent', () => { beforeEach(async(() => { + linkService = getMockLinkService(); TestBed.configureTestingModule({ imports: [NoopAnimationsModule], declarations: [WorkspaceItemSearchResultListElementComponent], providers: [ { provide: TruncatableService, useValue: {} }, + { provide: ItemDataService, useValue: {} }, + { provide: LinkService, useValue: linkService }, ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(WorkspaceItemSearchResultListElementComponent, { @@ -76,8 +84,12 @@ describe('WorkspaceItemSearchResultListElementComponent', () => { fixture.detectChanges(); }); - it('should init item properly', () => { - expect(component.item).toEqual(item); + it('should init item properly', (done) => { + component.item$.pipe(take(1)).subscribe((i) => { + expect(linkService.resolveLink).toHaveBeenCalled(); + expect(i).toBe(item); + done(); + }); }); it('should have properly status', () => { diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts index 830726c677..b9d89ef6ab 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts @@ -1,16 +1,19 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; -import { find } from 'rxjs/operators'; +import { find, map } from 'rxjs/operators'; +import { LinkService } from '../../../../core/cache/builders/link.service'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { Item } from '../../../../core/shared/item.model'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; -import { RemoteData } from '../../../../core/data/remote-data'; 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'; import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkspaceItemSearchResult } from '../../../object-collection/shared/workspace-item-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; +import { followLink } from '../../../utils/follow-link-config.model'; import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; /** @@ -28,18 +31,26 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResultL /** * The item object that belonging to the result object */ - item: Item; + item$: Observable; /** * Represent item's status */ status = MyDspaceItemStatusType.WORKSPACE; + constructor( + protected truncatableService: TruncatableService, + protected linkService: LinkService + ) { + super(truncatableService); + } + /** * Initialize all instance variables */ ngOnInit() { super.ngOnInit(); + this.linkService.resolveLink(this.dso, followLink('item')); this.initItem(this.dso.item as Observable>); } @@ -47,10 +58,9 @@ export class WorkspaceItemSearchResultListElementComponent extends SearchResultL * Retrieve item from result object */ initItem(item$: Observable>) { - item$.pipe( - find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) - ).subscribe((rd: RemoteData) => { - this.item = rd.payload; - }); + this.item$ = item$.pipe( + find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)), + map((rd: RemoteData) => rd.payload) + ); } } diff --git a/src/app/shared/object.util.ts b/src/app/shared/object.util.ts index 60ed71096a..02f7c54e1d 100644 --- a/src/app/shared/object.util.ts +++ b/src/app/shared/object.util.ts @@ -5,7 +5,7 @@ import { isEqual, isObject, transform } from 'lodash'; * Returns passed object without specified property */ export function deleteProperty(object: object, key: string): object { - const {[key]: deletedKey, ...otherKeys} = object; + const { [key]: deletedKey, ...otherKeys } = object as { [key: string]: any }; return otherKeys; } @@ -47,7 +47,7 @@ export function difference(object: object, base: object) { const changes = (o, b) => { return transform(o, (result, value, key) => { if (!isEqual(value, b[key]) && isNotEmpty(value)) { - const resultValue = (isObject(value) && isObject(b[key])) ? changes(value, b[key]) : value; + const resultValue = (isObject(value) && isObject(b[key])) ? changes(value, b[key]) : value as object; if (!hasOnlyEmptyProperties(resultValue)) { result[key] = resultValue; } diff --git a/src/app/shared/pagination/pagination.component.spec.ts b/src/app/shared/pagination/pagination.component.spec.ts index dfbef9123a..949ebc85d3 100644 --- a/src/app/shared/pagination/pagination.component.spec.ts +++ b/src/app/shared/pagination/pagination.component.spec.ts @@ -139,7 +139,7 @@ describe('Pagination component', () => { } }), NgxPaginationModule, - NgbModule.forRoot(), + NgbModule, RouterTestingModule.withRoutes([ { path: 'home', component: TestComponent } ])], diff --git a/src/app/shared/search-form/search-form.component.spec.ts b/src/app/shared/search-form/search-form.component.spec.ts index 74ed4bb913..ffd8dd87a2 100644 --- a/src/app/shared/search-form/search-form.component.spec.ts +++ b/src/app/shared/search-form/search-form.component.spec.ts @@ -124,7 +124,11 @@ export const objects: DSpaceObject[] = [ scheduler: null } }, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f', + _links: { + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f', + }, + }, id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f', uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f', type: Community.type, @@ -178,7 +182,11 @@ export const objects: DSpaceObject[] = [ scheduler: null } }, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863', + _links: { + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863', + }, + }, id: '9076bd16-e69a-48d6-9e41-0238cb40d863', uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863', type: Community.type, diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts index c49353deb3..97541c4786 100644 --- a/src/app/shared/search-form/search-form.component.ts +++ b/src/app/shared/search-form/search-form.component.ts @@ -1,9 +1,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; 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'; +import { isNotEmpty } from '../empty.util'; import { SearchService } from '../../core/shared/search/search.service'; import { currentPath } from '../utils/route.utils'; diff --git a/src/app/shared/search/facet-value.model.ts b/src/app/shared/search/facet-value.model.ts index d2cc521356..032f9c9b2a 100644 --- a/src/app/shared/search/facet-value.model.ts +++ b/src/app/shared/search/facet-value.model.ts @@ -1,9 +1,11 @@ -import { autoserialize, autoserializeAs } from 'cerialize'; +import { autoserialize, autoserializeAs, deserialize } from 'cerialize'; +import { HALLink } from '../../core/shared/hal-link.model'; +import { HALResource } from '../../core/shared/hal-resource.model'; /** * Class representing possible values for a certain filter */ -export class FacetValue { +export class FacetValue implements HALResource { /** * The display label of the facet value */ @@ -23,8 +25,11 @@ export class FacetValue { count: number; /** - * The REST url to add this filter value + * The {@link HALLink}s for this FacetValue */ - @autoserialize - search: string; + @deserialize + _links: { + self: HALLink + search: HALLink + } } diff --git a/src/app/shared/search/normalized-search-result.model.ts b/src/app/shared/search/normalized-search-result.model.ts deleted file mode 100644 index 3904b4a494..0000000000 --- a/src/app/shared/search/normalized-search-result.model.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { autoserialize, inheritSerialization } from 'cerialize'; -import { MetadataMap } from '../../core/shared/metadata.models'; -import { NormalizedObject } from '../../core/cache/models/normalized-object.model'; - -/** - * Represents a normalized version of a search result object of a certain DSpaceObject - */ -@inheritSerialization(NormalizedObject) -export class NormalizedSearchResult { - /** - * The UUID of the DSpaceObject that was found - */ - @autoserialize - indexableObject: string; - - /** - * The metadata that was used to find this item, hithighlighted - */ - @autoserialize - hitHighlights: MetadataMap; -} diff --git a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts index 99e9bfac2e..5dc930f67f 100644 --- a/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-authority-filter/search-authority-filter.component.ts @@ -23,7 +23,7 @@ export class SearchAuthorityFilterComponent extends SearchFacetFilterComponent i * Retrieve facet value from search link */ protected getFacetValue(facet: FacetValue): string { - const search = facet.search; + const search = facet._links.search.href; const hashes = search.slice(search.indexOf('?') + 1).split('&'); const params = {}; hashes.map((hash) => { diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts index ff5db664db..43f47cc2b9 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.spec.ts @@ -1,20 +1,20 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFacetOptionComponent } from './search-facet-option.component'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; -import { FilterType } from '../../../../filter-type.model'; -import { FacetValue } from '../../../../facet-value.model'; import { FormsModule } from '@angular/forms'; -import { of as observableOf } from 'rxjs'; -import { SearchService } from '../../../../../../core/shared/search/search.service'; -import { SearchServiceStub } from '../../../../../testing/search-service-stub'; +import { By } from '@angular/platform-browser'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; -import { RouterStub } from '../../../../../testing/router-stub'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; -import { By } from '@angular/platform-browser'; +import { SearchService } from '../../../../../../core/shared/search/search.service'; +import { RouterStub } from '../../../../../testing/router-stub'; +import { SearchServiceStub } from '../../../../../testing/search-service-stub'; +import { FacetValue } from '../../../../facet-value.model'; +import { FilterType } from '../../../../filter-type.model'; +import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { SearchFacetOptionComponent } from './search-facet-option.component'; describe('SearchFacetOptionComponent', () => { let comp: SearchFacetOptionComponent; @@ -47,21 +47,30 @@ describe('SearchFacetOptionComponent', () => { label: value2, value: value2, count: 20, - search: `` + _links: { + self: { href: 'selectedValue-self-link2' }, + search: { href: `` } + } }; const selectedValue: FacetValue = { label: value1, value: value1, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1},${operator}` + _links: { + self: { href: 'selectedValue-self-link1' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1},${operator}` } + } }; const authorityValue: FacetValue = { label: value2, value: value2, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` + _links: { + self: { href: 'authorityValue-self-link2' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` } + } }; const searchLink = '/search'; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts index 512cd5501c..04e810edda 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts @@ -113,7 +113,7 @@ export class SearchFacetOptionComponent implements OnInit, OnDestroy { */ private getFacetValue(): string { if (this.filterConfig.type === FilterType.authority) { - const search = this.filterValue.search; + const search = this.filterValue._links.search.href; const hashes = search.slice(search.indexOf('?') + 1).split('&'); const params = {}; hashes.map((hash) => { diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts index e6878dadd1..34fb64040c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.spec.ts @@ -38,7 +38,14 @@ describe('SearchFacetRangeOptionComponent', () => { label: value2, value: value2, count: 20, - search: '' + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } }; const searchLink = '/search'; @@ -96,7 +103,14 @@ describe('SearchFacetRangeOptionComponent', () => { label: '50-60', value: '50-60', count: 20, - search: '' + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } }; (comp as any).updateChangeParams(); expect(comp.changeQueryParams).toEqual({ diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts index 4ea6571a87..cfeda7d51c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.spec.ts @@ -1,19 +1,19 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { SearchFilterConfig } from '../../../../search-filter-config.model'; -import { FilterType } from '../../../../filter-type.model'; import { FormsModule } from '@angular/forms'; -import { of as observableOf } from 'rxjs'; -import { SearchService } from '../../../../../../core/shared/search/search.service'; -import { SearchServiceStub } from '../../../../../testing/search-service-stub'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { Router } from '@angular/router'; -import { RouterStub } from '../../../../../testing/router-stub'; +import { TranslateModule } from '@ngx-translate/core'; +import { of as observableOf } from 'rxjs'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; import { SearchFilterService } from '../../../../../../core/shared/search/search-filter.service'; -import { SearchFacetSelectedOptionComponent } from './search-facet-selected-option.component'; +import { SearchService } from '../../../../../../core/shared/search/search.service'; +import { RouterStub } from '../../../../../testing/router-stub'; +import { SearchServiceStub } from '../../../../../testing/search-service-stub'; import { FacetValue } from '../../../../facet-value.model'; +import { FilterType } from '../../../../filter-type.model'; +import { SearchFilterConfig } from '../../../../search-filter-config.model'; +import { SearchFacetSelectedOptionComponent } from './search-facet-selected-option.component'; describe('SearchFacetSelectedOptionComponent', () => { let comp: SearchFacetSelectedOptionComponent; @@ -47,25 +47,37 @@ describe('SearchFacetSelectedOptionComponent', () => { label: value1, value: value1, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1}` + _links: { + self: { href: 'selectedValue-self-link1' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value1}` } + } }; const selectedValue2: FacetValue = { label: value2, value: value2, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2}` + _links: { + self: { href: 'selectedValue-self-link2' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName1}=${value2}` } + } }; const selectedAuthorityValue: FacetValue = { label: label1, value: value1, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value1},${operator}` + _links: { + self: { href: 'selectedAuthorityValue-self-link1' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value1},${operator}` } + } }; const selectedAuthorityValue2: FacetValue = { label: label2, value: value2, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` + _links: { + self: { href: 'selectedAuthorityValue-self-link2' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` } + } }; const selectedValues = [selectedValue, selectedValue2]; const selectedAuthorityValues = [selectedAuthorityValue, selectedAuthorityValue2]; @@ -73,13 +85,19 @@ describe('SearchFacetSelectedOptionComponent', () => { label: value2, value: value2, count: 1, - search: '' + _links: { + self: { href: 'facetValue-self-link2' }, + search: { href: `` } + } }; const authorityValue: FacetValue = { label: label2, value: value2, count: 20, - search: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` + _links: { + self: { href: 'authorityValue-self-link2' }, + search: { href: `http://test.org/api/discover/search/objects?f.${filterName2}=${value2},${operator}` } + } }; const selectedValues$ = observableOf(selectedValues); const selectedAuthorityValues$ = observableOf(selectedAuthorityValues); diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts index 0cf54d88f5..f58a903b0c 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts @@ -102,7 +102,7 @@ export class SearchFacetSelectedOptionComponent implements OnInit, OnDestroy { */ private getFacetValue(facetValue: FacetValue): string { if (this.filterConfig.type === FilterType.authority) { - const search = facetValue.search; + const search = facetValue._links.search.href; const hashes = search.slice(search.indexOf('?') + 1).split('&'); const params = {}; hashes.map((hash) => { diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts index 1b66e29246..7695497750 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.spec.ts @@ -39,17 +39,38 @@ describe('SearchFacetFilterComponent', () => { label: value1, value: value1, count: 52, - search: '' + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } }, { label: value2, value: value2, count: 20, - search: '' + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } }, { label: value3, value: value3, count: 5, - search: '' + _links: { + self: { + href: '' + }, + search: { + href: '' + } + } } ]; diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts index 1d6a85b95b..df0c53f543 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts @@ -320,7 +320,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy { * Prevent unnecessary rerendering */ trackUpdate(index, value: FacetValue) { - return value ? value.search : undefined; + return value ? value._links.search.href : undefined; } } diff --git a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts index 530b4e6b71..72840b3ffe 100644 --- a/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts +++ b/src/app/shared/search/search-filters/search-filter/search-range-filter/search-range-filter.component.spec.ts @@ -45,17 +45,38 @@ describe('SearchRangeFilterComponent', () => { label: value1, value: value1, count: 52, - search: '' + _links: { + self: { + href:'' + }, + search: { + href: '' + } + } }, { label: value2, value: value2, count: 20, - search: '' + _links: { + self: { + href:'' + }, + search: { + href: '' + } + } }, { label: value3, value: value3, count: 5, - search: '' + _links: { + self: { + href:'' + }, + search: { + href: '' + } + } } ]; diff --git a/src/app/shared/search/search-options.model.ts b/src/app/shared/search/search-options.model.ts index 4dc92c32f4..a8b115abd3 100644 --- a/src/app/shared/search/search-options.model.ts +++ b/src/app/shared/search/search-options.model.ts @@ -1,6 +1,5 @@ import { isNotEmpty } from '../empty.util'; import { URLCombiner } from '../../core/url-combiner/url-combiner'; -import 'core-js/library/fn/object/entries'; import { SearchFilter } from './search-filter.model'; import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model'; import { ViewMode } from '../../core/shared/view-mode.model'; diff --git a/src/app/shared/search/search-query-response.model.ts b/src/app/shared/search/search-query-response.model.ts index da15a60631..2c9d11e2b3 100644 --- a/src/app/shared/search/search-query-response.model.ts +++ b/src/app/shared/search/search-query-response.model.ts @@ -1,6 +1,7 @@ import { autoserialize, autoserializeAs } from 'cerialize'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { PageInfo } from '../../core/shared/page-info.model'; -import { NormalizedSearchResult } from './normalized-search-result.model'; +import { SearchResult } from './search-result.model'; /** * Class representing the response returned by the server when performing a search request @@ -51,8 +52,8 @@ export class SearchQueryResponse { /** * The results for this query */ - @autoserializeAs(NormalizedSearchResult) - objects: NormalizedSearchResult[]; + @autoserializeAs(SearchResult) + objects: Array>; @autoserialize facets: any; // TODO diff --git a/src/app/shared/search/search-result.model.ts b/src/app/shared/search/search-result.model.ts index 8d26395021..2f14a60c97 100644 --- a/src/app/shared/search/search-result.model.ts +++ b/src/app/shared/search/search-result.model.ts @@ -1,25 +1,40 @@ +import { autoserialize, deserialize } from 'cerialize'; +import { link } from '../../core/cache/builders/build-decorators'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { MetadataMap } from '../../core/shared/metadata.models'; -import { ListableObject } from '../object-collection/shared/listable-object.model'; -import { excludeFromEquals, fieldsForEquals } from '../../core/utilities/equals.decorators'; +import { DSPACE_OBJECT } from '../../core/shared/dspace-object.resource-type'; import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { HALLink } from '../../core/shared/hal-link.model'; +import { MetadataMap } from '../../core/shared/metadata.models'; +import { excludeFromEquals, fieldsForEquals } from '../../core/utilities/equals.decorators'; +import { ListableObject } from '../object-collection/shared/listable-object.model'; /** * Represents a search result object of a certain () DSpaceObject */ export class SearchResult extends ListableObject { - /** - * The DSpaceObject that was found - */ - @fieldsForEquals('uuid') - indexableObject: T; - /** * The metadata that was used to find this item, hithighlighted */ @excludeFromEquals + @autoserialize hitHighlights: MetadataMap; + /** + * The {@link HALLink}s for this SearchResult + */ + @deserialize + _links: { + self: HALLink; + indexableObject: HALLink; + }; + + /** + * The DSpaceObject that was found + */ + @fieldsForEquals('uuid') + @link(DSPACE_OBJECT) + indexableObject: T; + /** * Method that returns as which type of object this object should be rendered */ diff --git a/src/app/shared/search/search-results/search-results.component.spec.ts b/src/app/shared/search/search-results/search-results.component.spec.ts index d2c02717c9..60e91d6fc1 100644 --- a/src/app/shared/search/search-results/search-results.component.spec.ts +++ b/src/app/shared/search/search-results/search-results.component.spec.ts @@ -111,7 +111,11 @@ export const objects = [ scheduler: null } }, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f', + _links: { + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f', + }, + }, id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f', uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f', type: Community.type, @@ -165,7 +169,11 @@ export const objects = [ scheduler: null } }, - self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863', + _links: { + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863', + }, + }, id: '9076bd16-e69a-48d6-9e41-0238cb40d863', uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863', type: Community.type, diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts index 6586254227..f05b33ff88 100644 --- a/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts +++ b/src/app/shared/search/search-sidebar/search-sidebar.component.spec.ts @@ -12,7 +12,7 @@ describe('SearchSidebarComponent', () => { // async beforeEach beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NgbCollapseModule.forRoot()], + imports: [TranslateModule.forRoot(), NgbCollapseModule], declarations: [SearchSidebarComponent], schemas: [NO_ERRORS_SCHEMA], }) diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 378387b6dd..22e7b06c8c 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -68,7 +68,6 @@ import { DsDynamicFormGroupComponent } from './form/builder/ds-dynamic-form-ui/m import { DsDynamicFormArrayComponent } from './form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component'; import { DsDynamicRelationGroupComponent } from './form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.components'; import { DsDatePickerInlineComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker-inline/dynamic-date-picker-inline.component'; -import { SortablejsModule } from 'angular-sortablejs'; import { NumberPickerComponent } from './number-picker/number-picker.component'; import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component'; import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; @@ -179,6 +178,7 @@ import { ExternalSourceEntryImportModalComponent } from './form/builder/ds-dynam import { ImportableListItemControlComponent } from './object-collection/shared/importable-list-item-control/importable-list-item-control.component'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; +import { SortablejsModule } from 'ngx-sortablejs'; import { LogInContainerComponent } from './log-in/container/log-in-container.component'; import { LogInShibbolethComponent } from './log-in/methods/shibboleth/log-in-shibboleth.component'; import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component'; diff --git a/src/app/shared/starts-with/date/starts-with-date.component.spec.ts b/src/app/shared/starts-with/date/starts-with-date.component.spec.ts index 88a1099072..533724f5cb 100644 --- a/src/app/shared/starts-with/date/starts-with-date.component.spec.ts +++ b/src/app/shared/starts-with/date/starts-with-date.component.spec.ts @@ -27,7 +27,7 @@ describe('StartsWithDateComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()], + imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule], declarations: [StartsWithDateComponent, EnumKeysPipe], providers: [ { provide: 'startsWithOptions', useValue: options }, diff --git a/src/app/shared/starts-with/text/starts-with-text.component.spec.ts b/src/app/shared/starts-with/text/starts-with-text.component.spec.ts index 590b46f6de..bc9c21aab8 100644 --- a/src/app/shared/starts-with/text/starts-with-text.component.spec.ts +++ b/src/app/shared/starts-with/text/starts-with-text.component.spec.ts @@ -19,7 +19,7 @@ describe('StartsWithTextComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()], + imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule], declarations: [StartsWithTextComponent, EnumKeysPipe], providers: [ { provide: 'startsWithOptions', useValue: options } diff --git a/src/app/shared/testing/eperson-mock.ts b/src/app/shared/testing/eperson-mock.ts index c822fc15d6..44585f278f 100644 --- a/src/app/shared/testing/eperson-mock.ts +++ b/src/app/shared/testing/eperson-mock.ts @@ -9,7 +9,11 @@ export const EPersonMock: EPerson = Object.assign(new EPerson(),{ email: 'test@test.com', requireCertificate: false, selfRegistered: false, - self: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/epersons/testid', + _links: { + self: { + href: 'https://dspace.4science.it/dspace-spring-rest/api/eperson/epersons/testid', + } + }, id: 'testid', uuid: 'testid', type: 'eperson', diff --git a/src/app/shared/testing/test-module.ts b/src/app/shared/testing/test-module.ts index 8f59d76c87..f25fda8d72 100644 --- a/src/app/shared/testing/test-module.ts +++ b/src/app/shared/testing/test-module.ts @@ -1,10 +1,10 @@ -import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core'; -import { QueryParamsDirectiveStub } from './query-params-directive-stub'; +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MySimpleItemActionComponent } from '../../+item-page/edit-item-page/simple-item-action/abstract-simple-item-action.component.spec'; -import {CommonModule} from '@angular/common'; -import {SharedModule} from '../shared.module'; -import { RouterLinkDirectiveStub } from './router-link-directive-stub'; +import { SharedModule } from '../shared.module'; import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive-stub'; +import { QueryParamsDirectiveStub } from './query-params-directive-stub'; +import { RouterLinkDirectiveStub } from './router-link-directive-stub'; /** * This module isn't used. It serves to prevent the AoT compiler @@ -26,4 +26,5 @@ import { NgComponentOutletDirectiveStub } from './ng-component-outlet-directive- CUSTOM_ELEMENTS_SCHEMA ] }) -export class TestModule {} +export class TestModule { +} diff --git a/src/app/shared/utils/follow-link-config.model.ts b/src/app/shared/utils/follow-link-config.model.ts new file mode 100644 index 0000000000..21df288690 --- /dev/null +++ b/src/app/shared/utils/follow-link-config.model.ts @@ -0,0 +1,50 @@ +import { FindListOptions } from '../../core/data/request.models'; +import { HALResource } from '../../core/shared/hal-resource.model'; + +/** + * A class to configure the retrieval of a {@link HALLink} + */ +export class FollowLinkConfig { + /** + * The name of the link to fetch. + * Can only be a {@link HALLink} of the object you're working with + */ + name: keyof R['_links']; + + /** + * {@link FindListOptions} for the query, + * allows you to resolve the link using a certain page, or sorted + * in a certain way + */ + findListOptions?: FindListOptions; + + /** + * A list of {@link FollowLinkConfig}s to + * use on the retrieved object. + */ + linksToFollow?: Array>; +} + +/** + * A factory function for {@link FollowLinkConfig}s, + * in order to create them in a less verbose way. + * + * @param linkName: the name of the link to fetch. + * Can only be a {@link HALLink} of the object you're working with + * @param findListOptions: {@link FindListOptions} for the query, + * allows you to resolve the link using a certain page, or sorted + * in a certain way + * @param linksToFollow: a list of {@link FollowLinkConfig}s to + * use on the retrieved object. + */ +export const followLink = ( + linkName: keyof R['_links'], + findListOptions?: FindListOptions, + ...linksToFollow: Array> +): FollowLinkConfig => { + return { + name: linkName, + findListOptions, + linksToFollow + } +}; diff --git a/src/app/submission/form/collection/submission-form-collection.component.spec.ts b/src/app/submission/form/collection/submission-form-collection.component.spec.ts index 8539560d26..ff91d86736 100644 --- a/src/app/submission/form/collection/submission-form-collection.component.spec.ts +++ b/src/app/submission/form/collection/submission-form-collection.component.spec.ts @@ -222,7 +222,7 @@ describe('SubmissionFormCollectionComponent Component', () => { imports: [ FormsModule, ReactiveFormsModule, - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ diff --git a/src/app/submission/form/footer/submission-form-footer.component.spec.ts b/src/app/submission/form/footer/submission-form-footer.component.spec.ts index 5fbfd84cb8..d786faeee8 100644 --- a/src/app/submission/form/footer/submission-form-footer.component.spec.ts +++ b/src/app/submission/form/footer/submission-form-footer.component.spec.ts @@ -34,7 +34,7 @@ describe('SubmissionFormFooterComponent Component', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ @@ -188,7 +188,7 @@ describe('SubmissionFormFooterComponent Component', () => { expect(submissionServiceStub.dispatchDeposit).toHaveBeenCalledWith(submissionId); }); - it('should call dispatchDiscard on discard confirmation', fakeAsync(() => { + it('should call dispatchDiscard on discard confirmation', () => { comp.showDepositAndDiscard = observableOf(true); fixture.detectChanges(); const modalBtn = fixture.debugElement.query(By.css('.btn-danger')); @@ -204,7 +204,7 @@ describe('SubmissionFormFooterComponent Component', () => { fixture.whenStable().then(() => { expect(submissionServiceStub.dispatchDiscard).toHaveBeenCalledWith(submissionId); }); - })); + }); it('should have deposit button disabled when submission is not valid', () => { comp.showDepositAndDiscard = observableOf(true); diff --git a/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts b/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts index 236bd6de9b..5a2978b17c 100644 --- a/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts +++ b/src/app/submission/form/section-add/submission-form-section-add.component.spec.ts @@ -59,7 +59,7 @@ describe('SubmissionFormSectionAddComponent Component', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ diff --git a/src/app/submission/form/submission-form.component.ts b/src/app/submission/form/submission-form.component.ts index 3ea07f9ae7..0b8cfce619 100644 --- a/src/app/submission/form/submission-form.component.ts +++ b/src/app/submission/form/submission-form.component.ts @@ -1,19 +1,19 @@ import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; -import { of as observableOf, Observable, Subscription } from 'rxjs'; -import { distinctUntilChanged, filter, flatMap, map, switchMap } from 'rxjs/operators'; +import { Observable, of as observableOf, Subscription } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; +import { AuthService } from '../../core/auth/auth.service'; +import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model'; +import { Collection } from '../../core/shared/collection.model'; +import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; +import { SubmissionObject } from '../../core/submission/models/submission-object.model'; +import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model'; import { hasValue, isNotEmpty } from '../../shared/empty.util'; -import { SubmissionObjectEntry } from '../objects/submission-objects.reducer'; -import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model'; -import { SubmissionDefinitionsModel } from '../../core/config/models/config-submission-definitions.model'; -import { SubmissionService } from '../submission.service'; -import { AuthService } from '../../core/auth/auth.service'; -import { SectionDataObject } from '../sections/models/section-data.model'; import { UploaderOptions } from '../../shared/uploader/uploader-options.model'; -import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; -import { Collection } from '../../core/shared/collection.model'; -import { SubmissionObject } from '../../core/submission/models/submission-object.model'; +import { SubmissionObjectEntry } from '../objects/submission-objects.reducer'; +import { SectionDataObject } from '../sections/models/section-data.model'; +import { SubmissionService } from '../submission.service'; /** * This component represents the submission form. @@ -189,7 +189,7 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy { this.submissionService.resetSubmissionObject( this.collectionId, this.submissionId, - submissionObject.self, + submissionObject._links.self.href, this.submissionDefinition, this.sections); } else { diff --git a/src/app/submission/objects/submission-objects.actions.ts b/src/app/submission/objects/submission-objects.actions.ts index 9bd88f035a..57226fc531 100644 --- a/src/app/submission/objects/submission-objects.actions.ts +++ b/src/app/submission/objects/submission-objects.actions.ts @@ -796,4 +796,5 @@ export type SubmissionObjectAction = DisableSectionAction | SaveSubmissionSectionFormAction | SaveSubmissionSectionFormSuccessAction | SaveSubmissionSectionFormErrorAction - | SetActiveSectionAction; + | SetActiveSectionAction + | DepositSubmissionAction; diff --git a/src/app/submission/objects/submission-objects.effects.spec.ts b/src/app/submission/objects/submission-objects.effects.spec.ts index 8bbdd4e0ee..40c5cc9dd0 100644 --- a/src/app/submission/objects/submission-objects.effects.spec.ts +++ b/src/app/submission/objects/submission-objects.effects.spec.ts @@ -109,8 +109,8 @@ describe('SubmissionObjectEffects test suite', () => { const mappedActions = []; (submissionDefinitionResponse.sections as SubmissionSectionModel[]) .forEach((sectionDefinition: SubmissionSectionModel) => { - const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1); - const config = sectionDefinition._links.config || ''; + const sectionId = sectionDefinition._links.self.href.substr(sectionDefinition._links.self.href.lastIndexOf('/') + 1); + const config = sectionDefinition._links.config.href || ''; const enabled = (sectionDefinition.mandatory); const sectionData = {}; const sectionErrors = null; diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index ba82fe1e65..a2a3350c6a 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -1,10 +1,24 @@ import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; +import { TranslateService } from '@ngx-translate/core'; +import { union } from 'lodash'; import { from as observableFrom, of as observableOf } from 'rxjs'; import { catchError, map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators'; -import { Store } from '@ngrx/store'; -import { union } from 'lodash'; +import { SubmissionObject } from '../../core/submission/models/submission-object.model'; +import { WorkflowItem } from '../../core/submission/models/workflowitem.model'; +import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model'; +import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model'; +import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model'; +import { SubmissionJsonPatchOperationsService } from '../../core/submission/submission-json-patch-operations.service'; +import { isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { SectionsType } from '../sections/sections-type'; +import { SectionsService } from '../sections/sections.service'; +import { SubmissionState } from '../submission.reducers'; +import { SubmissionService } from '../submission.service'; +import parseSectionErrors from '../utils/parseSectionErrors'; import { CompleteInitSubmissionFormAction, @@ -24,26 +38,12 @@ import { SaveSubmissionFormSuccessAction, SaveSubmissionSectionFormAction, SaveSubmissionSectionFormErrorAction, - SaveSubmissionSectionFormSuccessAction, SubmissionObjectAction, + SaveSubmissionSectionFormSuccessAction, + SubmissionObjectAction, SubmissionObjectActionTypes, UpdateSectionDataAction } from './submission-objects.actions'; -import { SectionsService } from '../sections/sections.service'; -import { isEmpty, isNotEmpty, isNotUndefined } from '../../shared/empty.util'; -import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model'; -import { SubmissionService } from '../submission.service'; -import { WorkflowItem } from '../../core/submission/models/workflowitem.model'; -import { NotificationsService } from '../../shared/notifications/notifications.service'; -import { SubmissionObject } from '../../core/submission/models/submission-object.model'; -import { TranslateService } from '@ngx-translate/core'; -import { SubmissionState } from '../submission.reducers'; import { SubmissionObjectEntry } from './submission-objects.reducer'; -import { SubmissionSectionModel } from '../../core/config/models/config-submission-section.model'; -import parseSectionErrors from '../utils/parseSectionErrors'; -import { WorkspaceitemSectionsObject } from '../../core/submission/models/workspaceitem-sections.model'; -import { WorkspaceitemSectionUploadObject } from '../../core/submission/models/workspaceitem-section-upload.model'; -import { SectionsType } from '../sections/sections-type'; -import { SubmissionJsonPatchOperationsService } from '../../core/submission/submission-json-patch-operations.service'; @Injectable() export class SubmissionObjectEffects { @@ -56,9 +56,10 @@ export class SubmissionObjectEffects { map((action: InitSubmissionFormAction) => { const definition = action.payload.submissionDefinition; const mappedActions = []; - definition.sections.page.forEach((sectionDefinition: SubmissionSectionModel) => { - const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1); - const config = sectionDefinition._links.config || ''; + definition.sections.page.forEach((sectionDefinition: any) => { + const selfLink = sectionDefinition._links.self.href || sectionDefinition._links.self; + const sectionId = selfLink.substr(selfLink.lastIndexOf('/') + 1); + const config = sectionDefinition._links.config ? (sectionDefinition._links.config.href || sectionDefinition._links.config) : ''; const enabled = (sectionDefinition.mandatory) || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId)); const sectionData = (isNotUndefined(action.payload.sections) && isNotUndefined(action.payload.sections[sectionId])) ? action.payload.sections[sectionId] : Object.create(null); const sectionErrors = null; diff --git a/src/app/submission/objects/submission-objects.reducer.spec.ts b/src/app/submission/objects/submission-objects.reducer.spec.ts index a5e0be451b..7fdccf3ebb 100644 --- a/src/app/submission/objects/submission-objects.reducer.spec.ts +++ b/src/app/submission/objects/submission-objects.reducer.spec.ts @@ -22,14 +22,13 @@ import { SaveAndDepositSubmissionAction, SaveForLaterSubmissionFormAction, SaveForLaterSubmissionFormErrorAction, - SaveForLaterSubmissionFormSuccessAction, SaveSubmissionFormAction, SaveSubmissionFormErrorAction, SaveSubmissionFormSuccessAction, SaveSubmissionSectionFormAction, SaveSubmissionSectionFormErrorAction, SaveSubmissionSectionFormSuccessAction, - SectionStatusChangeAction, + SectionStatusChangeAction, SubmissionObjectAction, UpdateSectionDataAction } from './submission-objects.actions'; import { SectionsType } from '../sections/sections-type'; @@ -117,7 +116,7 @@ describe('submissionReducer test suite', () => { }); it('should set to true savePendig flag on save', () => { - let action = new SaveSubmissionFormAction(submissionId); + let action: SubmissionObjectAction = new SaveSubmissionFormAction(submissionId); let newState = submissionObjectReducer(initState, action); expect(newState[826].savePending).toBeTruthy(); @@ -273,7 +272,7 @@ describe('submissionReducer test suite', () => { it('should enable submission section properly', () => { - let action = new EnableSectionAction(submissionId, 'traditionalpagetwo'); + let action: SubmissionObjectAction = new EnableSectionAction(submissionId, 'traditionalpagetwo'); let newState = submissionObjectReducer(initState, action); action = new DisableSectionAction(submissionId, 'traditionalpagetwo'); diff --git a/src/app/submission/objects/submission-objects.reducer.ts b/src/app/submission/objects/submission-objects.reducer.ts index 8c111dde67..e0aeefd7b6 100644 --- a/src/app/submission/objects/submission-objects.reducer.ts +++ b/src/app/submission/objects/submission-objects.reducer.ts @@ -548,7 +548,7 @@ function startDeposit(state: SubmissionObjectState, action: DepositSubmissionAct * @return SubmissionObjectState * the new state, with the deposit flag changed. */ -function endDeposit(state: SubmissionObjectState, action: DepositSubmissionSuccessAction | DepositSubmissionErrorAction): SubmissionObjectState { +function endDeposit(state: SubmissionObjectState, action: DepositSubmissionSuccessAction | DepositSubmissionErrorAction | DepositSubmissionAction): SubmissionObjectState { if (hasValue(state[ action.payload.submissionId ])) { return Object.assign({}, state, { [ action.payload.submissionId ]: Object.assign({}, state[ action.payload.submissionId ], { diff --git a/src/app/submission/sections/container/section-container.component.scss b/src/app/submission/sections/container/section-container.component.scss index 3917280f8c..0255b71dac 100644 --- a/src/app/submission/sections/container/section-container.component.scss +++ b/src/app/submission/sections/container/section-container.component.scss @@ -1,4 +1,4 @@ -:host /deep/ .card { +:host ::ng-deep .card { margin-bottom: $submission-sections-margin-bottom; overflow: unset; } @@ -9,13 +9,13 @@ } // TODO to remove the following when upgrading @ng-bootstrap -:host /deep/ .card:first-of-type { +:host ::ng-deep .card:first-of-type { border-bottom: $card-border-width solid $card-border-color !important; border-bottom-left-radius: $card-border-radius !important; border-bottom-right-radius: $card-border-radius !important; } -:host /deep/ .card-header button { +:host ::ng-deep .card-header button { box-shadow: none !important; width: 100%; } diff --git a/src/app/submission/sections/container/section-container.component.spec.ts b/src/app/submission/sections/container/section-container.component.spec.ts index 778aa4ab84..38b8572d0c 100644 --- a/src/app/submission/sections/container/section-container.component.spec.ts +++ b/src/app/submission/sections/container/section-container.component.spec.ts @@ -67,7 +67,7 @@ describe('SubmissionSectionContainerComponent test suite', () => { TestBed.configureTestingModule({ imports: [ - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ diff --git a/src/app/submission/sections/container/section-container.component.ts b/src/app/submission/sections/container/section-container.component.ts index f040288667..a48bf8cb92 100644 --- a/src/app/submission/sections/container/section-container.component.ts +++ b/src/app/submission/sections/container/section-container.component.ts @@ -48,7 +48,7 @@ export class SubmissionSectionContainerComponent implements OnInit { /** * The SectionsDirective reference */ - @ViewChild('sectionRef') sectionRef: SectionsDirective; + @ViewChild('sectionRef', {static: false}) sectionRef: SectionsDirective; /** * Initialize instance variables diff --git a/src/app/submission/sections/form/section-form.component.spec.ts b/src/app/submission/sections/form/section-form.component.spec.ts index be13c14941..d644e44df5 100644 --- a/src/app/submission/sections/form/section-form.component.spec.ts +++ b/src/app/submission/sections/form/section-form.component.spec.ts @@ -108,10 +108,11 @@ const testFormConfiguration = { ] } as FormRowModel, ], - self: 'testFormConfiguration.url', type: 'submissionform', _links: { - self: 'testFormConfiguration.url' + self: { + href: 'testFormConfiguration.url' + } } } as any; diff --git a/src/app/submission/sections/form/section-form.component.ts b/src/app/submission/sections/form/section-form.component.ts index 49dbaea807..36ed4b96a9 100644 --- a/src/app/submission/sections/form/section-form.component.ts +++ b/src/app/submission/sections/form/section-form.component.ts @@ -112,7 +112,7 @@ export class SubmissionSectionformComponent extends SectionModelComponent { /** * The FormComponent reference */ - @ViewChild('formRef') private formRef: FormComponent; + @ViewChild('formRef', {static: false}) private formRef: FormComponent; /** * Initialize instance variables diff --git a/src/app/submission/sections/license/section-license.component.ts b/src/app/submission/sections/license/section-license.component.ts index 940460c83d..e6915112e5 100644 --- a/src/app/submission/sections/license/section-license.component.ts +++ b/src/app/submission/sections/license/section-license.component.ts @@ -1,7 +1,4 @@ import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core'; - -import { Observable, Subscription } from 'rxjs'; -import { distinctUntilChanged, filter, find, flatMap, map, startWith, take } from 'rxjs/operators'; import { DynamicCheckboxModel, DynamicFormControlEvent, @@ -9,25 +6,29 @@ import { DynamicFormLayout } from '@ng-dynamic-forms/core'; -import { SectionModelComponent } from '../models/section.model'; -import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, filter, find, flatMap, map, startWith, take } from 'rxjs/operators'; import { CollectionDataService } from '../../../core/data/collection-data.service'; -import { hasValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../shared/empty.util'; -import { License } from '../../../core/shared/license.model'; import { RemoteData } from '../../../core/data/remote-data'; -import { Collection } from '../../../core/shared/collection.model'; -import { SECTION_LICENSE_FORM_LAYOUT, SECTION_LICENSE_FORM_MODEL } from './section-license.model'; -import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; -import { FormService } from '../../../shared/form/form.service'; import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; -import { SectionsType } from '../sections-type'; -import { renderSectionFor } from '../sections-decorator'; -import { SectionDataObject } from '../models/section-data.model'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { Collection } from '../../../core/shared/collection.model'; +import { License } from '../../../core/shared/license.model'; import { WorkspaceitemSectionLicenseObject } from '../../../core/submission/models/workspaceitem-section-license.model'; -import { SubmissionService } from '../../submission.service'; -import { SectionsService } from '../sections.service'; -import { SectionFormOperationsService } from '../form/section-form-operations.service'; +import { hasValue, isNotEmpty, isNotNull, isNotUndefined } from '../../../shared/empty.util'; +import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; import { FormComponent } from '../../../shared/form/form.component'; +import { FormService } from '../../../shared/form/form.service'; +import { followLink } from '../../../shared/utils/follow-link-config.model'; +import { SubmissionService } from '../../submission.service'; +import { SectionFormOperationsService } from '../form/section-form-operations.service'; +import { SectionDataObject } from '../models/section-data.model'; + +import { SectionModelComponent } from '../models/section.model'; +import { renderSectionFor } from '../sections-decorator'; +import { SectionsType } from '../sections-type'; +import { SectionsService } from '../sections.service'; +import { SECTION_LICENSE_FORM_LAYOUT, SECTION_LICENSE_FORM_MODEL } from './section-license.model'; /** * This component represents a section that contains the submission license form. @@ -85,7 +86,7 @@ export class SubmissionSectionLicenseComponent extends SectionModelComponent { /** * The FormComponent reference */ - @ViewChild('formRef') private formRef: FormComponent; + @ViewChild('formRef', {static: false}) private formRef: FormComponent; /** * Initialize instance variables @@ -132,9 +133,9 @@ export class SubmissionSectionLicenseComponent extends SectionModelComponent { (model as DynamicCheckboxModel).valueUpdates.next(false); } - this.licenseText$ = this.collectionDataService.findById(this.collectionId).pipe( + this.licenseText$ = this.collectionDataService.findById(this.collectionId, followLink('license')).pipe( filter((collectionData: RemoteData) => isNotUndefined((collectionData.payload))), - flatMap((collectionData: RemoteData) => collectionData.payload.license), + flatMap((collectionData: RemoteData) => (collectionData.payload as any).license), find((licenseData: RemoteData) => isNotUndefined((licenseData.payload))), map((licenseData: RemoteData) => licenseData.payload.text), startWith('')); diff --git a/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts b/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts index 43b0a7da3f..04852cc014 100644 --- a/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts +++ b/src/app/submission/sections/upload/accessConditions/submission-section-upload-access-conditions.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { find } from 'rxjs/operators'; -import { GroupEpersonService } from '../../../../core/eperson/group-eperson.service'; +import { GroupDataService } from '../../../../core/eperson/group-data.service'; import { ResourcePolicy } from '../../../../core/shared/resource-policy.model'; import { isEmpty } from '../../../../shared/empty.util'; import { Group } from '../../../../core/eperson/models/group.model'; @@ -32,9 +32,9 @@ export class SubmissionSectionUploadAccessConditionsComponent implements OnInit /** * Initialize instance variables * - * @param {GroupEpersonService} groupService + * @param {GroupDataService} groupService */ - constructor(private groupService: GroupEpersonService) {} + constructor(private groupService: GroupDataService) {} /** * Retrieve access conditions list diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts index 8cf0d22d20..19ee5d6d3d 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.component.ts @@ -125,7 +125,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { /** * The FormComponent reference */ - @ViewChild('formRef') public formRef: FormComponent; + @ViewChild('formRef', {static: false}) public formRef: FormComponent; /** * Initialize instance variables @@ -334,7 +334,7 @@ export class SubmissionSectionUploadFileEditComponent implements OnChanges { }); // Due to a bug can't dynamically change the select options, so replace the model with a new one - const confGroup = { relation: groupModel.relation }; + const confGroup = { relation: groupModel.relations }; const groupsConfig = Object.assign({}, BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG, confGroup); groupsConfig.options = groupOptions; (model.parent as DynamicFormGroupModel).group.pop(); diff --git a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts index ec72adf786..bc994aac52 100644 --- a/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts +++ b/src/app/submission/sections/upload/file/edit/section-upload-file-edit.model.ts @@ -50,10 +50,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_START_DATE_CONFIG: DynamicDatePicke placeholder: 'submission.sections.upload.form.from-placeholder', inline: false, toggleIcon: 'far fa-calendar-alt', - relation: [ + relations: [ { - action: 'ENABLE', - connective: 'OR', + match: 'ENABLE', + operator: 'OR', when: [] } ], @@ -81,10 +81,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_END_DATE_CONFIG: DynamicDatePickerM placeholder: 'submission.sections.upload.form.until-placeholder', inline: false, toggleIcon: 'far fa-calendar-alt', - relation: [ + relations: [ { - action: 'ENABLE', - connective: 'OR', + match: 'ENABLE', + operator: 'OR', when: [] } ], @@ -110,10 +110,10 @@ export const BITSTREAM_FORM_ACCESS_CONDITION_GROUPS_CONFIG: DynamicSelectModelCo id: 'groupUUID', label: 'submission.sections.upload.form.group-label', options: [], - relation: [ + relations: [ { - action: 'ENABLE', - connective: 'OR', + match: 'ENABLE', + operator: 'OR', when: [] } ], diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts index 54b51e7afc..4e0badb76d 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.spec.ts @@ -86,7 +86,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { imports: [ BrowserModule, CommonModule, - NgbModule.forRoot(), + NgbModule, TranslateModule.forRoot() ], declarations: [ @@ -190,7 +190,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { expect(comp.fileData).toEqual(fileData); }); - it('should call deleteFile on delete confirmation', fakeAsync(() => { + it('should call deleteFile on delete confirmation', () => { spyOn(compAsAny, 'deleteFile'); comp.fileData = fileData; @@ -209,7 +209,7 @@ describe('SubmissionSectionUploadFileComponent test suite', () => { fixture.whenStable().then(() => { expect(compAsAny.deleteFile).toHaveBeenCalled(); }); - })); + }); it('should delete file properly', () => { compAsAny.pathCombiner = pathCombiner; diff --git a/src/app/submission/sections/upload/file/section-upload-file.component.ts b/src/app/submission/sections/upload/file/section-upload-file.component.ts index 9923c358e7..c0ad31165b 100644 --- a/src/app/submission/sections/upload/file/section-upload-file.component.ts +++ b/src/app/submission/sections/upload/file/section-upload-file.component.ts @@ -141,7 +141,7 @@ export class SubmissionSectionUploadFileComponent implements OnChanges, OnInit { * The [[SubmissionSectionUploadFileEditComponent]] reference * @type {SubmissionSectionUploadFileEditComponent} */ - @ViewChild(SubmissionSectionUploadFileEditComponent) fileEditComp: SubmissionSectionUploadFileEditComponent; + @ViewChild(SubmissionSectionUploadFileEditComponent, {static: false}) fileEditComp: SubmissionSectionUploadFileEditComponent; /** * Initialize instance variables diff --git a/src/app/submission/sections/upload/section-upload.component.spec.ts b/src/app/submission/sections/upload/section-upload.component.spec.ts index a58de09b8d..af865b81eb 100644 --- a/src/app/submission/sections/upload/section-upload.component.spec.ts +++ b/src/app/submission/sections/upload/section-upload.component.spec.ts @@ -27,7 +27,7 @@ import { SubmissionUploadsConfigService } from '../../../core/config/submission- import { SectionUploadService } from './section-upload.service'; import { SubmissionSectionUploadComponent } from './section-upload.component'; import { CollectionDataService } from '../../../core/data/collection-data.service'; -import { GroupEpersonService } from '../../../core/eperson/group-eperson.service'; +import { GroupDataService } from '../../../core/eperson/group-data.service'; import { cold, hot } from 'jasmine-marbles'; import { Collection } from '../../../core/shared/collection.model'; import { ResourcePolicy } from '../../../core/shared/resource-policy.model'; @@ -52,8 +52,8 @@ function getMockCollectionDataService(): CollectionDataService { }); } -function getMockGroupEpersonService(): GroupEpersonService { - return jasmine.createSpyObj('GroupEpersonService', { +function getMockGroupEpersonService(): GroupDataService { + return jasmine.createSpyObj('GroupDataService', { findById: jasmine.createSpy('findById'), }); @@ -134,7 +134,7 @@ describe('SubmissionSectionUploadComponent test suite', () => { ], providers: [ { provide: CollectionDataService, useValue: getMockCollectionDataService() }, - { provide: GroupEpersonService, useValue: getMockGroupEpersonService() }, + { provide: GroupDataService, useValue: getMockGroupEpersonService() }, { provide: ResourcePolicyService, useValue: getMockResourcePolicyService() }, { provide: SubmissionUploadsConfigService, useValue: getMockSubmissionUploadsConfigService() }, { provide: SectionsService, useClass: SectionsServiceStub }, @@ -181,7 +181,7 @@ describe('SubmissionSectionUploadComponent test suite', () => { submissionServiceStub = TestBed.get(SubmissionService); sectionsServiceStub = TestBed.get(SectionsService); collectionDataService = TestBed.get(CollectionDataService); - groupService = TestBed.get(GroupEpersonService); + groupService = TestBed.get(GroupDataService); resourcePolicyService = TestBed.get(ResourcePolicyService); uploadsConfigService = TestBed.get(SubmissionUploadsConfigService); bitstreamService = TestBed.get(SectionUploadService); @@ -197,7 +197,9 @@ describe('SubmissionSectionUploadComponent test suite', () => { submissionServiceStub.getSubmissionObject.and.returnValue(observableOf(submissionState)); - collectionDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(mockCollection)); + collectionDataService.findById.and.returnValue(createSuccessfulRemoteDataObject$(Object.assign(new Collection(), mockCollection, { + defaultAccessConditions: createSuccessfulRemoteDataObject$(mockDefaultAccessCondition) + }))); resourcePolicyService.findByHref.and.returnValue(createSuccessfulRemoteDataObject$(mockDefaultAccessCondition)); diff --git a/src/app/submission/sections/upload/section-upload.component.ts b/src/app/submission/sections/upload/section-upload.component.ts index 6c2506b773..86da00c816 100644 --- a/src/app/submission/sections/upload/section-upload.component.ts +++ b/src/app/submission/sections/upload/section-upload.component.ts @@ -2,12 +2,13 @@ import { ChangeDetectorRef, Component, Inject } from '@angular/core'; import { BehaviorSubject, combineLatest as observableCombineLatest, Observable, Subscription} from 'rxjs'; import { distinctUntilChanged, filter, find, flatMap, map, reduce, take, tap } from 'rxjs/operators'; +import { followLink } from '../../../shared/utils/follow-link-config.model'; import { SectionModelComponent } from '../models/section.model'; import { hasValue, isNotEmpty, isNotUndefined, isUndefined } from '../../../shared/empty.util'; import { SectionUploadService } from './section-upload.service'; import { CollectionDataService } from '../../../core/data/collection-data.service'; -import { GroupEpersonService } from '../../../core/eperson/group-eperson.service'; +import { GroupDataService } from '../../../core/eperson/group-data.service'; import { ResourcePolicyService } from '../../../core/data/resource-policy.service'; import { SubmissionUploadsConfigService } from '../../../core/config/submission-uploads-config.service'; import { SubmissionUploadsModel } from '../../../core/config/models/config-submission-uploads.model'; @@ -95,7 +96,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent { public configMetadataForm$: Observable; /** - * List of available access conditions that could be setted to files + * List of available access conditions that could be set to files */ public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select @@ -122,7 +123,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent { * @param {SectionUploadService} bitstreamService * @param {ChangeDetectorRef} changeDetectorRef * @param {CollectionDataService} collectionDataService - * @param {GroupEpersonService} groupService + * @param {GroupDataService} groupService * @param {ResourcePolicyService} resourcePolicyService * @param {SectionsService} sectionService * @param {SubmissionService} submissionService @@ -133,7 +134,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent { constructor(private bitstreamService: SectionUploadService, private changeDetectorRef: ChangeDetectorRef, private collectionDataService: CollectionDataService, - private groupService: GroupEpersonService, + private groupService: GroupDataService, private resourcePolicyService: ResourcePolicyService, protected sectionService: SectionsService, private submissionService: SubmissionService, @@ -165,7 +166,7 @@ export class SubmissionSectionUploadComponent extends SectionModelComponent { tap((collectionRemoteData: RemoteData) => this.collectionName = collectionRemoteData.payload.name), flatMap((collectionRemoteData: RemoteData) => { return this.resourcePolicyService.findByHref( - (collectionRemoteData.payload as any)._links.defaultAccessConditions + (collectionRemoteData.payload as any)._links.defaultAccessConditions.href ); }), filter((defaultAccessConditionsRemoteData: RemoteData) => diff --git a/src/app/thumbnail/thumbnail.component.html b/src/app/thumbnail/thumbnail.component.html index 87fd0251f5..dbf8f6732c 100644 --- a/src/app/thumbnail/thumbnail.component.html +++ b/src/app/thumbnail/thumbnail.component.html @@ -1,4 +1,4 @@
- +
diff --git a/src/app/thumbnail/thumbnail.component.spec.ts b/src/app/thumbnail/thumbnail.component.spec.ts index f2be55d52c..c4258aceb9 100644 --- a/src/app/thumbnail/thumbnail.component.spec.ts +++ b/src/app/thumbnail/thumbnail.component.spec.ts @@ -1,11 +1,11 @@ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; - -import { ThumbnailComponent } from './thumbnail.component'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; import { Bitstream } from '../core/shared/bitstream.model'; import { SafeUrlPipe } from '../shared/utils/safe-url-pipe'; +import { THUMBNAIL_PLACEHOLDER, ThumbnailComponent } from './thumbnail.component'; + describe('ThumbnailComponent', () => { let comp: ThumbnailComponent; let fixture: ComponentFixture; @@ -25,18 +25,37 @@ describe('ThumbnailComponent', () => { el = de.nativeElement; }); - it('should display image', () => { - comp.thumbnail = new Bitstream(); - comp.thumbnail.content = 'test.url'; - fixture.detectChanges(); - const image: HTMLElement = de.query(By.css('img')).nativeElement; - expect(image.getAttribute('src')).toBe(comp.thumbnail.content); + describe('when the thumbnail exists', () => { + it('should display an image', () => { + const thumbnail = new Bitstream(); + thumbnail._links = { + self: { href: 'self.url' }, + bundle: { href: 'bundle.url' }, + format: { href: 'format.url' }, + content: { href: 'content.url' }, + }; + comp.thumbnail = thumbnail; + fixture.detectChanges(); + const image: HTMLElement = de.query(By.css('img')).nativeElement; + expect(image.getAttribute('src')).toBe(comp.thumbnail._links.content.href); + }); }); - - it('should display placeholder', () => { - fixture.detectChanges(); - const image: HTMLElement = de.query(By.css('img')).nativeElement; - expect(image.getAttribute('src')).toBe(comp.defaultImage); + describe(`when the thumbnail doesn't exist`, () => { + describe('and there is a default image', () => { + it('should display the default image', () => { + comp.src = 'http://bit.stream'; + comp.defaultImage = 'http://default.img'; + comp.errorHandler(); + expect(comp.src).toBe(comp.defaultImage); + }); + }); + describe('and there is no default image', () => { + it('should display the placeholder', () => { + comp.src = 'http://default.img'; + comp.defaultImage = 'http://default.img'; + comp.errorHandler(); + expect(comp.src).toBe(THUMBNAIL_PLACEHOLDER); + }) + }); }); - }); diff --git a/src/app/thumbnail/thumbnail.component.ts b/src/app/thumbnail/thumbnail.component.ts index e31e907b47..2bbd2bb2da 100644 --- a/src/app/thumbnail/thumbnail.component.ts +++ b/src/app/thumbnail/thumbnail.component.ts @@ -2,12 +2,16 @@ import { Component, Input, OnInit } from '@angular/core'; import { Bitstream } from '../core/shared/bitstream.model'; import { hasValue } from '../shared/empty.util'; +/** + * A fallback placeholder image as a base64 string + */ +export const THUMBNAIL_PLACEHOLDER = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23FFFFFF%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'; + /** * This component renders a given Bitstream as a thumbnail. * One input parameter of type Bitstream is expected. * If no Bitstream is provided, a holderjs image will be rendered instead. */ - @Component({ selector: 'ds-thumbnail', styleUrls: ['./thumbnail.component.scss'], @@ -15,24 +19,43 @@ import { hasValue } from '../shared/empty.util'; }) export class ThumbnailComponent implements OnInit { + /** + * The thumbnail Bitstream + */ @Input() thumbnail: Bitstream; /** - * The default 'holder.js' image + * The default image, used if the thumbnail isn't set or can't be downloaded */ - @Input() defaultImage? = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2293%22%20height%3D%22120%22%20viewBox%3D%220%200%2093%20120%22%20preserveAspectRatio%3D%22none%22%3E%3C!--%0ASource%20URL%3A%20holder.js%2F93x120%3Ftext%3DNo%20Thumbnail%0ACreated%20with%20Holder.js%202.8.2.%0ALearn%20more%20at%20http%3A%2F%2Fholderjs.com%0A(c)%202012-2015%20Ivan%20Malopinsky%20-%20http%3A%2F%2Fimsky.co%0A--%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%3C!%5BCDATA%5B%23holder_1543e460b05%20text%20%7B%20fill%3A%23AAAAAA%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_1543e460b05%22%3E%3Crect%20width%3D%2293%22%20height%3D%22120%22%20fill%3D%22%23FFFFFF%22%2F%3E%3Cg%3E%3Ctext%20x%3D%2235.6171875%22%20y%3D%2257%22%3ENo%3C%2Ftext%3E%3Ctext%20x%3D%2210.8125%22%20y%3D%2272%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E'; + @Input() defaultImage? = THUMBNAIL_PLACEHOLDER; + /** + * The src attribute used in the template to render the image. + */ src: string; - errorHandler(event) { - event.currentTarget.src = this.defaultImage; - } + /** + * Initialize the thumbnail. + * Use a default image if no actual image is available. + */ ngOnInit(): void { - if (hasValue(this.thumbnail) && this.thumbnail.content) { - this.src = this.thumbnail.content; - } else { - this.src = this.defaultImage - } + if (hasValue(this.thumbnail) && hasValue(this.thumbnail._links) && hasValue(this.thumbnail._links.content) && this.thumbnail._links.content.href) { + this.src = this.thumbnail._links.content.href; + } else { + this.src = this.defaultImage + } } + /** + * Handle image download errors. + * If the image can't be found, use the defaultImage instead. + * If that also can't be found, use the base64 placeholder. + */ + errorHandler() { + if (this.src !== this.defaultImage) { + this.src = this.defaultImage; + } else { + this.src = THUMBNAIL_PLACEHOLDER; + } + } } diff --git a/src/modules/app/browser-app.module.ts b/src/modules/app/browser-app.module.ts index 0dbe4f58fe..34d8fb18a7 100644 --- a/src/modules/app/browser-app.module.ts +++ b/src/modules/app/browser-app.module.ts @@ -18,7 +18,7 @@ import { DSpaceTransferState } from '../transfer-state/dspace-transfer-state.ser import { ClientCookieService } from '../../app/core/services/client-cookie.service'; import { CookieService } from '../../app/core/services/cookie.service'; import { AuthService } from '../../app/core/auth/auth.service'; -import { Angulartics2Module } from 'angulartics2'; +import { Angulartics2RouterlessModule } from 'angulartics2/routerlessmodule'; import { SubmissionService } from '../../app/submission/submission.service'; import { StatisticsModule } from '../../app/statistics/statistics.module'; @@ -48,7 +48,7 @@ export function getRequest(transferState: TransferState): any { IdlePreload }), StatisticsModule.forRoot(), - Angulartics2Module.forRoot(), + Angulartics2RouterlessModule.forRoot(), BrowserAnimationsModule, DSpaceBrowserTransferStateModule, TranslateModule.forRoot({ diff --git a/src/modules/app/server-app.module.ts b/src/modules/app/server-app.module.ts index 286e878d9b..4011bb8d37 100644 --- a/src/modules/app/server-app.module.ts +++ b/src/modules/app/server-app.module.ts @@ -23,7 +23,7 @@ import { AngularticsMock } from '../../app/shared/mocks/mock-angulartics.service import { SubmissionService } from '../../app/submission/submission.service'; import { ServerSubmissionService } from '../../app/submission/server-submission.service'; import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider'; -import { Angulartics2Module } from 'angulartics2'; +import { Angulartics2RouterlessModule } from 'angulartics2/routerlessmodule'; export function createTranslateLoader() { return new TranslateJson5UniversalLoader('dist/assets/i18n/', '.json5'); @@ -47,7 +47,7 @@ export function createTranslateLoader() { deps: [] } }), - Angulartics2Module.forRoot(), + Angulartics2RouterlessModule.forRoot(), ServerModule, AppModule ], diff --git a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html index 50b5fed9d3..adecd9e1af 100644 --- a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html +++ b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html @@ -4,7 +4,7 @@ a
- +
- +
- +
- +
-
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html index 1679f9354d..dbcb76a292 100644 --- a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html +++ b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html @@ -4,7 +4,7 @@
-
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html index 31ba79a158..b31353ef76 100644 --- a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html +++ b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html @@ -4,7 +4,7 @@
-
diff --git a/webpack/webpack.server.js b/webpack/webpack.server.js index 5e80a286a0..6f529ed791 100644 --- a/webpack/webpack.server.js +++ b/webpack/webpack.server.js @@ -20,7 +20,7 @@ module.exports = (env) => { /@ng/, /angular2-text-mask/, /ng2-file-upload/, - /angular-sortablejs/, + /ngx-sortablejs/, /sortablejs/, /ngx/] })], diff --git a/yarn.lock b/yarn.lock index 2d34ac734d..7035bb60c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,84 +2,95 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.13.9": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.9.tgz#8bbca4b968fccbf88fc2f86542cbee09e1256e1f" - integrity sha512-EAFtCs9dsGhpMRC45PoYsrkiExpWz9Ax15qXfzwdDRacz5DmdOVt+QpkLW1beUOwiyj/bhFyj23eaONK2RTn/w== +"@angular-devkit/architect@0.803.25": + version "0.803.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.803.25.tgz#06d109b3b24a080f0bac7374c5328b6a7b886f06" + integrity sha512-usV/zEncKCKQuF6AD3pRU6N5i5fbaAux/qZb+nbOz9/2G5jrXwe5sH+y3vxbgqB83e3LqusEQCTu7/tfg6LwZg== dependencies: - "@angular-devkit/core" "7.3.9" - rxjs "6.3.3" + "@angular-devkit/core" "8.3.25" + rxjs "6.4.0" -"@angular-devkit/build-angular@^0.13.5": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.13.9.tgz#92ef7b55a1aa055b2f5c8ffed4bdb04df86db678" - integrity sha512-onh07LhdxotDFjja0KKsDWNCwgpM/ymuRr5h0e+vT4AgklP2Uioz1CpzVOgxPIKkdVdGR9QgDinVsWAmY90J8g== +"@angular-devkit/build-angular@^0.803.25": + version "0.803.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.803.25.tgz#c630fda1d85b720a0f76211edbd475a8399fbbbb" + integrity sha512-WY0E7NgXuog3phhz5ZdutZPWQ9nbOr+omGN5KI1e8MZs1sJO4xkyaGRT8zOulkogkqJ2NboTBq3j9uSbZkcYeg== dependencies: - "@angular-devkit/architect" "0.13.9" - "@angular-devkit/build-optimizer" "0.13.9" - "@angular-devkit/build-webpack" "0.13.9" - "@angular-devkit/core" "7.3.9" - "@ngtools/webpack" "7.3.9" - ajv "6.9.1" - autoprefixer "9.4.6" - circular-dependency-plugin "5.0.2" + "@angular-devkit/architect" "0.803.25" + "@angular-devkit/build-optimizer" "0.803.25" + "@angular-devkit/build-webpack" "0.803.25" + "@angular-devkit/core" "8.3.25" + "@babel/core" "7.8.3" + "@babel/preset-env" "7.8.3" + "@ngtools/webpack" "8.3.25" + ajv "6.10.2" + autoprefixer "9.6.1" + browserslist "4.8.6" + cacache "12.0.2" + caniuse-lite "1.0.30001024" + circular-dependency-plugin "5.2.0" clean-css "4.2.1" - copy-webpack-plugin "4.6.0" - file-loader "3.0.1" - glob "7.1.3" - istanbul-instrumenter-loader "3.0.1" - karma-source-map-support "1.3.0" + copy-webpack-plugin "5.1.1" + core-js "3.6.4" + coverage-istanbul-loader "2.0.3" + file-loader "4.2.0" + find-cache-dir "3.0.0" + glob "7.1.4" + jest-worker "24.9.0" + karma-source-map-support "1.4.0" less "3.9.0" - less-loader "4.1.0" - license-webpack-plugin "2.1.0" + less-loader "5.0.0" + license-webpack-plugin "2.1.2" loader-utils "1.2.3" - mini-css-extract-plugin "0.5.0" + mini-css-extract-plugin "0.8.0" minimatch "3.0.4" - open "6.0.0" + open "6.4.0" parse5 "4.0.0" - postcss "7.0.14" + postcss "7.0.17" postcss-import "12.0.1" postcss-loader "3.0.0" - raw-loader "1.0.0" - rxjs "6.3.3" - sass-loader "7.1.0" - semver "5.6.0" + raw-loader "3.1.0" + regenerator-runtime "0.13.3" + rxjs "6.4.0" + sass "1.22.9" + sass-loader "7.2.0" + semver "6.3.0" + source-map "0.7.3" source-map-loader "0.2.4" - source-map-support "0.5.10" + source-map-support "0.5.13" speed-measure-webpack-plugin "1.3.1" - stats-webpack-plugin "0.7.0" - style-loader "0.23.1" + style-loader "1.0.0" stylus "0.54.5" stylus-loader "3.0.2" - terser-webpack-plugin "1.2.2" - tree-kill "1.2.1" - webpack "4.29.0" - webpack-dev-middleware "3.5.1" - webpack-dev-server "3.1.14" + terser "4.6.3" + terser-webpack-plugin "1.4.3" + tree-kill "1.2.2" + webpack "4.39.2" + webpack-dev-middleware "3.7.2" + webpack-dev-server "3.9.0" webpack-merge "4.2.1" - webpack-sources "1.3.0" + webpack-sources "1.4.3" webpack-subresource-integrity "1.1.0-rc.6" - optionalDependencies: - node-sass "4.12.0" + worker-plugin "3.2.0" -"@angular-devkit/build-optimizer@0.13.9": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.13.9.tgz#05a25ca7743876987158881585c55dfc478b95bd" - integrity sha512-GQtCntthQHSBv5l1ZY5p00JOECb/WcE1qUBo5kFjp84z0fszDkhOy52M1kcWCX4PFzJaY4DKk58hbUE/2UN0jw== +"@angular-devkit/build-optimizer@0.803.25": + version "0.803.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.803.25.tgz#83aedee3cbe15f4ec7f777dc028f2669e0ff4439" + integrity sha512-MiQimuEs8QeM3xo7bR3Yk1OWHHlp2pGCc2GLUMIcWhKqM+QjoRky0HoGoBazbznx292l+xjFjANvPEKbqJ2v7Q== dependencies: loader-utils "1.2.3" - source-map "0.5.6" - typescript "3.2.4" - webpack-sources "1.3.0" + source-map "0.7.3" + tslib "1.10.0" + typescript "3.5.3" + webpack-sources "1.4.3" -"@angular-devkit/build-webpack@0.13.9": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.13.9.tgz#9fa091d778db752c539e1c585e21ba47d7054672" - integrity sha512-6ypu6pzNmQxzATF4rTWEhGSl5hyGQ8a/3aCZF/ux+XGc3d4hi2HW+NWlDm1UEna6ZjNtgEPlgfP4q8BKrjRmfA== +"@angular-devkit/build-webpack@0.803.25": + version "0.803.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.803.25.tgz#7a0648920de1c51d30447cf369929d491e267f9c" + integrity sha512-WR7HWJIWL6TB3WHG7ZFn8s0z3WlojeQlod75UIKl5i+f4OU90kp8kxcoH5G6OCXu56x5w40oIi1ve5ljjWSJkw== dependencies: - "@angular-devkit/architect" "0.13.9" - "@angular-devkit/core" "7.3.9" - rxjs "6.3.3" + "@angular-devkit/architect" "0.803.25" + "@angular-devkit/core" "8.3.25" + rxjs "6.4.0" "@angular-devkit/core@0.7.5": version "0.7.5" @@ -91,15 +102,15 @@ rxjs "^6.0.0" source-map "^0.5.6" -"@angular-devkit/core@7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.9.tgz#bef2aaa0be7219c546fb99ea0ba9dd3a6dcd288a" - integrity sha512-SaxD+nKFW3iCBKsxNR7+66J30EexW/y7tm8m5AvUH+GwSAgIj0ZYmRUzFEPggcaLVA4WnE/YWqIXZMJW5dT7gw== +"@angular-devkit/core@8.3.25": + version "8.3.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.3.25.tgz#8133a18be811424f10a10f37c712165b0f69f3fc" + integrity sha512-l7Gqy1tMrTpRmPVlovcFX8UA3mtXRlgO8kcSsbJ9MKRKNTCcxlfsWEYY5igyDBUVh6ADkgSIu0nuk31ZGTe0lw== dependencies: - ajv "6.9.1" - chokidar "2.0.4" + ajv "6.10.2" fast-json-stable-stringify "2.0.0" - rxjs "6.3.3" + magic-string "0.25.3" + rxjs "6.4.0" source-map "0.7.3" "@angular-devkit/schematics@0.7.5": @@ -110,60 +121,67 @@ "@angular-devkit/core" "0.7.5" rxjs "^6.0.0" -"@angular-devkit/schematics@7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.9.tgz#4fe7bc878b116b157a3adf00583c28c951215877" - integrity sha512-xzROGCYp7aQbeJ3V6YC0MND7wKEAdWqmm/GaCufEk0dDS8ZGe0sQhcM2oBRa2nQqGQNeThFIH51kx+FayrJP0w== +"@angular-devkit/schematics@8.3.25": + version "8.3.25" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.3.25.tgz#692eaa0fc14bc09c315d93966c781a97ca524f77" + integrity sha512-/p1MkfursfLy+JRGXlJGPEmX55lrFCsR/2khWAVXZcMaFR3QlR/b6/zvB8I2pHFfr0/XWnYTT/BsF7rJjO3RmA== dependencies: - "@angular-devkit/core" "7.3.9" - rxjs "6.3.3" + "@angular-devkit/core" "8.3.25" + rxjs "6.4.0" -"@angular/animations@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.15.tgz#980c1f523a79d4b7cb44508f57fba06f2e0872fa" - integrity sha512-8oBt3HLgd2+kyJHUgsd7OzKCCss67t2sch15XNoIWlOLfxclqU+EfFE6t/vCzpT8/+lpZS6LU9ZrTnb+UBj5jg== +"@angular/animations@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-8.2.14.tgz#76736b21e56165e6ca4925fb69605bdcc56aba7d" + integrity sha512-3Vc9TnNpKdtvKIXcWDFINSsnwgEMiDmLzjceWg1iYKwpeZGQahUXPoesLwQazBMmxJzQiA4HOMj0TTXKZ+Jzkg== dependencies: tslib "^1.9.0" -"@angular/cdk@7.3.7": - version "7.3.7" - resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-7.3.7.tgz#ce1ad53ba04beb9c8e950acc5691ea0143753764" - integrity sha512-xbXxhHHKGkVuW6K7pzPmvpJXIwpl0ykBnvA2g+/7Sgy5Pd35wCC+UtHD9RYczDM/mkygNxMQtagyCErwFnDtQA== +"@angular/cdk@8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-8.2.3.tgz#16b96ffa935cbf5a646757ecaf2b19c434678f72" + integrity sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA== dependencies: tslib "^1.7.1" optionalDependencies: parse5 "^5.0.0" -"@angular/cli@^7.3.5": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.3.9.tgz#0366b5a66654c1f02ab2f3a9f15ebde446d506a4" - integrity sha512-7oJj7CKDlFUbQav1x1CV4xKKcbt0pnxY4unKcm7Q1tVXhu8bU2bc3cDA0aJnbofcYb6TJcd/C2qHgCt78q7edA== +"@angular/cli@^8.3.25": + version "8.3.25" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.3.25.tgz#2802291f83a88f334336a1482c8ee63a69cabad7" + integrity sha512-CPJI5nnbBvvyBUFwOHfRXy/KVwsiYlcbDAeIk1klcjQjbVFYZbnY0iAhNupy9j7rPQhb7jle5oslU3TLfbqOTQ== dependencies: - "@angular-devkit/architect" "0.13.9" - "@angular-devkit/core" "7.3.9" - "@angular-devkit/schematics" "7.3.9" - "@schematics/angular" "7.3.9" - "@schematics/update" "0.13.9" + "@angular-devkit/architect" "0.803.25" + "@angular-devkit/core" "8.3.25" + "@angular-devkit/schematics" "8.3.25" + "@schematics/angular" "8.3.25" + "@schematics/update" "0.803.25" "@yarnpkg/lockfile" "1.1.0" + ansi-colors "4.1.1" + debug "^4.1.1" ini "1.3.5" - inquirer "6.2.1" + inquirer "6.5.1" npm-package-arg "6.1.0" - open "6.0.0" - pacote "9.4.0" - semver "5.6.0" + npm-pick-manifest "3.0.2" + open "6.4.0" + pacote "9.5.5" + read-package-tree "5.3.1" + rimraf "3.0.0" + semver "6.3.0" symbol-observable "1.2.0" + universal-analytics "^0.4.20" + uuid "^3.3.2" -"@angular/common@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.15.tgz#e6c2f6913cdc49f87adcaabc30604e721561374b" - integrity sha512-2b5JY2HWVHCf3D1GZjmde7jdAXSTXkYtmjLtA9tQkjOOTr80eHpNSujQqnzb97dk9VT9OjfjqTQd7K3pxZz8jw== +"@angular/common@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-8.2.14.tgz#027e52b2951c14082d6e3af1a4ffa1356220e439" + integrity sha512-Qmt+aX2quUW54kaNT7QH7WGXnFxr/cC2C6sf5SW5SdkZfDQSiz8IaItvieZfXVQUbBOQKFRJ7TlSkt0jI/yjvw== dependencies: tslib "^1.9.0" -"@angular/compiler-cli@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-7.2.15.tgz#25cc3a6556ba726d00c4992ad894f8db203f4fbc" - integrity sha512-+AsfyKawmj/sa+m4Pz8VSRFbCfx/3IOjAuuEjhopbyr154YpPDSu8NTbcwzq3yfbVcPwK4/4exmbQzpsndaCTg== +"@angular/compiler-cli@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-8.2.14.tgz#1997bec04a6b9d022954e5747505fe8906994594" + integrity sha512-XDrTyrlIZM+0NquVT+Kbg5bn48AaWFT+B3bAT288PENrTdkuxuF9AhjFRZj8jnMdmaE4O2rioEkXBtl6z3zptA== dependencies: canonical-path "1.0.0" chokidar "^2.1.1" @@ -172,66 +190,58 @@ magic-string "^0.25.0" minimist "^1.2.0" reflect-metadata "^0.1.2" - shelljs "^0.8.1" source-map "^0.6.1" tslib "^1.9.0" - yargs "9.0.1" + yargs "13.1.0" -"@angular/compiler@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.15.tgz#9698dac49dbb46956f0b8a6280580025ea7ab04e" - integrity sha512-5yb4NcLk8GuXkYf7Dcor4XkGueYp4dgihzDmMjYDUrV0NPhubKlr+SwGtLOtzgRBWJ1I2bO0S3zwa0q0OgIPOw== +"@angular/compiler@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-8.2.14.tgz#46db7a9d1c17f236126518ff26480c160d5a6183" + integrity sha512-ABZO4E7eeFA1QyJ2trDezxeQM5ZFa1dXw1Mpl/+1vuXDKNjJgNyWYwKp/NwRkLmrsuV0yv4UDCDe4kJOGbPKnw== dependencies: tslib "^1.9.0" -"@angular/core@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.15.tgz#c00d4be0ebe95b70f7631154169509cc97934e9a" - integrity sha512-XsuYm0jEU/mOqwDOk2utThv8J9kESkAerfuCHClE9rB2TtHUOGCfekF7lJWqjjypu6/J9ygoPFo7hdAE058ZGg== +"@angular/core@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-8.2.14.tgz#35566f5b19480369229477e7e0e0fde740bd5204" + integrity sha512-zeePkigi+hPh3rN7yoNENG/YUBUsIvUXdxx+AZq+QPaFeKEA2FBSrKn36ojHFrdJUjKzl0lPMEiGC2b6a6bo6g== dependencies: tslib "^1.9.0" -"@angular/forms@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.15.tgz#6b6e10b5f4687b6be3081abcc02a055b3ceeb6d8" - integrity sha512-p0kcIQLtBBC1qeTA6M3nOuXf/k91E80FKquVM9zEsO2kDjI0oZJVfFYL2UMov5samlJOPN+t6lRHEIUa7ApPsw== +"@angular/forms@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-8.2.14.tgz#7d357c346a3884881beb044c50ec4a09d3d7ee8e" + integrity sha512-zhyKL3CFIqcyHJ/TQF/h1OZztK611a6rxuPHCrt/5Sn1SuBTJJQ1pPTkOYIDy6IrCrtyANc8qB6P17Mao71DNQ== dependencies: tslib "^1.9.0" -"@angular/http@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/http/-/http-7.2.15.tgz#a32bea9e67e99eef88150085aeebbe7aeecd39eb" - integrity sha512-TR7PEdmLWNIre3Zn8lvyb4lSrvPUJhKLystLnp4hBMcWsJqq5iK8S3bnlR4viZ9HMlf7bW7+Hm4SI6aB3tdUtw== +"@angular/platform-browser-dynamic@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.14.tgz#4439a79fe10ec45170e6940a28835e9ff0918950" + integrity sha512-mO2JPR5kLU/A3AQngy9+R/Q5gaF9csMStBQjwsCRI0wNtlItOIGL6+wTYpiTuh/ux+WVN1F2sLcEYU4Zf1ud9A== dependencies: tslib "^1.9.0" -"@angular/platform-browser-dynamic@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.15.tgz#e697159b565ef78bd7d276fa876d099172ad8735" - integrity sha512-UL2PqhzXMD769NQ6Lh6pxlBDKvN9Qol3XLRFil80lwJ1GRW16ITeYbCamcafIH2GOyd88IhmYcbMfUQ/6q4MMQ== +"@angular/platform-browser@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-8.2.14.tgz#31f082e8ba977f9b89964d721c38cbc32ce0e433" + integrity sha512-MtJptptyKzsE37JZ2VB/tI4cvMrdAH+cT9pMBYZd66YSZfKjIj5s+AZo7z8ncoskQSB1o3HMfDjSK7QXGx1mLQ== dependencies: tslib "^1.9.0" -"@angular/platform-browser@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.15.tgz#d6df74c427453e563c12bc2ec03a83bf10bb3805" - integrity sha512-aYgmPsbC9Tvp9vmKWD8voeAp4crwCay7/D6lM3ClEe2EeK934LuEXq3/uczMrFVbnIX7BBIo8fh03Tl7wbiGPw== +"@angular/platform-server@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-8.2.14.tgz#393e42d82022ad072b652999696bd5fa0b5c6928" + integrity sha512-gGAgxMmac5CyLcwgB+qCD1o75An0NmpREh/lxPgz6n6Zs9JqdqpZROLSIHqGBaU6MWo1qiOfS6L08HwYPx7ipQ== dependencies: - tslib "^1.9.0" - -"@angular/platform-server@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-7.2.15.tgz#06c8a4c1850da6289f643bd690fc7e1e8bdd6376" - integrity sha512-a7XhYlbmQ7pN6liFq8WqdX4GNoxCIXhlZqotZkfwJDsDy2E2yyvVx6BYCEOnSRvO9xXwfyBXiLfZ4Y2A7xeCoQ== - dependencies: - domino "^2.1.0" + domino "^2.1.2" tslib "^1.9.0" xhr2 "^0.1.4" -"@angular/router@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-7.2.15.tgz#b2acbd07c17158801006cdd7e93113d6ec1f116e" - integrity sha512-qAubRJRQanguUqJQ76J9GSZ4JFtoyhJKRmX5P23ANZJXpB6YLzF2fJmOGi+E6cV8F0tKBMEq1pjxFTisx0MXwQ== +"@angular/router@^8.2.14": + version "8.2.14" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-8.2.14.tgz#5f9f9707710983c2143aead79dcd2da520ae3eb8" + integrity sha512-DHA2BhODqV7F0g6ZKgFaZgbsqzHHWRcfWchCOrOVKu2rYiKUTwwHVLBgZAhrpNeinq2pWanVYSIhMr7wy+LfEA== dependencies: tslib "^1.9.0" @@ -247,6 +257,257 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/compat-data@^7.8.0", "@babel/compat-data@^7.8.4": + version "7.8.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.8.5.tgz#d28ce872778c23551cbb9432fc68d28495b613b9" + integrity sha512-jWYUqQX/ObOhG1UiEkbH5SANsE/8oKXiQWjj7p7xgj9Zmnt//aUvyz4dBkK0HNsS8/cbyC5NmmH87VekW+mXFg== + dependencies: + browserslist "^4.8.5" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" + integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helpers" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.7.5": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.8.3", "@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== + dependencies: + "@babel/types" "^7.8.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-call-delegate@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" + integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-compilation-targets@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.4.tgz#03d7ecd454b7ebe19a254f76617e61770aed2c88" + integrity sha512-3k3BsKMvPp5bjxgMdrFyq0UaEO48HciVrOVF0+lon8pp95cyJ2ujAh0TrBHNMnJGT2rr0iKOJPFFbSqjDyf/Pg== + dependencies: + "@babel/compat-data" "^7.8.4" + browserslist "^4.8.5" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-regexp-features-plugin@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" + integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== + dependencies: + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.6.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== + dependencies: + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" + integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" + integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.8.3", "@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -256,6 +517,449 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.7.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz#ae10b3214cb25f7adb1f3bc87ba42ca10b7e2543" + integrity sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" + integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" + integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-destructuring@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" + integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" + integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-modules-amd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" + integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" + integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" + integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== + dependencies: + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" + integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== + dependencies: + "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" + integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typeof-symbol@^7.8.3": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/preset-env@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.3.tgz#dc0fb2938f52bbddd79b3c861a4b3427dd3a6c54" + integrity sha512-Rs4RPL2KjSLSE2mWAx5/iCH+GC1ikKdxPrhnRS6PfFVaiZeom22VFKN4X8ZthyN61kAaR05tfXTbCvatl9WIQg== + dependencies: + "@babel/compat-data" "^7.8.0" + "@babel/helper-compilation-targets" "^7.8.3" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.8.3" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.8.3" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.8.3" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.8.3" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.8.3" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.8.3" + "@babel/plugin-transform-modules-systemjs" "^7.8.3" + "@babel/plugin-transform-modules-umd" "^7.8.3" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.8.3" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.3" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.3" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/types" "^7.8.3" + browserslist "^4.8.2" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.0" + semver "^5.5.0" + "@babel/runtime-corejs3@^7.7.4": version "7.7.6" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.7.6.tgz#5b1044ea11b659d288f77190e19c62da959ed9a3" @@ -271,11 +975,49 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/template@^7.7.4", "@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.4" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@fortawesome/fontawesome-free@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.5.0.tgz#0c6c53823d04457ae669cd19567b8a21dbb4fcfd" integrity sha512-p4lu0jfj5QN013ddArh99r3OXZ/fp9rbovs62LfaO70OMBsAXxtNd0lAq/97fitrscR0fqfd+/a5KNcp6Sh/0A== +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -284,72 +1026,72 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@ng-bootstrap/ng-bootstrap@^4.1.0": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-4.2.2.tgz#a1c3a9576656cb4f793bbc3df56dfbdeb098f2fb" - integrity sha512-v8QmC17bv9he5Ep6zutaI9aQ2w/2NqySP0fejOKe7cacKpGUqsLIakpyd2FD7mfZu7pSCCtHYpRWR+h6yq+Ngg== +"@ng-bootstrap/ng-bootstrap@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-5.2.1.tgz#4fea4b561a8fa2422d31d492ffa3843b22669cfd" + integrity sha512-73/FX3wkDCQgdTBIa/pAOUB+DQLbag2vET3NIaqNz8Zno6cilkefY1zdlQ2zbwONcGzCyoTPFAUPivHgvoy9/w== dependencies: tslib "^1.9.0" -"@ng-dynamic-forms/core@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/core/-/core-7.2.0.tgz#788253da5f0bc44ea69cd1eb0071b78f091ea389" - integrity sha512-eRb26jDNIXiBla0hzgEpdL1Za9e6RD9phbV9PxzIkNlYKY2+FQowQBPmGBuck21E9okfVkEle2RJ4lUmozV5jw== +"@ng-dynamic-forms/core@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/core/-/core-8.1.1.tgz#41af2d95f6b0e426030aa993be5d4937c81a8e10" + integrity sha512-x0wUAv2r929CqTbRnAutAWmrSKd0pbbk4hwqguMl3D4Xk2/Qc565LYWWFRnq+Xr9NgyCONXKBu9unxspfG4g0A== dependencies: tslib "^1.9.0" -"@ng-dynamic-forms/ui-ng-bootstrap@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/ui-ng-bootstrap/-/ui-ng-bootstrap-7.2.0.tgz#b01da1f0a149108218eb0a1e6f26700a6a5bdbb9" - integrity sha512-iX6/7p5FK7yCEDxbKRs//JwsklQGx//0LyB4FkzPil7LNjXqJCabA7WS3+lUFZQdYXM0fAcyve+UZJCM7yTZiA== +"@ng-dynamic-forms/ui-ng-bootstrap@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@ng-dynamic-forms/ui-ng-bootstrap/-/ui-ng-bootstrap-8.1.1.tgz#a2444ec68c3416533b625b74ce861ea06dcaa74b" + integrity sha512-LJEbJatev6Lg+Fs6/+xxXJ2DydUO/5sEC2hwTET8BRZmeThL7//4cLbOTKihY2X/JL16cEsIFB8mxgfBeJ2c3Q== dependencies: tslib "^1.9.0" -"@ngrx/effects@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-7.4.0.tgz#7d1977538cf85e42ab48fd648acdfbc8b52f93d3" - integrity sha512-YjgB17WnLCBDPjAkHduKWsLFSGLZryPaTjY3EIvMF+WTRPDlgC5SAv2n7p3YIei6g6IYcEvOwLWBqZHFUXTgBw== +"@ngrx/effects@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-8.6.0.tgz#a0d7339597a5128c5cf896ddcf93f73406a45860" + integrity sha512-JdyJLQbv/wnE0ZPY9DcDOtF9PzJuzsKWmIWgIGunHF18wdjk5O8Zpkcrxq18wDRL6geg5UTtNJRMvTQhpDbzow== -"@ngrx/entity@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/entity/-/entity-7.4.0.tgz#634cdff1db9629ca0e64c1d6b1e43dc15f4e2ca6" - integrity sha512-aFRDTNp6IFkYFlP9gV6hgNgtDYot9KYF8WVbaQTao9ihmdPumMBOCeRttPPiHS/cU41w9nW3xF53NgxQPnEiQA== +"@ngrx/entity@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/entity/-/entity-8.6.0.tgz#63e7875d0e83e552249b8b75bb9b6aba248cae2a" + integrity sha512-Qq+ANgsHd2/i7gam1j05hxA8kPWQyf5ewtCLlbtMJI/qLmvA6ruSE8PYNNwrt90wm4BWdks2zKE5ERzvPzto0w== -"@ngrx/router-store@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-7.4.0.tgz#69c085bda3022117169f87ed5753b951de7d376d" - integrity sha512-ZpwTO1/ha3pxO7NV3jIfnwipBN1A719IjAOgrcmI8Ut06VH3HY/7JVFTkwLN/FyuHvl4EOlAVYmMAblmrymUWA== +"@ngrx/router-store@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-8.6.0.tgz#3bda275722e476e8604fd57af81f37687662d673" + integrity sha512-4Dvl6dfOj15lNZ63wucRNcTEHUi0hEqapOBVRslfAsnaSRo2t1lOvfX7b68IbxPiqzabTBdIeEkJwAC2q/rZZg== -"@ngrx/schematics@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-7.4.0.tgz#c430e11e60b4ef9cd60d92569da65b29847bce89" - integrity sha512-H0endOV7nYWDaFH7mOJAWFGVymlOYynwjEHZPWeLQFZIFUaekKOrgrHpc+rygu1Hov5ww8lNXHgAunm4vpvwMA== +"@ngrx/schematics@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-8.6.0.tgz#5387c0abc438768e4cb56c0b617082e0db2f00d7" + integrity sha512-d28FVsLWFJYxpMFnqzWvdbFSSPNlLUIezd0c4zlyf4CyNS/C8aw6Lio9xjOJHhgZuHvFuO9GwRrYV/GaS6wC7A== -"@ngrx/store-devtools@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-7.4.0.tgz#5a73469c70322351c4224f4529c5123f587a5997" - integrity sha512-ZmPpquprBYUozbLuLMLZzUhI+LnMNGMNg8x1ij9yDxXWQADcJm1Zu7kouYE1r5SoCYxKfwJ3Ia1VQfS3A5S8dw== +"@ngrx/store-devtools@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-8.6.0.tgz#ac287e4b094d099781cdc9f3281039c0e988296c" + integrity sha512-PWZmiOZE0J56GFfZpuzKLb7w0K2c6OXZSp/eWDeAvtdHFD4/Nas1i4TXtiWWMWWnSZeNs0hNIg4nFJXi2EddJQ== -"@ngrx/store@^7.3.0": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-7.4.0.tgz#525a343aa45d7f6ca60f3301a23a27669c14bbce" - integrity sha512-kwTUHgfgBeAL4RQBjZO46z9v4Xzg8PXAgY4WwXdt3zUk1tF4ZvijMleFvFRUoiJJfxF/UM6jgIZ/yGrX2dXQuA== +"@ngrx/store@^8.6.0": + version "8.6.0" + resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-8.6.0.tgz#8540c5bd40b33fc2f443e7e86f47c0d801b8f413" + integrity sha512-K4cvCEa+5hw9qrETQWO+Cha3YbVCAT8yaIKJr/N35KntTL9mQMjoL+51JWLZfBwPV0e19CFgJIyrBnVUTxwr2A== -"@ngtools/webpack@7.3.9", "@ngtools/webpack@^7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.3.9.tgz#db115dba8cc0886d8d822723be4119d3849fb4e3" - integrity sha512-+ROpqfCXLdQwfP+UNDLk4p959ZrocpStkdd2Iy9CeOJ8yDkityqpstTwQC3oHzzu/95BiyZ0hrHbM6AsPPIvJg== +"@ngtools/webpack@8.3.25", "@ngtools/webpack@^8.3.25": + version "8.3.25" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.3.25.tgz#f33dfb114463662b16b719031fd99ebf21354cf1" + integrity sha512-yHvgxXUXlgdWijtzcRjTaUqzK+6TVK/8p7PreBR00GsLxhl4U1jQSC6yDaZUCjOaEkiczFWl4hEuC4wTU/hLdg== dependencies: - "@angular-devkit/core" "7.3.9" + "@angular-devkit/core" "8.3.25" enhanced-resolve "4.1.0" - rxjs "6.3.3" - tree-kill "1.2.1" - webpack-sources "1.3.0" + rxjs "6.4.0" + tree-kill "1.2.2" + webpack-sources "1.4.3" -"@nguniversal/express-engine@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-7.1.1.tgz#9445ccb374dabdadccc8de98ca8a79b536ae14de" - integrity sha512-RJ2VATA6s48bYNrAfjnkjUCohpR7ehiOySwGA2vuUIWCWXKDIIPxgmET5ffVHy1a2XdMsOgrQ9Whth7+CxnUgw== +"@nguniversal/express-engine@^8.2.6": + version "8.2.6" + resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-8.2.6.tgz#3930551727b5be1256f0aefa1ffd3c37cb420f9f" + integrity sha512-IKUKTpesgjYyB0Xg+fFhSbwbGBJhG0Wfn8MkQAi9RgSi8QsrSMkI3oUXc86Z7fpQL55D/ZIH7PekoC0Fmh/kxA== "@ngx-translate/core@11.0.1": version "11.0.1" @@ -365,10 +1107,10 @@ dependencies: tslib "^1.9.0" -"@nicky-lenaers/ngx-scroll-to@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@nicky-lenaers/ngx-scroll-to/-/ngx-scroll-to-1.0.0.tgz#2afdc03e5b3218bbb5e19ec69fb1e7f7c8eb83dc" - integrity sha512-IBKmt9D8gkntSwwQyAWCtOY552JLWcwTDlKOduEF6h8SYfpc1eSJu65rz8zHpur2MRZeLCGaIV+woBLpGYk8YQ== +"@nicky-lenaers/ngx-scroll-to@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@nicky-lenaers/ngx-scroll-to/-/ngx-scroll-to-3.0.1.tgz#e690e2ce7c6195373ad223cee411daaab3831b12" + integrity sha512-n7kwFUfV7B2UyRDQPegziXPp9zmRdEZiIgk2jJSirLrZf2jW96r25DNOvoahjQnK4PS3at+JD9LIWF+WyI0Lhg== dependencies: tslib "^1.9.0" @@ -377,14 +1119,13 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.1.tgz#53f349bb986ab273d601175aa1b25a655ab90ee3" integrity sha512-KU/VDjC5RwtDUZiz3d+DHXJF2lp5hB9dn552TXIyptj8SH1vXmR40mG0JgGq03IlYsOgGfcv8xrLpSQ0YUMQdA== -"@schematics/angular@7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.3.9.tgz#f57baf1cd9588d4f1035974d06fd8f3d54df021a" - integrity sha512-B3lytFtFeYNLfWdlrIzvy3ulFRccD2/zkoL0734J+DAGfUz7vbysJ50RwYL46sQUcKdZdvb48ktfu1S8yooP6Q== +"@schematics/angular@8.3.25": + version "8.3.25" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.3.25.tgz#11252399e30e2ddb94323e5e438bb69839fb9464" + integrity sha512-/vEPtE+fvgsWPml/MVqzmlGPBujadPPNwaTuuj5Uz1aVcKeEYzLkbN8YQOpml4vxZHCF8RDwNdGiU4SZg63Jfg== dependencies: - "@angular-devkit/core" "7.3.9" - "@angular-devkit/schematics" "7.3.9" - typescript "3.2.4" + "@angular-devkit/core" "8.3.25" + "@angular-devkit/schematics" "8.3.25" "@schematics/angular@^0.7.5": version "0.7.5" @@ -395,18 +1136,18 @@ "@angular-devkit/schematics" "0.7.5" typescript ">=2.6.2 <2.10" -"@schematics/update@0.13.9": - version "0.13.9" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.13.9.tgz#60d338676d10d24d1b12812a0624f6e7c3dbcd06" - integrity sha512-4MQcaKFxhMzZyE//+DknDh3h3duy3avg2oxSHxdwXlCZ8Q92+4lpegjJcSRiqlEwO4qeJ5XnrjrvzfIiaIZOmA== +"@schematics/update@0.803.25": + version "0.803.25" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.803.25.tgz#d424dfb4eaa06215ea447993613da2730327097b" + integrity sha512-VIlqhJsCStA3aO4llxZ7lAOvQUqppyZdrEO7f/ApIJmuofPQTkO5Hx21tnv0dyExwoqPCSIHzEu4Tmc0/TWM1A== dependencies: - "@angular-devkit/core" "7.3.9" - "@angular-devkit/schematics" "7.3.9" + "@angular-devkit/core" "8.3.25" + "@angular-devkit/schematics" "8.3.25" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" - pacote "9.4.0" - rxjs "6.3.3" - semver "5.6.0" + pacote "9.5.5" + rxjs "6.4.0" + semver "6.3.0" semver-intersect "1.4.0" "@types/acorn@^4.0.3": @@ -701,15 +1442,6 @@ semver "^6.3.0" tsutils "^3.17.1" -"@webassemblyjs/ast@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" - integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== - dependencies: - "@webassemblyjs/helper-module-context" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/wast-parser" "1.7.11" - "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -719,43 +1451,21 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wast-parser" "1.8.5" -"@webassemblyjs/floating-point-hex-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" - integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== - "@webassemblyjs/floating-point-hex-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== -"@webassemblyjs/helper-api-error@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" - integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== - "@webassemblyjs/helper-api-error@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== -"@webassemblyjs/helper-buffer@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" - integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== - "@webassemblyjs/helper-buffer@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== -"@webassemblyjs/helper-code-frame@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" - integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== - dependencies: - "@webassemblyjs/wast-printer" "1.7.11" - "@webassemblyjs/helper-code-frame@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" @@ -763,21 +1473,11 @@ dependencies: "@webassemblyjs/wast-printer" "1.8.5" -"@webassemblyjs/helper-fsm@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" - integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== - "@webassemblyjs/helper-fsm@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== -"@webassemblyjs/helper-module-context@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" - integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== - "@webassemblyjs/helper-module-context@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" @@ -786,26 +1486,11 @@ "@webassemblyjs/ast" "1.8.5" mamacro "^0.0.3" -"@webassemblyjs/helper-wasm-bytecode@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" - integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== - "@webassemblyjs/helper-wasm-bytecode@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== -"@webassemblyjs/helper-wasm-section@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" - integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - "@webassemblyjs/helper-wasm-section@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" @@ -816,13 +1501,6 @@ "@webassemblyjs/helper-wasm-bytecode" "1.8.5" "@webassemblyjs/wasm-gen" "1.8.5" -"@webassemblyjs/ieee754@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" - integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== - dependencies: - "@xtuc/ieee754" "^1.2.0" - "@webassemblyjs/ieee754@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" @@ -830,13 +1508,6 @@ dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" - integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== - dependencies: - "@xtuc/long" "4.2.1" - "@webassemblyjs/leb128@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" @@ -844,30 +1515,11 @@ dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" - integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== - "@webassemblyjs/utf8@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== -"@webassemblyjs/wasm-edit@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" - integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/helper-wasm-section" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - "@webassemblyjs/wasm-opt" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - "@webassemblyjs/wast-printer" "1.7.11" - "@webassemblyjs/wasm-edit@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" @@ -882,17 +1534,6 @@ "@webassemblyjs/wasm-parser" "1.8.5" "@webassemblyjs/wast-printer" "1.8.5" -"@webassemblyjs/wasm-gen@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" - integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/ieee754" "1.7.11" - "@webassemblyjs/leb128" "1.7.11" - "@webassemblyjs/utf8" "1.7.11" - "@webassemblyjs/wasm-gen@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" @@ -904,16 +1545,6 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" -"@webassemblyjs/wasm-opt@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" - integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - "@webassemblyjs/wasm-opt@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" @@ -924,18 +1555,6 @@ "@webassemblyjs/wasm-gen" "1.8.5" "@webassemblyjs/wasm-parser" "1.8.5" -"@webassemblyjs/wasm-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" - integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-api-error" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/ieee754" "1.7.11" - "@webassemblyjs/leb128" "1.7.11" - "@webassemblyjs/utf8" "1.7.11" - "@webassemblyjs/wasm-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" @@ -948,18 +1567,6 @@ "@webassemblyjs/leb128" "1.8.5" "@webassemblyjs/utf8" "1.8.5" -"@webassemblyjs/wast-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" - integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/floating-point-hex-parser" "1.7.11" - "@webassemblyjs/helper-api-error" "1.7.11" - "@webassemblyjs/helper-code-frame" "1.7.11" - "@webassemblyjs/helper-fsm" "1.7.11" - "@xtuc/long" "4.2.1" - "@webassemblyjs/wast-parser@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" @@ -972,15 +1579,6 @@ "@webassemblyjs/helper-fsm" "1.8.5" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" - integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/wast-parser" "1.7.11" - "@xtuc/long" "4.2.1" - "@webassemblyjs/wast-printer@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" @@ -995,11 +1593,6 @@ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== -"@xtuc/long@4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" - integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== - "@xtuc/long@4.2.2": version "4.2.2" resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" @@ -1044,11 +1637,6 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-dynamic-import@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" - integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== - acorn-jsx@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" @@ -1064,16 +1652,16 @@ acorn@^5.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" integrity sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw== -acorn@^6.0.5, acorn@^6.2.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" - integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== - acorn@^6.0.7: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== +acorn@^6.2.1: + version "6.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" + integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== + acorn@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" @@ -1089,7 +1677,7 @@ after@0.8.2: resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= -agent-base@4: +agent-base@4, agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== @@ -1133,10 +1721,10 @@ ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" - integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA== +ajv@6.10.2, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -1153,16 +1741,6 @@ ajv@^5.0.0, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - ajv@^6.1.1: version "6.5.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" @@ -1198,11 +1776,6 @@ angular-idle-preload@3.0.0: resolved "https://registry.yarnpkg.com/angular-idle-preload/-/angular-idle-preload-3.0.0.tgz#decace34d9fac1cb00000727a6dc5caafdb84e4d" integrity sha512-W3P2m2B6MHdt1DVunH6H3VWkAZrG3ZwxGcPjedVvIyRhg/LmMtILoizHSxTXw3fsKIEdAPwGObXGpML9WD1jJA== -angular-sortablejs@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/angular-sortablejs/-/angular-sortablejs-2.6.0.tgz#d41a5dcaf1dd08bcd79677b1fc0c64fb872fe2d3" - integrity sha512-f/W5WUeySMLhMqUHpAqzHCi3+yj6uwPcwr5FcKRRF+o5nzuYR5ppW1GJJk/Px1Q0HhL2//z9O3QZpEVMlvHf5w== - angular2-template-loader@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/angular2-template-loader/-/angular2-template-loader-0.6.2.tgz#c0d44e90fff0fac95e8b23f043acda7fd1c51d7c" @@ -1231,6 +1804,11 @@ ansi-align@^2.0.0: dependencies: string-width "^2.0.0" +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + ansi-colors@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" @@ -1255,11 +1833,6 @@ ansi-escapes@^1.1.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== - ansi-escapes@^4.2.1: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d" @@ -1336,12 +1909,20 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-root-path@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== @@ -1375,14 +1956,6 @@ archiver@^3.0.0: tar-stream "^2.1.0" zip-stream "^2.1.2" -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1505,7 +2078,7 @@ arrify@^1.0.0, arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@~2.0.3: +asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -1563,11 +2136,6 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-foreach@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" - integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -1609,17 +2177,18 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@9.4.6: - version "9.4.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.6.tgz#0ace275e33b37de16b09a5547dbfe73a98c1d446" - integrity sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw== +autoprefixer@9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" + integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw== dependencies: - browserslist "^4.4.1" - caniuse-lite "^1.0.30000929" + browserslist "^4.6.3" + caniuse-lite "^1.0.30000980" + chalk "^2.4.2" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.13" - postcss-value-parser "^3.3.1" + postcss "^7.0.17" + postcss-value-parser "^4.0.0" autoprefixer@^7.1.1: version "7.2.6" @@ -1693,6 +2262,13 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + babel-polyfill@6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" @@ -1855,6 +2431,18 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU= +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" @@ -1867,13 +2455,6 @@ blob@0.0.4: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - blocking-proxy@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" @@ -2012,6 +2593,13 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -2081,6 +2669,15 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +browserslist@4.8.6, browserslist@^4.6.3, browserslist@^4.8.2, browserslist@^4.8.3, browserslist@^4.8.5: + version "4.8.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.6.tgz#96406f3f5f0755d272e27a66f4163ca821590a7e" + integrity sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg== + dependencies: + caniuse-lite "^1.0.30001023" + electron-to-chromium "^1.3.341" + node-releases "^1.1.47" + browserslist@^2.0.0, browserslist@^2.11.3: version "2.11.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" @@ -2107,15 +2704,6 @@ browserslist@^4.0.2: electron-to-chromium "^1.3.61" node-releases "^1.0.0-alpha.11" -browserslist@^4.4.1: - version "4.8.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289" - integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA== - dependencies: - caniuse-lite "^1.0.30001015" - electron-to-chromium "^1.3.322" - node-releases "^1.1.42" - browserstack@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.1.tgz#e2dfa66ffee940ebad0a07f7e00fd4687c455d66" @@ -2213,35 +2801,17 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@^10.0.4: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cacache@^11.0.2, cacache@^11.3.2, cacache@^11.3.3: - version "11.3.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" - integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== +cacache@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c" + integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg== dependencies: bluebird "^3.5.5" chownr "^1.1.1" figgy-pudding "^3.5.1" glob "^7.1.4" graceful-fs "^4.1.15" + infer-owner "^1.0.3" lru-cache "^5.1.1" mississippi "^3.0.0" mkdirp "^0.5.1" @@ -2252,7 +2822,7 @@ cacache@^11.0.2, cacache@^11.3.2, cacache@^11.3.3: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^12.0.2, cacache@^12.0.3: +cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -2367,12 +2937,7 @@ camelcase@^2.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - -camelcase@^4.0.0, camelcase@^4.1.0: +camelcase@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -2402,21 +2967,26 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" +caniuse-lite@1.0.30001024: + version "1.0.30001024" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001024.tgz#7feb6793fd5c9d7e0d4c01c80321855592a46b73" + integrity sha512-LubRSEPpOlKlhZw9wGlLHo8ZVj6ugGU3xGUfLPneNBledSd9lIM5cCGZ9Mz/mMCJUhEt4jZpYteZNVRdJw5FRA== + caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000805, caniuse-lite@^1.0.30000878: version "1.0.30000883" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000883.tgz#597c1eabfb379bd9fbeaa778632762eb574706ac" integrity sha512-ovvb0uya4cKJct8Rj9Olstz0LaWmyJhCp3NawRG5fVigka8pEhIIwipF7zyYd2Q58UZb5YfIt52pVF444uj2kQ== -caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30001015: - version "1.0.30001016" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66" - integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA== - caniuse-lite@^1.0.30000939: version "1.0.30000948" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000948.tgz#793ed7c28fe664856beb92b43fc013fc22b81633" integrity sha512-Lw4y7oz1X5MOMZm+2IFaSISqVVQvUuD+ZUSfeYK/SlYiMjkHN/eJ2PDfJehW5NA6JjrxYSSnIWfwjeObQMEjFQ== +caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30001023: + version "1.0.30001025" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz#30336a8aca7f98618eb3cf38e35184e13d4e5fe6" + integrity sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ== + canonical-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" @@ -2479,7 +3049,22 @@ check-types@^7.3.0: resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== -chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: +"chokidar@>=2.0.0 <4.0.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" + integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.3.0" + optionalDependencies: + fsevents "~2.1.2" + +chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== @@ -2499,7 +3084,7 @@ chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.0 optionalDependencies: fsevents "^1.2.2" -chokidar@^2.1.1: +chokidar@^2.1.1, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -2537,23 +3122,11 @@ chokidar@^2.1.6: optionalDependencies: fsevents "^1.2.7" -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= - chownr@^1.1.1, chownr@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== -chrome-trace-event@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" - integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== - dependencies: - tslib "^1.9.0" - chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -2574,10 +3147,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" -circular-dependency-plugin@5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef" - integrity sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA== +circular-dependency-plugin@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz#e09dbc2dd3e2928442403e2d45b41cea06bc0a93" + integrity sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw== circular-json@^0.5.0: version "0.5.9" @@ -2638,15 +3211,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" @@ -2665,16 +3229,6 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -clone-deep@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" - integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== - dependencies: - for-own "^1.0.0" - is-plain-object "^2.0.4" - kind-of "^6.0.0" - shallow-clone "^1.0.0" - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -2843,7 +3397,7 @@ commander@2.17.x, commander@~2.17.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3: +commander@^2.11.0, commander@^2.20.0, commander@~2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2932,7 +3486,7 @@ compression@1.7.1: safe-buffer "5.1.1" vary "~1.1.2" -compression@^1.5.2, compression@^1.7.4: +compression@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== @@ -2972,7 +3526,7 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" -connect-history-api-fallback@^1.3.0, connect-history-api-fallback@^1.6.0: +connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== @@ -2994,11 +3548,6 @@ console-browserify@^1.1.0: dependencies: date-now "^0.1.4" -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -3026,6 +3575,13 @@ convert-source-map@^1.5.0, convert-source-map@^1.5.1: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + cookie-parser@1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5" @@ -3066,21 +3622,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" - integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - globby "^7.1.1" - is-glob "^4.0.0" - loader-utils "^1.1.0" - minimatch "^3.0.4" - p-limit "^1.0.0" - serialize-javascript "^1.4.0" - -copy-webpack-plugin@^5.1.1: +copy-webpack-plugin@5.1.1, copy-webpack-plugin@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== @@ -3110,21 +3652,29 @@ copyfiles@^2.1.1: through2 "^2.0.1" yargs "^13.2.4" +core-js-compat@^3.6.2: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== + dependencies: + browserslist "^4.8.3" + semver "7.0.0" + core-js-pure@^3.0.0: version "3.5.0" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.5.0.tgz#f63c7f2b245e7d678e73f87ad28505480554d70e" integrity sha512-wB0QtKAofWigiISuT1Tej3hKgq932fB//Lf1VoPbiLpTYlHY0nIDhgF+q1na0DAKFHH5wGCirkAknOmDN8ijXA== +core-js@3.6.4, core-js@^3.6.4: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.4.tgz#440a83536b458114b9cb2ac1580ba377dc470647" + integrity sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw== + core-js@^2.2.0, core-js@^2.4.0: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== -core-js@^2.6.5: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - core-js@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" @@ -3150,6 +3700,17 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" +coverage-istanbul-loader@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz#87d42f03fa0fd3fa8743ec76945d9d67f105722a" + integrity sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA== + dependencies: + convert-source-map "^1.7.0" + istanbul-lib-instrument "^4.0.0" + loader-utils "^1.2.3" + merge-source-map "^1.1.0" + schema-utils "^2.6.1" + coveralls@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.0.tgz#22ef730330538080d29b8c151dc9146afde88a99" @@ -3230,14 +3791,6 @@ cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.4, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" - integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= - dependencies: - lru-cache "^4.0.1" - which "^1.2.9" - cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -3561,7 +4114,7 @@ debug@*, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -3575,25 +4128,23 @@ debug@3.1.0, debug@^3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: +debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: ms "^2.1.1" -decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + +decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decamelize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" - integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== - dependencies: - xregexp "4.0.0" - decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -3609,11 +4160,6 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-freeze-strict@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz#77d0583ca24a69be4bbd9ac2fae415d55523e5b0" - integrity sha1-d9BYPKJKab5LvZrC+uQV1VUj5bA= - deep-freeze@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" @@ -3624,14 +4170,6 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -default-gateway@^2.6.0: - version "2.7.2" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" - integrity sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ== - dependencies: - execa "^0.10.0" - ip-regex "^2.1.0" - default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -3682,18 +4220,6 @@ del@^2.2.0: pinkie-promise "^2.0.0" rimraf "^2.2.8" -del@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" - integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= - dependencies: - globby "^6.1.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - p-map "^1.1.1" - pify "^3.0.0" - rimraf "^2.2.8" - del@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" @@ -3712,11 +4238,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" @@ -3762,16 +4283,19 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== +dezalgo@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + dependencies: + asap "^2.0.0" + wrappy "1" + di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" @@ -3873,7 +4397,7 @@ domhandler@2.1: dependencies: domelementtype "1" -domino@^2.1.0: +domino@^2.1.2: version "2.1.4" resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.4.tgz#78922e7fab7c610f35792b6c745b7962d342e9c4" integrity sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ== @@ -3973,10 +4497,10 @@ electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.61: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.62.tgz#2e8e2dc070c800ec8ce23ff9dfcceb585d6f9ed8" integrity sha512-x09ndL/Gjnuk3unlAyoGyUg3wbs4w/bXurgL7wL913vXHAOWmMhrLf1VNGRaMLngmadd5Q8gsV9BFuIr6rP+Xg== -electron-to-chromium@^1.3.322: - version "1.3.322" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" - integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== +electron-to-chromium@^1.3.341: + version "1.3.345" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz#2569d0d54a64ef0f32a4b7e8c80afa5fe57c5d98" + integrity sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg== elliptic@^6.0.0: version "6.4.1" @@ -4221,14 +4745,6 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" -eslint-scope@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" - integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4381,16 +4897,6 @@ eventemitter3@^3.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== -eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== - -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= - events@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" @@ -4548,7 +5054,7 @@ express@4.16.2: utils-merge "1.0.1" vary "~1.1.2" -express@^4.16.2, express@^4.16.3, express@^4.17.1: +express@^4.16.3, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== @@ -4627,15 +5133,6 @@ external-editor@^2.0.1: iconv-lite "^0.4.17" tmp "^0.0.33" -external-editor@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -4801,19 +5298,24 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-loader@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" - integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== +file-loader@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" + integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ== dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" + loader-utils "^1.2.3" + schema-utils "^2.0.0" 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== +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -4845,6 +5347,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" @@ -4871,16 +5380,16 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= +find-cache-dir@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.0.0.tgz#cd4b7dd97b7185b7e17dbfe2d6e4115ee3eeb8fc" + integrity sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw== dependencies: commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" + make-dir "^3.0.0" + pkg-dir "^4.1.0" -find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: +find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== @@ -4906,13 +5415,6 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -4977,11 +5479,6 @@ font-awesome@4.7.0: resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" integrity sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM= -for-in@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" - integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -4994,13 +5491,6 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -5147,31 +5637,18 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - -fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== +fsevents@^1.2.2, fsevents@^1.2.7: + version "1.2.11" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" + integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== dependencies: + bindings "^1.5.0" nan "^2.12.1" - node-pre-gyp "^0.12.0" -fstream@^1.0.0, fstream@^1.0.2: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" - integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" +fsevents@~2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" @@ -5183,32 +5660,16 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -gaze@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" - integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== - dependencies: - globule "^1.0.0" - genfun@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -5276,7 +5737,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0: +glob-parent@^5.0.0, glob-parent@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== @@ -5312,10 +5773,10 @@ glob@7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@7.1.4, glob@^7.1.3, glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -5335,10 +5796,10 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3, glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -5402,6 +5863,11 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^12.1.0: version "12.3.0" resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" @@ -5462,15 +5928,6 @@ globby@^8.0.0: pify "^3.0.0" slash "^1.0.0" -globule@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" - integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== - dependencies: - glob "~7.1.1" - lodash "~4.17.10" - minimatch "~3.0.2" - glogg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810" @@ -5649,11 +6106,6 @@ has-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -5792,7 +6244,7 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== -html-entities@^1.2.0, html-entities@^1.2.1: +html-entities@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= @@ -5887,7 +6339,7 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-middleware@^0.19.1: +http-proxy-middleware@0.19.1, http-proxy-middleware@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== @@ -5897,16 +6349,6 @@ http-proxy-middleware@^0.19.1: lodash "^4.17.11" micromatch "^3.1.10" -http-proxy-middleware@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" - integrity sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q== - dependencies: - http-proxy "^1.16.2" - is-glob "^4.0.0" - lodash "^4.17.5" - micromatch "^3.1.9" - http-proxy@^1.13.0, http-proxy@^1.17.0, http-proxy@^1.8.1: version "1.17.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" @@ -5916,15 +6358,6 @@ http-proxy@^1.13.0, http-proxy@^1.17.0, http-proxy@^1.8.1: follow-redirects "^1.0.0" requires-port "^1.0.0" -http-proxy@^1.16.2: - version "1.18.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" - integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - http-server@0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" @@ -5961,6 +6394,14 @@ https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + https@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https/-/https-1.0.0.tgz#3c37c7ae1a8eeb966904a2ad1e975a194b7ed3a4" @@ -5985,7 +6426,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -6097,11 +6538,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -in-publish@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" - integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= - indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" @@ -6137,7 +6573,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -6176,23 +6612,23 @@ inquirer@3.0.6: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" - integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== +inquirer@6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.1.tgz#8bfb7a5ac02dac6ff641ac4c5ff17da112fcdb42" + integrity sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw== dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" + ansi-escapes "^4.2.1" + chalk "^2.4.2" + cli-cursor "^3.1.0" cli-width "^2.0.0" - external-editor "^3.0.0" - figures "^2.0.0" - lodash "^4.17.10" - mute-stream "0.0.7" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" run-async "^2.2.0" - rxjs "^6.1.0" - string-width "^2.1.0" - strip-ansi "^5.0.0" + rxjs "^6.4.0" + string-width "^4.1.0" + strip-ansi "^5.1.0" through "^2.3.6" inquirer@^7.0.0: @@ -6214,14 +6650,6 @@ inquirer@^7.0.0: strip-ansi "^5.1.0" through "^2.3.6" -internal-ip@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27" - integrity sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q== - dependencies: - default-gateway "^2.6.0" - ipaddr.js "^1.5.2" - internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -6240,18 +6668,13 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" @@ -6277,7 +6700,7 @@ ipaddr.js@1.9.0: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== -ipaddr.js@^1.5.2, ipaddr.js@^1.9.0: +ipaddr.js@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== @@ -6287,6 +6710,11 @@ is-absolute-url@^2.0.0: resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -6318,6 +6746,13 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -6475,7 +6910,7 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-glob@^4.0.1: +is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -6519,6 +6954,11 @@ is-number@^4.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -6562,6 +7002,11 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -6714,6 +7159,11 @@ istanbul-lib-coverage@^1.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" integrity sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A== +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + istanbul-lib-instrument@^1.7.3: version "1.10.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" @@ -6727,6 +7177,19 @@ istanbul-lib-instrument@^1.7.3: istanbul-lib-coverage "^1.2.0" semver "^5.3.0" +istanbul-lib-instrument@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" + integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== + dependencies: + "@babel/core" "^7.7.5" + "@babel/parser" "^7.7.5" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + istanbul@0.4.5, istanbul@^0.4.0, istanbul@^0.4.3: version "0.4.5" resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" @@ -6785,14 +7248,7 @@ jasminewd2@^2.1.0: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= -jest-worker@^23.2.0: - version "23.2.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" - integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= - dependencies: - merge-stream "^1.0.1" - -jest-worker@^24.9.0: +jest-worker@24.9.0, jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -6800,10 +7256,12 @@ jest-worker@^24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" -js-base64@^2.1.8: - version "2.4.9" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.9.tgz#748911fb04f48a60c4771b375cac45a80df11c03" - integrity sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ== +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= + dependencies: + merge-stream "^1.0.1" js-cookie@2.2.0: version "2.2.0" @@ -6843,6 +7301,11 @@ jsesc@^1.3.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -7029,10 +7492,10 @@ karma-remap-istanbul@0.6.0: istanbul "^0.4.3" remap-istanbul "^0.9.0" -karma-source-map-support@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz#36dd4d8ca154b62ace95696236fae37caf0a7dde" - integrity sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q== +karma-source-map-support@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz#58526ceccf7e8730e56effd97a4de8d712ac0d6b" + integrity sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A== dependencies: source-map-support "^0.5.5" @@ -7100,7 +7563,7 @@ kew@^0.7.0: resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" integrity sha1-edk9LTM2PW/dKXCzNdkUGtWR15s= -killable@^1.0.0, killable@^1.0.1: +killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== @@ -7163,13 +7626,6 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -7182,14 +7638,14 @@ lcov-parse@^0.0.10: resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" integrity sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM= -less-loader@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" - integrity sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg== +less-loader@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466" + integrity sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg== dependencies: clone "^2.1.1" loader-utils "^1.1.0" - pify "^3.0.0" + pify "^4.0.1" less@3.9.0: version "3.9.0" @@ -7207,6 +7663,18 @@ less@3.9.0: request "^2.83.0" source-map "~0.6.0" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.0, levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -7215,10 +7683,10 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -license-webpack-plugin@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.0.tgz#83acaa6e89c3c5316effdd80cb4ec9c5cd8efc2f" - integrity sha512-vDiBeMWxjE9n6TabQ9J4FH8urFdsRK0Nvxn1cit9biCiR9aq1zBR0X2BlAkEiIG6qPamLeU0GzvIgLkrFc398A== +license-webpack-plugin@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.2.tgz#63f7c571537a450ec47dc98f5d5ffdbca7b3b14f" + integrity sha512-7poZHRla+ae0eEButlwMrPpkXyhNVBf2EHePYWT0jyLnI6311/OXJkTI2sOIRungRpQgU2oDMpro5bSFPT5F0A== dependencies: "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" @@ -7241,16 +7709,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -7261,11 +7719,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" - integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= - loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -7299,14 +7752,6 @@ loader-utils@^1.0.0: emojis-list "^2.0.0" json5 "^0.5.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -7367,12 +7812,7 @@ lodash._root@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= -lodash.assign@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= - -lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: +lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= @@ -7448,11 +7888,6 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.mergewith@^4.6.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -7463,11 +7898,6 @@ lodash.startswith@^4.2.1: resolved "https://registry.yarnpkg.com/lodash.startswith/-/lodash.startswith-4.2.1.tgz#c598c4adce188a27e53145731cdc6c0e7177600c" integrity sha1-xZjErc4YiiflMUVzHNxsDnF3YAw= -lodash.tail@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" - integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= - lodash.template@^3.0.0: version "3.6.2" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" @@ -7521,7 +7951,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -7549,16 +7979,16 @@ log4js@^4.0.0: rfdc "^1.1.4" streamroller "^1.0.6" -loglevel@^1.4.1: - version "1.6.6" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" - integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== - loglevel@^1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== +loglevel@^1.6.4: + version "1.6.6" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" + integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== + loglevelnext@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" @@ -7600,7 +8030,7 @@ lru-cache@4.1.x: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^4.0.1, lru-cache@^4.1.1: +lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== @@ -7615,6 +8045,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +magic-string@0.25.3: + version "0.25.3" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.3.tgz#34b8d2a2c7fec9d9bdf9929a3fd81d271ef35be9" + integrity sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA== + dependencies: + sourcemap-codec "^1.4.4" + magic-string@^0.22.4: version "0.22.5" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e" @@ -7656,16 +8093,16 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535" integrity sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g== -make-fetch-happen@^4.0.1, make-fetch-happen@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.2.tgz#2d156b11696fb32bffbafe1ac1bc085dd6c78a79" - integrity sha512-YMJrAjHSb/BordlsDEcVcPyTbiJKkzqMf48N8dAJZT9Zjctrkb6Yg4TY9Sq2AwSIQJFn5qBBKVTYt3vP5FMIHA== +make-fetch-happen@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" + integrity sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag== dependencies: agentkeepalive "^3.4.1" - cacache "^11.3.3" + cacache "^12.0.0" http-cache-semantics "^3.8.1" http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" + https-proxy-agent "^2.2.3" lru-cache "^5.1.1" mississippi "^3.0.0" node-fetch-npm "^2.0.2" @@ -7749,13 +8186,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - mem@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" @@ -7778,7 +8208,7 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= -meow@^3.3.0, meow@^3.7.0: +meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= @@ -7799,6 +8229,13 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== + dependencies: + source-map "^0.6.1" + merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" @@ -7845,7 +8282,7 @@ micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -7911,7 +8348,7 @@ mime@^2.1.0, mime@^2.3.1: resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" integrity sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg== -mime@^2.4.2: +mime@^2.4.2, mime@^2.4.4: version "2.4.4" resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== @@ -7926,12 +8363,13 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mini-css-extract-plugin@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0" - integrity sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw== +mini-css-extract-plugin@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1" + integrity sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw== dependencies: loader-utils "^1.1.0" + normalize-url "1.9.1" schema-utils "^1.0.0" webpack-sources "^1.1.0" @@ -7945,7 +8383,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -7993,7 +8431,7 @@ minipass-pipeline@^1.2.2: dependencies: minipass "^3.0.0" -minipass@^2.2.1, minipass@^2.3.3: +minipass@^2.2.1: version "2.3.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" integrity sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w== @@ -8016,13 +8454,6 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" -minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" - integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA== - dependencies: - minipass "^2.2.1" - minizlib@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" @@ -8030,22 +8461,6 @@ minizlib@^1.2.1: dependencies: minipass "^2.9.0" -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^2.0.1" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -8070,15 +8485,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mixin-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" - integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= - dependencies: - for-in "^0.1.3" - is-extendable "^0.1.1" - -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -8182,12 +8589,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.10.0, nan@^2.9.2: - version "2.11.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" - integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw== - -nan@^2.12.1, nan@^2.13.2: +nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -8219,15 +8621,6 @@ ncp@^2.0.0: resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= -needle@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.2.tgz#1120ca4c41f2fcc6976fd28a8968afe239929418" - integrity sha512-mW7W8dKuVYefCpNzE3Z7xUmPI9wSrSL/1qH31YGMxmSOAnjatS3S9Zv3cmiHrhx3Jkp1SrWWBdOFXjfF48Uq3A== - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -8248,10 +8641,10 @@ next-tick@~1.0.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= -ng-mocks@^7.6.0: - version "7.8.0" - resolved "https://registry.yarnpkg.com/ng-mocks/-/ng-mocks-7.8.0.tgz#05b9f46164ca8d22b72ee9ac2369f37b2434ceb2" - integrity sha512-QopwqQUeEoUmHZdJeEDG3koJ5woHYeVe3TEfRjVHwLyLfJ/wdcNcepdei6j9n9Ne42SpS2bOETgKBqUT5NUsng== +ng-mocks@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/ng-mocks/-/ng-mocks-8.1.0.tgz#d00a5e53ae53587f35c68147826590fab71a1658" + integrity sha512-/314nyU6UrONCUKfvFRuJPLpNBxqocwJmQBlPy4he5Vueu6gObXjy+KLUlbbENuA7zTeBjp//RA6w/Fa1yQ4Fw== ng2-file-upload@1.2.1: version "1.2.1" @@ -8263,17 +8656,10 @@ ng2-nouislider@^1.8.2: resolved "https://registry.yarnpkg.com/ng2-nouislider/-/ng2-nouislider-1.8.2.tgz#4d4aab402d307020415da1714a5e9f46817fe97c" integrity sha512-apCpRxwX/3VapLuPozZkUfM3HAE1unuCm2UdRMDvAHbbY6CLobaZcsWUYQ6b02VzxccyV4G1z0xsq2un8J2Lqw== -ngrx-store-freeze@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/ngrx-store-freeze/-/ngrx-store-freeze-0.2.4.tgz#146687cdf7e21244eb9003c7e883f2125847076c" - integrity sha512-90awpbbMa/x2H81eWWYniyli3LJ1PZU/FaztL10d9Rp/4kw2+97pqyLjdxSPxcOv9St//m9kfuWZ7gyoVDjgcg== - dependencies: - deep-freeze-strict "^1.1.1" - -ngx-bootstrap@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-3.2.0.tgz#ece7c48af0bc260462c3f77de14f22d4b3dde149" - integrity sha512-oLSLIWZgRiIfcuxyXLMZUOhX3wZtg6lpuMbdo/0UzMDg2bSOe1XPskcKZ/iuOa3FOlU9rjuYMzswHYYV5f/QCA== +ngx-bootstrap@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-5.3.2.tgz#0668b01202610657e998b3ca87669645e0b31dc9" + integrity sha512-gSMf8EXYl99Q3gqkq4RVhoTNSTYHz2Or6Cig2BJRbLJyqk15ZQE5qcq/ldHS8zzx/wgCA3HQeI63t2j2mEU9PA== ngx-infinite-scroll@6.0.1: version "6.0.1" @@ -8294,6 +8680,13 @@ ngx-pagination@3.0.3: resolved "https://registry.yarnpkg.com/ngx-pagination/-/ngx-pagination-3.0.3.tgz#314145263613738d8c544da36cd8dacc5aa89a6f" integrity sha1-MUFFJjYTc42MVE2jbNjazFqomm8= +ngx-sortablejs@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/ngx-sortablejs/-/ngx-sortablejs-3.1.4.tgz#8c2e29f8f6c0ea6cdf8298ae1438b522d0ed70b9" + integrity sha512-jrEC4loWf01JxBcPiOHiyHbXwNrs4acIus1c9NVv7hiK574dywoqOnL5/OVQFnluqItWC7llqCUXfDr3Kmyqfg== + dependencies: + tslib "^1.9.0" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -8333,53 +8726,6 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== -node-gyp@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" - integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== - dependencies: - fstream "^1.0.0" - glob "^7.0.3" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3 || 4" - osenv "0" - request "^2.87.0" - rimraf "2" - semver "~5.3.0" - tar "^2.0.0" - which "1" - -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.0" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -8409,38 +8755,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - node-releases@^1.0.0-alpha.11: version "1.0.0-alpha.11" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.11.tgz#73c810acc2e5b741a17ddfbb39dfca9ab9359d8a" @@ -8448,10 +8762,10 @@ node-releases@^1.0.0-alpha.11: dependencies: semver "^5.3.0" -node-releases@^1.1.42: - version "1.1.42" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7" - integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA== +node-releases@^1.1.47: + version "1.1.47" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" + integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== dependencies: semver "^6.3.0" @@ -8462,54 +8776,6 @@ node-releases@^1.1.8: dependencies: semver "^5.3.0" -node-sass@4.12.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017" - integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ== - dependencies: - async-foreach "^0.1.3" - chalk "^1.1.1" - cross-spawn "^3.0.0" - gaze "^1.0.0" - get-stdin "^4.0.1" - glob "^7.0.3" - in-publish "^2.0.0" - lodash "^4.17.11" - meow "^3.7.0" - mkdirp "^0.5.1" - nan "^2.13.2" - node-gyp "^3.8.0" - npmlog "^4.0.0" - request "^2.88.0" - sass-graph "^2.2.4" - stdout-stream "^1.4.0" - "true-case-path" "^1.0.2" - -node-sass@^4.11.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a" - integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA== - dependencies: - async-foreach "^0.1.3" - chalk "^1.1.1" - cross-spawn "^3.0.0" - gaze "^1.0.0" - get-stdin "^4.0.1" - glob "^7.0.3" - in-publish "^2.0.0" - lodash.assign "^4.2.0" - lodash.clonedeep "^4.3.2" - lodash.mergewith "^4.6.0" - meow "^3.7.0" - mkdirp "^0.5.1" - nan "^2.10.0" - node-gyp "^3.8.0" - npmlog "^4.0.0" - request "^2.88.0" - sass-graph "^2.2.4" - stdout-stream "^1.4.0" - "true-case-path" "^1.0.2" - nodemon@^1.15.0: version "1.18.4" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.4.tgz#873f65fdb53220eb166180cf106b1354ac5d714d" @@ -8534,21 +8800,13 @@ noms@0.0.0: inherits "^2.0.1" readable-stream "~1.0.31" -"nopt@2 || 3", nopt@3.x: +nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -8556,6 +8814,16 @@ nopt@~1.0.10: dependencies: abbrev "1" +normalize-package-data@^2.0.0, normalize-package-data@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" @@ -8566,16 +8834,6 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -8583,7 +8841,7 @@ normalize-path@^2.0.1, normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -8593,6 +8851,16 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= +normalize-url@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + normalize-url@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" @@ -8608,6 +8876,11 @@ npm-bundled@^1.0.1: resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== +npm-normalize-package-bin@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + npm-package-arg@6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" @@ -8636,13 +8909,14 @@ npm-packlist@^1.1.12: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-packlist@^1.1.6: - version "1.1.11" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" - integrity sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA== +npm-pick-manifest@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" + integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" npm-pick-manifest@^2.2.3: version "2.2.3" @@ -8653,17 +8927,18 @@ npm-pick-manifest@^2.2.3: npm-package-arg "^6.0.0" semver "^5.4.1" -npm-registry-fetch@^3.8.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.1.tgz#00ff6e4e35d3f75a172b332440b53e93f4cb67de" - integrity sha512-VQCEZlydXw4AwLROAXWUR7QDfe2Y8Id/vpAgp6TI1/H78a4SiQ1kQrKZALm5/zxM5n4HIi+aYb+idUAV/RuY0Q== +npm-registry-fetch@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz#2b1434f93ccbe6b6385f8e45f45db93e16921d7a" + integrity sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A== dependencies: JSONStream "^1.3.4" bluebird "^3.5.1" figgy-pudding "^3.4.1" lru-cache "^5.1.1" - make-fetch-happen "^4.0.2" + make-fetch-happen "^5.0.0" npm-package-arg "^6.1.0" + safe-buffer "^5.2.0" npm-run-all@4.1.3: version "4.1.3" @@ -8687,16 +8962,6 @@ npm-run-path@^2.0.0, npm-run-path@^2.0.2: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - nth-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -8858,10 +9123,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.0.0.tgz#cae5e2c1a3a1bfaee0d0acc8c4b7609374750346" - integrity sha512-/yb5mVZBz7mHLySMiSj2DcLtMBbFPJk5JBKEkHVZFxZAPzeg3L026O0T+lbdz1B2nyDnkClRSwRQJdeVUIF7zw== +open@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" + integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== dependencies: is-wsl "^1.1.0" @@ -8895,7 +9160,7 @@ opn@4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" -opn@^5.1.0, opn@^5.5.0: +opn@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== @@ -8959,22 +9224,6 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" - -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - os-locale@^3.0.0, os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -8989,7 +9238,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@0, osenv@^0.1.4, osenv@^0.1.5: +osenv@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -9012,13 +9261,6 @@ p-is-promise@^2.0.0: resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== -p-limit@^1.0.0, p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" @@ -9033,13 +9275,6 @@ p-limit@^2.2.0, p-limit@^2.2.1: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -9054,11 +9289,6 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-map@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== - p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -9078,11 +9308,6 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" @@ -9098,18 +9323,19 @@ package-json@^4.0.0: registry-url "^3.0.3" semver "^5.1.0" -pacote@9.4.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807" - integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w== +pacote@9.5.5: + version "9.5.5" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.5.tgz#63355a393614c3424e735820c3731e2cbbedaeeb" + integrity sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA== dependencies: bluebird "^3.5.3" - cacache "^11.3.2" + cacache "^12.0.2" figgy-pudding "^3.5.1" get-stream "^4.1.0" glob "^7.1.3" + infer-owner "^1.0.4" lru-cache "^5.1.1" - make-fetch-happen "^4.0.1" + make-fetch-happen "^5.0.0" minimatch "^3.0.4" minipass "^2.3.5" mississippi "^3.0.0" @@ -9118,7 +9344,7 @@ pacote@9.4.0: npm-package-arg "^6.1.0" npm-packlist "^1.1.12" npm-pick-manifest "^2.2.3" - npm-registry-fetch "^3.8.0" + npm-registry-fetch "^4.0.0" osenv "^0.1.5" promise-inflight "^1.0.1" promise-retry "^1.1.1" @@ -9244,11 +9470,6 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= - path-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -9310,13 +9531,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -9377,6 +9591,11 @@ phantomjs-prebuilt@^2.1.7: request-progress "^2.0.1" which "^1.2.10" +picomatch@^2.0.4, picomatch@^2.0.7: + version "2.2.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" + integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -9413,13 +9632,6 @@ pixrem@^4.0.0: postcss "^6.0.0" reduce-css-calc "^1.2.7" -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -9481,7 +9693,7 @@ portfinder@^1.0.20: debug "^2.2.0" mkdirp "0.5.x" -portfinder@^1.0.9: +portfinder@^1.0.25: version "1.0.25" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== @@ -10192,10 +10404,10 @@ postcss-values-parser@^1.5.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@7.0.14, postcss@^7.0.1, postcss@^7.0.5: - version "7.0.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" - integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== +postcss@7.0.17: + version "7.0.17" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" + integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -10210,7 +10422,7 @@ postcss@^6.0, postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.14, source-map "^0.6.1" supports-color "^5.4.0" -postcss@^7.0.0, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.6: +postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.6: version "7.0.25" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.25.tgz#dd2a2a753d50b13bed7a2009b4a18ac14d9db21e" integrity sha512-NXXVvWq9icrm/TgQC0O6YVFi4StfJz46M1iNd/h6B26Nvh/HKI+q4YZtFN/EjcInZliEscO/WL10BXnc1E5nwg== @@ -10219,6 +10431,24 @@ postcss@^7.0.0, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0. source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7.0.1, postcss@^7.0.5: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.17: + version "7.0.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" + integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + postcss@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18" @@ -10233,7 +10463,7 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.1: +prepend-http@^1.0.0, prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= @@ -10256,6 +10486,11 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + process-es6@^0.11.6: version "0.11.6" resolved "https://registry.yarnpkg.com/process-es6/-/process-es6-0.11.6.tgz#c6bb389f9a951f82bd4eb169600105bd2ff9c778" @@ -10407,7 +10642,7 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" -pump@^2.0.0, pump@^2.0.1: +pump@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== @@ -10482,6 +10717,14 @@ qs@~2.3.3: resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -10576,15 +10819,15 @@ raw-loader@0.5.1: resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= -raw-loader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-1.0.0.tgz#3f9889e73dadbda9a424bce79809b4133ad46405" - integrity sha512-Uqy5AqELpytJTRxYT4fhltcKPj0TyaEpzJDcGz7DFJi+pQOOi3GjR/DOdxTkTsF+NzhnldIoG6TORaBlInUuqA== +raw-loader@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f" + integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA== dependencies: loader-utils "^1.1.0" - schema-utils "^1.0.0" + schema-utils "^2.0.1" -rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: +rc@^1.0.1, rc@^1.1.6: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -10601,6 +10844,27 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +read-package-json@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1" + integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + npm-normalize-package-bin "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" + integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== + dependencies: + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + util-promisify "^2.1.0" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -10609,14 +10873,6 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -10626,15 +10882,6 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -10644,7 +10891,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -10698,6 +10945,16 @@ readable-stream@~2.0.0, readable-stream@~2.0.6: string_decoder "~0.10.x" util-deprecate "~1.0.1" +readdir-scoped-modules@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" + integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -10717,6 +10974,13 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +readdirp@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" + integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== + dependencies: + picomatch "^2.0.7" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -10756,16 +11020,33 @@ reduce-function-call@^1.0.1, reduce-function-call@^1.0.2: dependencies: balanced-match "^0.4.2" -reflect-metadata@0.1.12, reflect-metadata@^0.1.2: +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +reflect-metadata@^0.1.2: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A== -regenerate@^1.2.1: +regenerate-unicode-properties@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== +regenerator-runtime@0.13.3, regenerator-runtime@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + regenerator-runtime@^0.10.0: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" @@ -10776,10 +11057,12 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.2: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" - integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== +regenerator-transform@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" + integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== + dependencies: + private "^0.1.6" regex-cache@^0.4.2: version "0.4.4" @@ -10815,6 +11098,18 @@ regexpu-core@^1.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" +regexpu-core@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" + integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.1.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -10835,6 +11130,11 @@ regjsgen@^0.2.0: resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= +regjsgen@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" @@ -10842,6 +11142,13 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +regjsparser@^0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96" + integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q== + dependencies: + jsesc "~0.5.0" + relateurl@0.2.x: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" @@ -11067,7 +11374,7 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2, rimraf@2.6.2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2.6.2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== @@ -11081,6 +11388,13 @@ rimraf@2.6.3, rimraf@^2.6.3: dependencies: glob "^7.1.3" +rimraf@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" + integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg== + dependencies: + glob "^7.1.3" + rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -11182,13 +11496,6 @@ rxjs-spy@^7.5.1: error-stack-parser "^2.0.1" stacktrace-gps "^3.0.2" -rxjs@6.3.3: - version "6.3.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" - integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== - dependencies: - tslib "^1.9.0" - rxjs@6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" @@ -11196,7 +11503,14 @@ rxjs@6.4.0: dependencies: tslib "^1.9.0" -rxjs@^6.0.0, rxjs@^6.1.0: +rxjs@6.5.4, rxjs@^6.4.0: + version "6.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" + integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + dependencies: + tslib "^1.9.0" + +rxjs@^6.0.0: version "6.2.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9" integrity sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ== @@ -11220,6 +11534,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -11232,26 +11551,15 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass-graph@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" - integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= +sass-loader@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.2.0.tgz#e34115239309d15b2527cb62b5dfefb62a96ff7f" + integrity sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA== dependencies: - glob "^7.0.0" - lodash "^4.0.0" - scss-tokenizer "^0.2.3" - yargs "^7.0.0" - -sass-loader@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" - integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== - dependencies: - clone-deep "^2.0.1" + clone-deep "^4.0.1" loader-utils "^1.0.1" - lodash.tail "^4.1.1" neo-async "^2.5.0" - pify "^3.0.0" + pify "^4.0.1" semver "^5.5.0" sass-loader@7.3.1: @@ -11275,6 +11583,13 @@ sass-resources-loader@^2.0.0: glob "^7.1.1" loader-utils "^1.0.4" +sass@1.22.9: + version "1.22.9" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.9.tgz#41a2ed6038027f58be2bd5041293452a29c2cb84" + integrity sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ== + dependencies: + chokidar ">=2.0.0 <4.0.0" + saucelabs@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" @@ -11287,7 +11602,7 @@ sax@0.5.x: resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= -sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -11299,7 +11614,7 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" -schema-utils@^0.4.4, schema-utils@^0.4.5: +schema-utils@^0.4.5: version "0.4.7" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== @@ -11316,6 +11631,14 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" +schema-utils@^2.0.0, schema-utils@^2.0.1: + version "2.6.4" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" + integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + schema-utils@^2.6.0, schema-utils@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f" @@ -11331,14 +11654,6 @@ script-ext-html-webpack-plugin@2.1.4: dependencies: debug "^4.1.1" -scss-tokenizer@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" - integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= - dependencies: - js-base64 "^2.1.8" - source-map "^0.4.2" - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -11361,7 +11676,7 @@ selfsigned@^1.10.4: dependencies: node-forge "0.7.5" -selfsigned@^1.9.1: +selfsigned@^1.10.7: version "1.10.7" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA== @@ -11394,7 +11709,17 @@ semver-intersect@1.4.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== -semver@5.6.0, semver@^5.0.1: +semver@6.3.0, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.0.1: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -11404,16 +11729,6 @@ semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= - send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -11452,12 +11767,12 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -"serialize-javascript@>= 2.1.2", serialize-javascript@^1.4.0, serialize-javascript@^2.1.2: +"serialize-javascript@>= 2.1.2", serialize-javascript@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -serve-index@^1.7.2, serve-index@^1.9.1: +serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= @@ -11490,7 +11805,7 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -11535,15 +11850,6 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallow-clone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" - integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== - dependencies: - is-extendable "^0.1.1" - kind-of "^5.0.0" - mixin-object "^2.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -11582,15 +11888,6 @@ shelljs@^0.7.0: interpret "^1.0.0" rechoir "^0.6.2" -shelljs@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" - integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -11710,6 +12007,18 @@ sockjs-client@1.3.0: json3 "^3.3.2" url-parse "^1.4.3" +sockjs-client@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" + integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + sockjs@0.3.19: version "0.3.19" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" @@ -11734,6 +12043,13 @@ socks@~2.3.2: ip "1.1.5" smart-buffer "^4.1.0" +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + sortablejs@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.7.0.tgz#80a2b2370abd568e1cec8c271131ef30a904fa28" @@ -11768,10 +12084,10 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.10: - version "0.5.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" - integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -11784,7 +12100,7 @@ source-map-support@^0.5.0, source-map-support@~0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.5, source-map-support@~0.5.10, source-map-support@~0.5.12: +source-map-support@^0.5.5, source-map-support@~0.5.12: version "0.5.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== @@ -11826,14 +12142,7 @@ source-map@0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map@^0.4.2, source-map@~0.4.1: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - integrity sha1-66T12pwNyZneaAMti092FzZSA2s= - dependencies: - amdefine ">=0.0.4" - -source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -11850,6 +12159,13 @@ source-map@~0.2.0: dependencies: amdefine ">=0.0.4" +source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + sourcemap-codec@^1.4.4: version "1.4.6" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" @@ -11898,7 +12214,7 @@ spdy-transport@^3.0.0: readable-stream "^3.0.6" wbuf "^1.7.3" -spdy@^4.0.0: +spdy@^4.0.0, spdy@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== @@ -11956,13 +12272,6 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -ssri@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" - integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== - dependencies: - safe-buffer "^5.1.1" - ssri@^6.0.0, ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" @@ -12004,13 +12313,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -stats-webpack-plugin@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz#ccffe9b745de8bbb155571e063f8263fc0e2bc06" - integrity sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ== - dependencies: - lodash "^4.17.4" - "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -12021,13 +12323,6 @@ statuses@~1.3.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= -stdout-stream@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" - integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== - dependencies: - readable-stream "^2.0.1" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -12078,6 +12373,11 @@ streamroller@^1.0.6: fs-extra "^7.0.1" lodash "^4.17.14" +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + string-replace-loader@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-replace-loader/-/string-replace-loader-2.1.1.tgz#b72e7b57b6ef04efe615aff0ad989b5c14ca63d1" @@ -12086,7 +12386,7 @@ string-replace-loader@^2.1.1: loader-utils "^1.1.0" schema-utils "^0.4.5" -string-width@^1.0.1, string-width@^1.0.2: +string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= @@ -12095,7 +12395,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -12211,13 +12511,13 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -style-loader@0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" - integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== +style-loader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82" + integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw== dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" + loader-utils "^1.2.3" + schema-utils "^2.0.1" stylehacks@^4.0.0: version "4.0.3" @@ -12282,7 +12582,7 @@ supports-color@^3.1.0: dependencies: has-flag "^1.0.0" -supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0: +supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -12329,7 +12629,7 @@ tapable@^1.0.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" integrity sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg== -tapable@^1.1.0, tapable@^1.1.3: +tapable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== @@ -12345,28 +12645,6 @@ tar-stream@^2.1.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -tar@^4: - version "4.4.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" - integrity sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg== - dependencies: - chownr "^1.0.1" - fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - tar@^4.4.8: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" @@ -12387,21 +12665,7 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -terser-webpack-plugin@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz#9bff3a891ad614855a7dde0d707f7db5a927e3d9" - integrity sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg== - dependencies: - cacache "^11.0.2" - find-cache-dir "^2.0.0" - schema-utils "^1.0.0" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - terser "^3.16.1" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -terser-webpack-plugin@^1.1.0, terser-webpack-plugin@^1.4.3: +terser-webpack-plugin@1.4.3, terser-webpack-plugin@^1.4.1, terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== @@ -12430,14 +12694,14 @@ terser-webpack-plugin@^2.3.1: terser "^4.4.3" webpack-sources "^1.4.3" -terser@^3.16.1: - version "3.17.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" - integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== +terser@4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== dependencies: - commander "^2.19.0" + commander "^2.20.0" source-map "~0.6.1" - source-map-support "~0.5.10" + source-map-support "~0.5.12" terser@^3.8.2: version "3.8.2" @@ -12562,6 +12826,11 @@ to-fast-properties@^1.0.3: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -12577,6 +12846,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -12619,10 +12895,10 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -tree-kill@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" - integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== trim-newlines@^1.0.0: version "1.0.0" @@ -12634,13 +12910,6 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= -"true-case-path@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" - integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== - dependencies: - glob "^7.1.2" - tryer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" @@ -12693,12 +12962,12 @@ tsconfig@^7.0.0: strip-bom "^3.0.0" strip-json-comments "^2.0.0" -tslib@^1.7.1: +tslib@1.10.0, tslib@^1.7.1, tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.0, tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== @@ -12828,15 +13097,10 @@ typescript@2.4.1: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc" integrity sha1-w8yxbdqgsjFN4DHn5v7onlujRrw= -typescript@3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" - integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== - -typescript@3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" - integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== +typescript@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== "typescript@>=2.6.2 <2.10", typescript@^2.5.0: version "2.9.2" @@ -12878,6 +13142,29 @@ undefsafe@^2.0.2: dependencies: debug "^2.2.0" +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -12905,13 +13192,6 @@ uniqs@^2.0.0: resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= -unique-filename@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" - integrity sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM= - dependencies: - unique-slug "^2.0.0" - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -12941,6 +13221,15 @@ units-css@^0.4.0: isnumeric "^0.2.0" viewport-dimensions "^0.2.0" +universal-analytics@^0.4.20: + version "0.4.20" + resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.20.tgz#d6b64e5312bf74f7c368e3024a922135dbf24b03" + integrity sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw== + dependencies: + debug "^3.0.0" + request "^2.88.0" + uuid "^3.0.0" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -13078,6 +13367,13 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +util-promisify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" + integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= + dependencies: + object.getownpropertydescriptors "^2.0.3" + util.promisify@1.0.0, util.promisify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" @@ -13093,13 +13389,6 @@ util@0.10.3: dependencies: inherits "2.0.1" -util@^0.10.3: - version "0.10.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== - dependencies: - inherits "2.0.3" - util@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" @@ -13127,6 +13416,11 @@ uuid@^2.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= +uuid@^3.0.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -13207,13 +13501,6 @@ vlq@^0.2.2: resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== -vm-browserify@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= - dependencies: - indexof "0.0.1" - vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -13224,7 +13511,7 @@ void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -watchpack@^1.5.0, watchpack@^1.6.0: +watchpack@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== @@ -13359,24 +13646,15 @@ webpack-dev-middleware@3.2.0: url-join "^4.0.0" webpack-log "^2.0.0" -webpack-dev-middleware@3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" - integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== +webpack-dev-middleware@3.7.2, webpack-dev-middleware@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" + integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== dependencies: - memory-fs "~0.4.1" - mime "^2.3.1" - range-parser "^1.0.3" - webpack-log "^2.0.0" - -webpack-dev-middleware@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.5.1.tgz#9265b7742ef50f54f54c1d9af022fc17c1be9b88" - integrity sha512-4dwCh/AyMOYAybggUr8fiCkRnjVDp+Cqlr9c+aaNB3GJYgRGYQWJ1YX/WAKUNA9dPNHZ6QSN2lYDKqjKSI8Vqw== - dependencies: - memory-fs "~0.4.1" - mime "^2.3.1" - range-parser "^1.0.3" + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" webpack-log "^2.0.0" webpack-dev-middleware@^2.0.6: @@ -13402,41 +13680,44 @@ webpack-dev-middleware@^3.7.0: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@3.1.14: - version "3.1.14" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" - integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== +webpack-dev-server@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz#27c3b5d0f6b6677c4304465ac817623c8b27b89c" + integrity sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" - chokidar "^2.0.0" - compression "^1.5.2" - connect-history-api-fallback "^1.3.0" - debug "^3.1.0" - del "^3.0.0" - express "^4.16.2" - html-entities "^1.2.0" - http-proxy-middleware "~0.18.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.2.1" + http-proxy-middleware "0.19.1" import-local "^2.0.0" - internal-ip "^3.0.1" + internal-ip "^4.3.0" ip "^1.1.5" - killable "^1.0.0" - loglevel "^1.4.1" - opn "^5.1.0" - portfinder "^1.0.9" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.4" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.25" schema-utils "^1.0.0" - selfsigned "^1.9.1" - semver "^5.6.0" - serve-index "^1.7.2" + selfsigned "^1.10.7" + semver "^6.3.0" + serve-index "^1.9.1" sockjs "0.3.19" - sockjs-client "1.3.0" - spdy "^4.0.0" - strip-ansi "^3.0.0" - supports-color "^5.1.0" + sockjs-client "1.4.0" + spdy "^4.0.1" + strip-ansi "^3.0.1" + supports-color "^6.1.0" url "^0.11.0" - webpack-dev-middleware "3.4.0" + webpack-dev-middleware "^3.7.2" webpack-log "^2.0.0" - yargs "12.0.2" + ws "^6.2.1" + yargs "12.0.5" webpack-dev-server@^3.1.11: version "3.7.2" @@ -13519,10 +13800,10 @@ webpack-node-externals@1.7.2: resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3" integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg== -webpack-sources@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" - integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== +webpack-sources@1.4.3, webpack-sources@^1.2.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -13535,14 +13816,6 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.2.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - webpack-subresource-integrity@1.1.0-rc.6: version "1.1.0-rc.6" resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz#37f6f1264e1eb378e41465a98da80fad76ab8886" @@ -13550,35 +13823,34 @@ webpack-subresource-integrity@1.1.0-rc.6: dependencies: webpack-core "^0.6.8" -webpack@4.29.0: - version "4.29.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.0.tgz#f2cfef83f7ae404ba889ff5d43efd285ca26e750" - integrity sha512-pxdGG0keDBtamE1mNvT5zyBdx+7wkh6mh7uzMOo/uRQ/fhsdj5FXkh/j5mapzs060forql1oXqXN9HJGju+y7w== +webpack@4.39.2: + version "4.39.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.39.2.tgz#c9aa5c1776d7c309d1b3911764f0288c8c2816aa" + integrity sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA== dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-module-context" "1.7.11" - "@webassemblyjs/wasm-edit" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - acorn "^6.0.5" - acorn-dynamic-import "^4.0.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^1.0.0" + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.2.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" enhanced-resolve "^4.1.0" - eslint-scope "^4.0.0" + eslint-scope "^4.0.3" json-parse-better-errors "^1.0.2" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^0.4.4" - tapable "^1.1.0" - terser-webpack-plugin "^1.1.0" - watchpack "^1.5.0" - webpack-sources "^1.3.0" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.1" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.1" + watchpack "^1.6.0" + webpack-sources "^1.4.1" webpack@^4.29.6: version "4.41.3" @@ -13627,30 +13899,18 @@ when@~3.6.x: resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1, which@^1.1.1, which@^1.2.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@^1.1.1, which@^1.2.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - widest-line@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" @@ -13673,13 +13933,6 @@ wordwrap@~0.0.2: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= -worker-farm@^1.5.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" - integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== - dependencies: - errno "~0.1.7" - worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -13687,6 +13940,13 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" +worker-plugin@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/worker-plugin/-/worker-plugin-3.2.0.tgz#ddae9f161b76fcbaacf8f54ecd037844584e43e7" + integrity sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q== + dependencies: + loader-utils "^1.1.0" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -13725,7 +13985,7 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^6.0.0: +ws@^6.0.0, ws@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== @@ -13769,21 +14029,11 @@ xmlhttprequest-ssl@~1.5.4: resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= -xregexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" - integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== - xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= -y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -13809,13 +14059,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" @@ -13824,7 +14067,7 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^13.1.0, yargs-parser@^13.1.1: +yargs-parser@^13.0.0, yargs-parser@^13.1.0, yargs-parser@^13.1.1: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== @@ -13832,38 +14075,6 @@ yargs-parser@^13.1.0, yargs-parser@^13.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" - integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= - dependencies: - camelcase "^3.0.0" - -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= - dependencies: - camelcase "^4.1.0" - -yargs@12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" - integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== - dependencies: - cliui "^4.0.0" - decamelize "^2.0.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^10.1.0" - yargs@12.0.5, yargs@^12.0.1: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" @@ -13882,6 +14093,23 @@ yargs@12.0.5, yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" +yargs@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301" + integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg== + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + yargs@13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" @@ -13899,25 +14127,6 @@ yargs@13.2.4: y18n "^4.0.0" yargs-parser "^13.1.0" -yargs@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" - integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - yargs@^13.2.4: version "13.3.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" @@ -13934,25 +14143,6 @@ yargs@^13.2.4: y18n "^4.0.0" yargs-parser "^13.1.1" -yargs@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" - integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= - dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - y18n "^3.2.1" - yargs-parser "^5.0.0" - yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" @@ -13979,7 +14169,7 @@ zip-stream@^2.1.2: compress-commons "^2.1.1" readable-stream "^3.4.0" -zone.js@^0.8.29: - version "0.8.29" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12" - integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ== +zone.js@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.9.1.tgz#e37c6e5c54c13fae4de26b5ffe8d8e9212da6d9b" + integrity sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag==