diff --git a/package.json b/package.json index aaabc0271a..b4a40c0a19 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "node": "8.* || >= 10.*" }, "resolutions": { + "serialize-javascript": ">= 2.1.2", "set-value": ">= 2.0.1" }, "scripts": { @@ -74,38 +75,38 @@ "sync-i18n": "node ./scripts/sync-i18n-files.js" }, "dependencies": { - "@angular/animations": "^6.1.4", - "@angular/cdk": "^6.4.7", - "@angular/cli": "^6.1.5", - "@angular/common": "^6.1.4", - "@angular/core": "^6.1.4", - "@angular/forms": "^6.1.4", - "@angular/http": "^6.1.4", - "@angular/platform-browser": "^6.1.4", - "@angular/platform-browser-dynamic": "^6.1.4", - "@angular/platform-server": "^6.1.4", - "@angular/router": "^6.1.4", + "@angular/animations": "^7.2.15", + "@angular/cdk": "7.3.7", + "@angular/cli": "^7.3.5", + "@angular/common": "^7.2.15", + "@angular/core": "^7.2.15", + "@angular/forms": "^7.2.15", + "@angular/http": "^7.2.15", + "@angular/platform-browser": "^7.2.15", + "@angular/platform-browser-dynamic": "^7.2.15", + "@angular/platform-server": "^7.2.15", + "@angular/router": "^7.2.15", "@angularclass/bootloader": "1.0.1", - "@ng-bootstrap/ng-bootstrap": "^2.0.0", - "@ng-dynamic-forms/core": "6.2.0", - "@ng-dynamic-forms/ui-ng-bootstrap": "6.2.0", - "@ngrx/effects": "^6.1.0", - "@ngrx/router-store": "^6.1.0", - "@ngrx/store": "^6.1.0", - "@nguniversal/express-engine": "6.1.0", - "@ngx-translate/core": "10.0.2", - "@ngx-translate/http-loader": "3.0.1", + "@ng-bootstrap/ng-bootstrap": "^4.1.0", + "@ng-dynamic-forms/core": "^7.1.0", + "@ng-dynamic-forms/ui-ng-bootstrap": "^7.1.0", + "@ngrx/effects": "^7.3.0", + "@ngrx/router-store": "^7.3.0", + "@ngrx/store": "^7.3.0", + "@nguniversal/express-engine": "^7.1.1", + "@ngx-translate/core": "11.0.1", + "@ngx-translate/http-loader": "4.0.0", "@nicky-lenaers/ngx-scroll-to": "^1.0.0", "angular-idle-preload": "3.0.0", "angular-sortablejs": "^2.5.0", "angular2-text-mask": "9.0.0", - "angulartics2": "^6.2.0", + "angulartics2": "7.5.2", "body-parser": "1.18.2", "bootstrap": "4.3.1", "cerialize": "0.1.18", "compression": "1.7.1", "cookie-parser": "1.4.3", - "core-js": "^2.5.7", + "core-js": "^2.6.5", "debug-loader": "^0.0.1", "express": "4.16.2", "express-session": "1.15.6", @@ -113,6 +114,7 @@ "file-saver": "^1.3.8", "font-awesome": "4.7.0", "fork-ts-checker-webpack-plugin": "^0.4.10", + "hammerjs": "^2.0.8", "http-server": "0.11.1", "https": "1.0.0", "js-cookie": "2.2.0", @@ -122,18 +124,19 @@ "jwt-decode": "^2.2.0", "methods": "1.1.2", "moment": "^2.22.1", + "moment-range": "^4.0.2", "morgan": "^1.9.1", - "ng-mocks": "^6.2.1", + "ng-mocks": "^7.6.0", "ng2-file-upload": "1.2.1", - "ng2-nouislider": "^1.7.11", + "ng2-nouislider": "^1.8.2", "ngx-bootstrap": "^3.2.0", "ngx-infinite-scroll": "6.0.1", - "ngx-moment": "^3.1.0", + "ngx-moment": "^3.4.0", "ngx-pagination": "3.0.3", "nouislider": "^11.0.0", "pem": "1.13.2", "reflect-metadata": "0.1.12", - "rxjs": "6.2.2", + "rxjs": "6.4.0", "rxjs-spy": "^7.5.1", "sass-resources-loader": "^2.0.0", "sortablejs": "1.7.0", @@ -143,17 +146,18 @@ "url-parse": "^1.4.7", "uuid": "^3.2.1", "webfontloader": "1.6.28", - "webpack-cli": "^3.1.0", - "zone.js": "^0.8.26" + "webpack-cli": "^3.2.0", + "zone.js": "^0.8.29" }, "devDependencies": { - "@angular/compiler": "^6.1.4", - "@angular/compiler-cli": "^6.1.4", + "@angular-devkit/build-angular": "^0.13.5", + "@angular/compiler": "^7.2.15", + "@angular/compiler-cli": "^7.2.15", "@fortawesome/fontawesome-free": "^5.5.0", - "@ngrx/entity": "^6.1.0", - "@ngrx/schematics": "^6.1.0", - "@ngrx/store-devtools": "^6.1.0", - "@ngtools/webpack": "^6.1.5", + "@ngrx/entity": "^7.3.0", + "@ngrx/schematics": "^7.3.0", + "@ngrx/store-devtools": "^7.3.0", + "@ngtools/webpack": "^7.3.9", "@schematics/angular": "^0.7.5", "@types/acorn": "^4.0.3", "@types/cookie-parser": "1.4.1", @@ -162,44 +166,47 @@ "@types/express-serve-static-core": "4.16.0", "@types/file-saver": "^1.3.0", "@types/hammerjs": "2.0.35", - "@types/jasmine": "^2.8.6", + "@types/jasmine": "^3.3.9", "@types/js-cookie": "2.1.0", "@types/json5": "^0.0.30", "@types/lodash": "^4.14.110", "@types/memory-cache": "0.2.0", "@types/mime": "2.0.0", - "@types/node": "^10.9.4", + "@types/node": "^11.11.2", "@types/serve-static": "1.13.2", "@types/uuid": "^3.4.3", "@types/webfontloader": "1.6.29", + "@typescript-eslint/eslint-plugin": "^2.12.0", + "@typescript-eslint/parser": "^2.12.0", "ajv": "^6.1.1", "ajv-keywords": "^3.1.0", "angular2-template-loader": "0.6.2", "autoprefixer": "^9.1.3", "caniuse-lite": "^1.0.30000697", "cli-progress": "^3.3.1", - "codelyzer": "^4.4.4", + "codelyzer": "^5.1.0", "commander": "^3.0.2", - "compression-webpack-plugin": "^1.1.6", - "copy-webpack-plugin": "^4.4.1", + "compression-webpack-plugin": "^3.0.1", + "copy-webpack-plugin": "^5.1.1", "copyfiles": "^2.1.1", "coveralls": "3.0.0", - "css-loader": "1.0.0", + "css-loader": "3.4.0", "cssnano": "^4.1.10", "deep-freeze": "0.0.1", + "eslint": "^6.7.2", "exports-loader": "^0.7.0", - "html-webpack-plugin": "^4.0.0-alpha", + "html-webpack-plugin": "3.2.0", "imports-loader": "0.8.0", "istanbul-instrumenter-loader": "3.0.1", - "jasmine-core": "^3.2.1", + "jasmine-core": "^3.3.0", "jasmine-marbles": "0.3.1", "jasmine-spec-reporter": "4.2.1", - "karma": "3.0.0", + "karma": "4.0.1", "karma-chrome-launcher": "2.2.0", - "karma-cli": "1.0.1", + "karma-cli": "2.0.0", "karma-coverage": "1.1.2", "karma-istanbul-preprocessor": "0.0.2", - "karma-jasmine": "1.1.2", + "karma-jasmine": "2.0.1", "karma-mocha-reporter": "2.2.5", "karma-phantomjs-launcher": "1.0.4", "karma-remap-coverage": "^0.1.5", @@ -223,26 +230,26 @@ "protractor": "^5.4.2", "protractor-istanbul-plugin": "2.0.0", "raw-loader": "0.5.1", - "resolve-url-loader": "^2.3.0", "rimraf": "2.6.2", "rollup": "^0.65.0", "rollup-plugin-commonjs": "^9.1.6", "rollup-plugin-node-globals": "1.2.1", "rollup-plugin-node-resolve": "^3.0.3", "rollup-plugin-terser": "^2.0.2", - "sass-loader": "^7.1.0", - "script-ext-html-webpack-plugin": "2.0.1", + "sass-loader": "7.3.1", + "script-ext-html-webpack-plugin": "2.1.4", "source-map": "0.7.3", "source-map-loader": "0.2.4", "string-replace-loader": "^2.1.1", + "terser-webpack-plugin": "^2.3.1", "to-string-loader": "1.1.5", "ts-helpers": "1.1.2", "ts-node": "4.1.0", "tslint": "5.11.0", "typedoc": "^0.9.0", - "typescript": "^2.9.1", + "typescript": "3.1.6", "webdriver-manager": "^12.1.7", - "webpack": "^4.17.1", + "webpack": "^4.29.6", "webpack-bundle-analyzer": "^3.3.2", "webpack-dev-middleware": "3.2.0", "webpack-dev-server": "^3.1.11", diff --git a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts index 4a5e301921..674ae739d8 100644 --- a/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts +++ b/src/app/+admin/admin-registries/metadata-registry/metadata-registry.component.spec.ts @@ -1,7 +1,6 @@ import { MetadataRegistryComponent } from './metadata-registry.component'; import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; -import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list'; import { TranslateModule } from '@ngx-translate/core'; import { By } from '@angular/platform-browser'; @@ -18,6 +17,7 @@ import { NotificationsService } from '../../../shared/notifications/notification import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub'; import { RestResponse } from '../../../core/cache/response.models'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { MetadataSchema } from '../../../core/metadata/metadata-schema.model'; describe('MetadataRegistryComponent', () => { let comp: MetadataRegistryComponent; @@ -101,12 +101,12 @@ describe('MetadataRegistryComponent', () => { it('should start editing the selected schema', async(() => { fixture.whenStable().then(() => { - expect(registryService.editMetadataSchema).toHaveBeenCalledWith(mockSchemasList[0]); + expect(registryService.editMetadataSchema).toHaveBeenCalledWith(mockSchemasList[0] as MetadataSchema); }); })); it('should cancel editing the selected schema when clicked again', async(() => { - spyOn(registryService, 'getActiveMetadataSchema').and.returnValue(observableOf(mockSchemasList[0])); + spyOn(registryService, 'getActiveMetadataSchema').and.returnValue(observableOf(mockSchemasList[0] as MetadataSchema)); spyOn(registryService, 'cancelEditMetadataSchema'); row.click(); fixture.detectChanges(); @@ -121,7 +121,7 @@ describe('MetadataRegistryComponent', () => { beforeEach(() => { spyOn(registryService, 'deleteMetadataSchema').and.callThrough(); - spyOn(registryService, 'getSelectedMetadataSchemas').and.returnValue(observableOf(selectedSchemas)); + spyOn(registryService, 'getSelectedMetadataSchemas').and.returnValue(observableOf(selectedSchemas as MetadataSchema[])); comp.deleteSchemas(); fixture.detectChanges(); }); diff --git a/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts b/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts index e23a9691c4..e0b0ef25a5 100644 --- a/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts +++ b/src/app/+admin/admin-registries/metadata-schema/metadata-schema.component.spec.ts @@ -1,7 +1,6 @@ import { MetadataSchemaComponent } from './metadata-schema.component'; import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; -import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list'; import { TranslateModule } from '@ngx-translate/core'; import { CommonModule } from '@angular/common'; @@ -22,6 +21,7 @@ import { NotificationsServiceStub } from '../../../shared/testing/notifications- import { RestResponse } from '../../../core/cache/response.models'; import { MetadataSchema } from '../../../core/metadata/metadata-schema.model'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { MetadataField } from '../../../core/metadata/metadata-field.model'; describe('MetadataSchemaComponent', () => { let comp: MetadataSchemaComponent; @@ -152,12 +152,12 @@ describe('MetadataSchemaComponent', () => { it('should start editing the selected field', async(() => { fixture.whenStable().then(() => { - expect(registryService.editMetadataField).toHaveBeenCalledWith(mockFieldsList[2]); + expect(registryService.editMetadataField).toHaveBeenCalledWith(mockFieldsList[2] as MetadataField); }); })); it('should cancel editing the selected field when clicked again', async(() => { - spyOn(registryService, 'getActiveMetadataField').and.returnValue(observableOf(mockFieldsList[2])); + spyOn(registryService, 'getActiveMetadataField').and.returnValue(observableOf(mockFieldsList[2] as MetadataField)); spyOn(registryService, 'cancelEditMetadataField'); row.click(); fixture.detectChanges(); @@ -172,7 +172,7 @@ describe('MetadataSchemaComponent', () => { beforeEach(() => { spyOn(registryService, 'deleteMetadataField').and.callThrough(); - spyOn(registryService, 'getSelectedMetadataFields').and.returnValue(observableOf(selectedFields)); + spyOn(registryService, 'getSelectedMetadataFields').and.returnValue(observableOf(selectedFields as MetadataField[])); comp.deleteFields(); fixture.detectChanges(); }); diff --git a/src/app/+collection-page/collection-form/collection-form.component.ts b/src/app/+collection-page/collection-form/collection-form.component.ts index 76ba549f14..59433e49a0 100644 --- a/src/app/+collection-page/collection-form/collection-form.component.ts +++ b/src/app/+collection-page/collection-form/collection-form.component.ts @@ -1,6 +1,10 @@ import { Component, Input } from '@angular/core'; -import { DynamicFormService, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; -import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; +import { + DynamicFormControlModel, + DynamicFormService, + DynamicInputModel, + DynamicTextAreaModel +} from '@ng-dynamic-forms/core'; import { Collection } from '../../core/shared/collection.model'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; import { Location } from '@angular/common'; diff --git a/src/app/+community-page/community-form/community-form.component.ts b/src/app/+community-page/community-form/community-form.component.ts index 1f081bd81b..e9bd2f66c8 100644 --- a/src/app/+community-page/community-form/community-form.component.ts +++ b/src/app/+community-page/community-form/community-form.component.ts @@ -1,8 +1,11 @@ import { Component, Input } from '@angular/core'; -import { DynamicFormService, DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core'; -import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; +import { + DynamicFormControlModel, + DynamicFormService, + DynamicInputModel, + DynamicTextAreaModel +} from '@ng-dynamic-forms/core'; import { Community } from '../../core/shared/community.model'; -import { ResourceType } from '../../core/shared/resource-type'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; import { Location } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 1d0d765130..1f3da086c2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -82,6 +82,7 @@ export class AppComponent implements OnInit, AfterViewInit { } } + angulartics2GoogleAnalytics.startTracking(); angulartics2DSpace.startTracking(); metadata.listenForRouteChange(); diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index ad9247799b..837fb9befd 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -1,5 +1,6 @@ import { ActionReducerMap, createSelector, MemoizedSelector } from '@ngrx/store'; import * as fromRouter from '@ngrx/router-store'; + import { hostWindowReducer, HostWindowState } from './shared/search/host-window.reducer'; import { CommunityListReducer, CommunityListState } from './community-list-page/community-list.reducer'; import { formReducer, FormState } from './shared/form/form.reducer'; @@ -8,23 +9,28 @@ import { sidebarFilterReducer, SidebarFiltersState } from './shared/sidebar/filt import { filterReducer, SearchFiltersState } from './shared/search/search-filters/search-filter/search-filter.reducer'; import { notificationsReducer, NotificationsState } from './shared/notifications/notifications.reducers'; import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer'; -import { metadataRegistryReducer, MetadataRegistryState } from './+admin/admin-registries/metadata-registry/metadata-registry.reducers'; +import { + metadataRegistryReducer, + MetadataRegistryState +} from './+admin/admin-registries/metadata-registry/metadata-registry.reducers'; import { hasValue } from './shared/empty.util'; import { cssVariablesReducer, CSSVariablesState } from './shared/sass-helper/sass-helper.reducer'; import { menusReducer, MenusState } from './shared/menu/menu.reducer'; -import { historyReducer, HistoryState } from './shared/history/history.reducer'; -import { selectableListReducer, SelectableListsState } from './shared/object-list/selectable-list/selectable-list.reducer'; -import { bitstreamFormatReducer, BitstreamFormatRegistryState } from './+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; +import { + selectableListReducer, + SelectableListsState +} from './shared/object-list/selectable-list/selectable-list.reducer'; import { ObjectSelectionListState, objectSelectionReducer } from './shared/object-select/object-select.reducer'; -import { NameVariantListsState, nameVariantReducer } from './shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; +import { + NameVariantListsState, + nameVariantReducer +} from './shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer'; export interface AppState { router: fromRouter.RouterReducerState; - history: HistoryState; hostWindow: HostWindowState; forms: FormState; metadataRegistry: MetadataRegistryState; - bitstreamFormats: BitstreamFormatRegistryState; notifications: NotificationsState; sidebar: SidebarState; sidebarFilter: SidebarFiltersState; @@ -40,11 +46,9 @@ export interface AppState { export const appReducers: ActionReducerMap = { router: fromRouter.routerReducer, - history: historyReducer, hostWindow: hostWindowReducer, forms: formReducer, metadataRegistry: metadataRegistryReducer, - bitstreamFormats: bitstreamFormatReducer, notifications: notificationsReducer, sidebar: sidebarReducer, sidebarFilter: sidebarFilterReducer, diff --git a/src/app/community-list-page/community-list-adapter.ts b/src/app/community-list-page/community-list-adapter.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/community-list-page/community-list-service.ts b/src/app/community-list-page/community-list-service.ts index a25dbd2689..be04887e71 100644 --- a/src/app/community-list-page/community-list-service.ts +++ b/src/app/community-list-page/community-list-service.ts @@ -312,7 +312,7 @@ export class CommunityListService { hasColls$ = this.collectionDataService.findByParent(community.uuid, { elementsPerPage: 1 }) .pipe( - filter((rd: RemoteData>) => rd.hasSucceeded), + filter((rd: RemoteData>) => rd.hasSucceeded), take(1), map((results) => results.payload.totalElements > 0), ); @@ -320,8 +320,8 @@ export class CommunityListService { let hasChildren$: Observable; hasChildren$ = observableCombineLatest(hasSubcoms$, hasColls$).pipe( take(1), - map((result: [boolean]) => { - if (result[0] || result[1]) { + map(([hasSubcoms, hasColls]: [boolean, boolean]) => { + if (hasSubcoms || hasColls) { return true; } else { return false; diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 94b1e9e6ff..a536313521 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -60,7 +60,8 @@ export class AuthService { // and is not the login route, clear redirect url and messages const routeUrl$ = this.store.pipe( select(routerStateSelector), - filter((routerState: RouterReducerState) => isNotUndefined(routerState) && isNotUndefined(routerState.state)), + filter((routerState: RouterReducerState) => isNotUndefined(routerState) + && isNotUndefined(routerState.state) && isNotEmpty(routerState.state.url)), filter((routerState: RouterReducerState) => !this.isLoginRoute(routerState.state.url)), map((routerState: RouterReducerState) => routerState.state.url) ); diff --git a/src/app/core/core.reducers.ts b/src/app/core/core.reducers.ts index 4fcf36f9cc..78391eee3f 100644 --- a/src/app/core/core.reducers.ts +++ b/src/app/core/core.reducers.ts @@ -1,7 +1,4 @@ -import { - ActionReducerMap, - createFeatureSelector, -} from '@ngrx/store'; +import { ActionReducerMap, } from '@ngrx/store'; import { objectCacheReducer, ObjectCacheState } from './cache/object-cache.reducer'; import { indexReducer, MetaIndexState } from './index/index.reducer'; @@ -9,17 +6,21 @@ import { requestReducer, RequestState } from './data/request.reducer'; import { authReducer, AuthState } from './auth/auth.reducer'; import { jsonPatchOperationsReducer, JsonPatchOperationsState } from './json-patch/json-patch-operations.reducer'; import { serverSyncBufferReducer, ServerSyncBufferState } from './cache/server-sync-buffer.reducer'; -import { - objectUpdatesReducer, - ObjectUpdatesState -} from './data/object-updates/object-updates.reducer'; +import { objectUpdatesReducer, ObjectUpdatesState } from './data/object-updates/object-updates.reducer'; import { routeReducer, RouteState } from './services/route.reducer'; +import { + bitstreamFormatReducer, + BitstreamFormatRegistryState +} from '../+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; +import { historyReducer, HistoryState } from './history/history.reducer'; export interface CoreState { + 'bitstreamFormats': BitstreamFormatRegistryState; 'cache/object': ObjectCacheState, 'cache/syncbuffer': ServerSyncBufferState, 'cache/object-updates': ObjectUpdatesState 'data/request': RequestState, + 'history': HistoryState; 'index': MetaIndexState, 'auth': AuthState, 'json/patch': JsonPatchOperationsState, @@ -27,10 +28,12 @@ export interface CoreState { } export const coreReducers: ActionReducerMap = { + 'bitstreamFormats': bitstreamFormatReducer, 'cache/object': objectCacheReducer, 'cache/syncbuffer': serverSyncBufferReducer, 'cache/object-updates': objectUpdatesReducer, 'data/request': requestReducer, + 'history': historyReducer, 'index': indexReducer, 'auth': authReducer, 'json/patch': jsonPatchOperationsReducer, 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 f3ce478236..c626fcd6e2 100644 --- a/src/app/core/data/bitstream-format-data.service.spec.ts +++ b/src/app/core/data/bitstream-format-data.service.spec.ts @@ -3,7 +3,6 @@ import { RequestEntry } from './request.reducer'; import { RestResponse } from '../cache/response.models'; import { Observable, of as observableOf } from 'rxjs'; import { Action, Store } from '@ngrx/store'; -import { CoreState } from '../core.reducers'; import { ObjectCacheService } from '../cache/object-cache.service'; import { cold, getTestScheduler, hot } from 'jasmine-marbles'; import { HALEndpointService } from '../shared/hal-endpoint.service'; @@ -19,6 +18,7 @@ import { BitstreamFormatsRegistrySelectAction } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions'; import { TestScheduler } from 'rxjs/testing'; +import { CoreState } from '../core.reducers'; describe('BitstreamFormatDataService', () => { let service: BitstreamFormatDataService; diff --git a/src/app/core/data/bitstream-format-data.service.ts b/src/app/core/data/bitstream-format-data.service.ts index 7255ed3663..b5c2b708dc 100644 --- a/src/app/core/data/bitstream-format-data.service.ts +++ b/src/app/core/data/bitstream-format-data.service.ts @@ -5,7 +5,6 @@ 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 { 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'; @@ -17,7 +16,6 @@ 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 { AppState } from '../../app.reducer'; import { BitstreamFormatRegistryState } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.reducers'; import { BitstreamFormatsRegistryDeselectAction, @@ -26,8 +24,9 @@ import { } from '../../+admin/admin-registries/bitstream-formats/bitstream-format.actions'; import { hasValue } from '../../shared/empty.util'; import { RequestEntry } from './request.reducer'; +import { CoreState } from '../core.reducers'; -const bitstreamFormatsStateSelector = (state: AppState) => state.bitstreamFormats; +const bitstreamFormatsStateSelector = (state: CoreState) => state.bitstreamFormats; const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSelector, (bitstreamFormatRegistryState: BitstreamFormatRegistryState) => bitstreamFormatRegistryState.selectedBitstreamFormats); @@ -55,6 +54,7 @@ export class BitstreamFormatDataService extends DataService { /** * Get the endpoint for browsing bitstream formats * @param {FindListOptions} options + * @param {string} linkPath * @returns {Observable} */ getBrowseEndpoint(options: FindListOptions = {}, linkPath?: string): Observable { @@ -99,7 +99,7 @@ export class BitstreamFormatDataService extends DataService { /** * Create a new BitstreamFormat - * @param BitstreamFormat + * @param {BitstreamFormat} bitstreamFormat */ public createBitstreamFormat(bitstreamFormat: BitstreamFormat): Observable { const requestId = this.requestService.generateRequestId(); diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index 997ccec49f..f1d76b47fd 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -1,12 +1,22 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { distinctUntilChanged, filter, find, first, map, mergeMap, skipWhile, switchMap, take, tap } from 'rxjs/operators'; +import { + distinctUntilChanged, + filter, + find, + first, + map, + mergeMap, + skipWhile, + switchMap, + take, + tap +} from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { CoreState } from '../core.reducers'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { URLCombiner } from '../url-combiner/url-combiner'; import { PaginatedList } from './paginated-list'; @@ -14,9 +24,9 @@ import { RemoteData } from './remote-data'; import { CreateRequest, DeleteByIDRequest, + FindByIDRequest, FindListOptions, FindListRequest, - FindByIDRequest, GetRequest } from './request.models'; import { RequestService } from './request.service'; @@ -37,6 +47,7 @@ import { NormalizedObjectBuildService } from '../cache/builders/normalized-objec import { ChangeAnalyzer } from './change-analyzer'; 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; @@ -238,7 +249,7 @@ export abstract class DataService { */ update(object: T): Observable> { const oldVersion$ = this.objectCache.getObjectBySelfLink(object.self); - return oldVersion$.pipe(take(1), mergeMap((oldVersion: T) => { + return oldVersion$.pipe(take(1), mergeMap((oldVersion: NormalizedObject) => { const operations = this.comparator.diff(oldVersion, object); if (isNotEmpty(operations)) { this.objectCache.addPatch(object.self, operations); diff --git a/src/app/core/data/item-data.service.spec.ts b/src/app/core/data/item-data.service.spec.ts index 44c5f48cfe..6f2719f374 100644 --- a/src/app/core/data/item-data.service.spec.ts +++ b/src/app/core/data/item-data.service.spec.ts @@ -6,22 +6,14 @@ 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, - GetRequest, - MappedCollectionsRequest, - PostRequest, - RestRequest -} from './request.models'; +import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { Observable } from 'rxjs'; +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 { of as observableOf } from 'rxjs'; import { getMockRequestService } from '../../shared/mocks/mock-request.service'; describe('ItemDataService', () => { @@ -184,7 +176,7 @@ describe('ItemDataService', () => { }); it('should configure a DELETE request', () => { - result.subscribe(() => expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(DeleteRequest), undefined)); + result.subscribe(() => expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(DeleteRequest))); }); }); @@ -198,7 +190,7 @@ describe('ItemDataService', () => { }); it('should configure a POST request', () => { - result.subscribe(() => expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(PostRequest), undefined)); + result.subscribe(() => expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(PostRequest))); }); }); diff --git a/src/app/core/data/relationship-type.service.ts b/src/app/core/data/relationship-type.service.ts index 627fc4863f..7978373b08 100644 --- a/src/app/core/data/relationship-type.service.ts +++ b/src/app/core/data/relationship-type.service.ts @@ -2,7 +2,7 @@ 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, tap } from 'rxjs/operators'; +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'; @@ -42,7 +42,7 @@ export class RelationshipTypeService { map((endpointURL: string) => new FindListRequest(this.requestService.generateRequestId(), endpointURL, options)), configureRequest(this.requestService), switchMap(() => this.rdbService.buildList(link$)) - ); + ) as Observable>>; } /** diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index d624238bb8..b73657ce2c 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -3,8 +3,13 @@ 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 { distinctUntilChanged, filter, map, mergeMap, skipWhile, startWith, switchMap, take, tap } from 'rxjs/operators'; -import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; +import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators'; +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'; @@ -15,7 +20,11 @@ import { RemoteData } 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 { + 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'; @@ -28,7 +37,10 @@ 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 { + RemoveNameVariantAction, + SetNameVariantAction +} from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions'; const relationshipListsStateSelector = (state: AppState) => state.relationshipLists; @@ -117,7 +129,7 @@ export class RelationshipService extends DataService { getResponseFromEntry(), tap(() => this.removeRelationshipItemsFromCache(item1)), tap(() => this.removeRelationshipItemsFromCache(item2)) - ); + ) as Observable; } /** diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index 5807666d66..01560380c2 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -21,6 +21,7 @@ import { } from './request.models'; import { RequestService } from './request.service'; import { TestScheduler } from 'rxjs/testing'; +import { RequestEntry } from './request.reducer'; describe('RequestService', () => { let scheduler: TestScheduler; @@ -107,7 +108,7 @@ describe('RequestService', () => { beforeEach(() => { spyOn(service, 'getByHref').and.returnValue(observableOf({ completed: false - })) + } as RequestEntry)) }); it('should return true', () => { @@ -122,7 +123,7 @@ describe('RequestService', () => { beforeEach(() => { spyOn(service, 'getByHref').and.returnValues(observableOf({ completed: true - })); + } as RequestEntry)); }); it('should return false', () => { @@ -432,7 +433,7 @@ describe('RequestService', () => { let valid; const requestEntry = { completed: false }; beforeEach(() => { - spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry)); + spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry as RequestEntry)); valid = serviceAsAny.isValid(requestEntry); }); it('return an observable emitting false', () => { @@ -444,7 +445,7 @@ describe('RequestService', () => { let valid; const requestEntry = { completed: true, response: { isSuccessful: false } }; beforeEach(() => { - spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry)); + spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry as RequestEntry)); valid = serviceAsAny.isValid(requestEntry); }); it('return an observable emitting false', () => { @@ -470,7 +471,7 @@ describe('RequestService', () => { beforeEach(() => { spyOn(Date.prototype, 'getTime').and.returnValue(now); - spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry)); + spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry as RequestEntry)); valid = serviceAsAny.isValid(requestEntry); }); @@ -497,7 +498,7 @@ describe('RequestService', () => { }; beforeEach(() => { spyOn(Date.prototype, 'getTime').and.returnValue(now); - spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry)); + spyOn(service, 'getByUUID').and.returnValue(observableOf(requestEntry as RequestEntry)); valid = serviceAsAny.isValid(requestEntry); }); diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index af9bf54cb8..b811a75549 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -5,8 +5,6 @@ import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { Observable, race as observableRace } from 'rxjs'; import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators'; import { cloneDeep, remove } from 'lodash'; - -import { AppState } from '../../app.reducer'; import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util'; import { CacheableObject } from '../cache/object-cache.reducer'; import { ObjectCacheService } from '../cache/object-cache.service'; @@ -19,7 +17,7 @@ import { } from '../index/index.selectors'; import { UUIDService } from '../shared/uuid.service'; import { RequestConfigureAction, RequestExecuteAction, RequestRemoveAction } from './request.actions'; -import { GetRequest, RestRequest, SubmissionRequest } from './request.models'; +import { GetRequest, RestRequest } from './request.models'; import { RequestEntry, RequestState } from './request.reducer'; import { CommitSSBAction } from '../cache/server-sync-buffer.actions'; import { RestRequestMethod } from './rest-request-method'; @@ -52,7 +50,7 @@ const entryFromUUIDSelector = (uuid: string): MemoizedSelector, href: string): MemoizedSelector => createSelector( + (selector: MemoizedSelector, href: string): MemoizedSelector => createSelector( selector, (state: IndexState) => getUuidsFromHrefSubstring(state, href) ); diff --git a/src/app/shared/history/history.actions.ts b/src/app/core/history/history.actions.ts similarity index 91% rename from src/app/shared/history/history.actions.ts rename to src/app/core/history/history.actions.ts index ad970bd350..d4e621cc1c 100644 --- a/src/app/shared/history/history.actions.ts +++ b/src/app/core/history/history.actions.ts @@ -1,6 +1,6 @@ import { Action } from '@ngrx/store'; -import { type } from '../ngrx/type'; +import { type } from '../../shared/ngrx/type'; export const HistoryActionTypes = { ADD_TO_HISTORY: type('dspace/history/ADD_TO_HISTORY'), diff --git a/src/app/shared/history/history.reducer.spec.ts b/src/app/core/history/history.reducer.spec.ts similarity index 100% rename from src/app/shared/history/history.reducer.spec.ts rename to src/app/core/history/history.reducer.spec.ts diff --git a/src/app/shared/history/history.reducer.ts b/src/app/core/history/history.reducer.ts similarity index 100% rename from src/app/shared/history/history.reducer.ts rename to src/app/core/history/history.reducer.ts diff --git a/src/app/core/history/selectors.ts b/src/app/core/history/selectors.ts new file mode 100644 index 0000000000..a04d3839b1 --- /dev/null +++ b/src/app/core/history/selectors.ts @@ -0,0 +1,3 @@ +import { CoreState } from '../core.reducers'; + +export const historySelector = (state: CoreState) => state.history; diff --git a/src/app/core/index/index.selectors.ts b/src/app/core/index/index.selectors.ts index a6d7b7e7b0..de4adab09b 100644 --- a/src/app/core/index/index.selectors.ts +++ b/src/app/core/index/index.selectors.ts @@ -1,5 +1,4 @@ import { createSelector, MemoizedSelector } from '@ngrx/store'; -import { AppState } from '../../app.reducer'; import { hasValue } from '../../shared/empty.util'; import { CoreState } from '../core.reducers'; import { coreSelector } from '../core.selectors'; @@ -11,7 +10,7 @@ import { IndexName, IndexState, MetaIndexState } from './index.reducer'; * @returns * a MemoizedSelector to select the MetaIndexState */ -export const metaIndexSelector: MemoizedSelector = createSelector( +export const metaIndexSelector: MemoizedSelector = createSelector( coreSelector, (state: CoreState) => state.index ); @@ -23,7 +22,7 @@ export const metaIndexSelector: MemoizedSelector = cre * @returns * a MemoizedSelector to select the object index */ -export const objectIndexSelector: MemoizedSelector = createSelector( +export const objectIndexSelector: MemoizedSelector = createSelector( metaIndexSelector, (state: MetaIndexState) => state[IndexName.OBJECT] ); @@ -34,7 +33,7 @@ export const objectIndexSelector: MemoizedSelector = creat * @returns * a MemoizedSelector to select the request index */ -export const requestIndexSelector: MemoizedSelector = createSelector( +export const requestIndexSelector: MemoizedSelector = createSelector( metaIndexSelector, (state: MetaIndexState) => state[IndexName.REQUEST] ); @@ -45,7 +44,7 @@ export const requestIndexSelector: MemoizedSelector = crea * @returns * a MemoizedSelector to select the request UUID mapping */ -export const requestUUIDIndexSelector: MemoizedSelector = createSelector( +export const requestUUIDIndexSelector: MemoizedSelector = createSelector( metaIndexSelector, (state: MetaIndexState) => state[IndexName.UUID_MAPPING] ); @@ -53,14 +52,13 @@ export const requestUUIDIndexSelector: MemoizedSelector = /** * Return the self link of an object in the object-cache based on its UUID * - * @param id + * @param uuid * the UUID for which you want to find the matching self link - * @param identifierType the type of index, used to select index from state * @returns * a MemoizedSelector to select the self link */ export const selfLinkFromUuidSelector = - (uuid: string): MemoizedSelector => createSelector( + (uuid: string): MemoizedSelector => createSelector( objectIndexSelector, (state: IndexState) => hasValue(state) ? state[uuid] : undefined ); @@ -74,7 +72,7 @@ export const selfLinkFromUuidSelector = * a MemoizedSelector to select the UUID */ export const uuidFromHrefSelector = - (href: string): MemoizedSelector => createSelector( + (href: string): MemoizedSelector => createSelector( requestIndexSelector, (state: IndexState) => hasValue(state) ? state[href] : undefined ); @@ -89,7 +87,7 @@ export const uuidFromHrefSelector = * a MemoizedSelector to select the UUID of the cached request */ export const originalRequestUUIDFromRequestUUIDSelector = - (uuid: string): MemoizedSelector => createSelector( + (uuid: string): MemoizedSelector => createSelector( requestUUIDIndexSelector, (state: IndexState) => hasValue(state) ? state[uuid] : undefined ); diff --git a/src/app/core/json-patch/json-patch-operations.service.ts b/src/app/core/json-patch/json-patch-operations.service.ts index 90eaf87a0e..c1b37bf904 100644 --- a/src/app/core/json-patch/json-patch-operations.service.ts +++ b/src/app/core/json-patch/json-patch-operations.service.ts @@ -17,7 +17,6 @@ import { } from './json-patch-operations.actions'; import { JsonPatchOperationModel } from './json-patch.model'; import { getResponseFromEntry } from '../shared/operators'; -import { ObjectCacheEntry } from '../cache/object-cache.reducer'; /** * An abstract class that provides methods to make JSON Patch requests. @@ -88,8 +87,8 @@ export abstract class JsonPatchOperationsService { const [successResponse$, errorResponse$] = partition((response: RestResponse) => response.isSuccessful)(this.requestService.getByUUID(requestId).pipe( getResponseFromEntry(), - find((entry: ObjectCacheEntry) => startTransactionTime < entry.timeAdded), - map((entry: ObjectCacheEntry) => entry), + find((entry: RestResponse) => startTransactionTime < entry.timeAdded), + map((entry: RestResponse) => entry), )); return observableMerge( errorResponse$.pipe( diff --git a/src/app/core/services/route.service.spec.ts b/src/app/core/services/route.service.spec.ts index ae31f28384..525329d50f 100644 --- a/src/app/core/services/route.service.spec.ts +++ b/src/app/core/services/route.service.spec.ts @@ -8,7 +8,7 @@ import { getTestScheduler, hot } from 'jasmine-marbles'; import { RouteService } from './route.service'; import { MockRouter } from '../../shared/mocks/mock-router'; import { TestScheduler } from 'rxjs/testing'; -import { AddUrlToHistoryAction } from '../../shared/history/history.actions'; +import { AddUrlToHistoryAction } from '../history/history.actions'; describe('RouteService', () => { let scheduler: TestScheduler; diff --git a/src/app/core/services/route.service.ts b/src/app/core/services/route.service.ts index b29c491cb0..2a0df6d16a 100644 --- a/src/app/core/services/route.service.ts +++ b/src/app/core/services/route.service.ts @@ -1,28 +1,17 @@ -import { distinctUntilChanged, filter, map, take, tap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, take } from 'rxjs/operators'; import { Injectable } from '@angular/core'; -import { - ActivatedRoute, - NavigationEnd, - Params, - Router, - RouterStateSnapshot, -} from '@angular/router'; +import { ActivatedRoute, NavigationEnd, Params, Router, RouterStateSnapshot, } from '@angular/router'; import { combineLatest, Observable } from 'rxjs'; import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store'; import { isEqual } from 'lodash'; -import { - AddParameterAction, - SetParameterAction, - SetParametersAction, - SetQueryParametersAction -} from './route.actions'; -import { CoreState } from '../../core/core.reducers'; -import { coreSelector } from '../../core/core.selectors'; +import { AddParameterAction, SetParameterAction, SetParametersAction, SetQueryParametersAction } from './route.actions'; +import { CoreState } from '../core.reducers'; +import { coreSelector } from '../core.selectors'; import { hasValue } from '../../shared/empty.util'; -import { historySelector } from '../../shared/history/selectors'; -import { AddUrlToHistoryAction } from '../../shared/history/history.actions'; +import { historySelector } from '../history/selectors'; +import { AddUrlToHistoryAction } from '../history/history.actions'; /** * Selector to select all route parameters from the store diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html index 4df07880d8..86de30c23e 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html @@ -1,6 +1,6 @@