diff --git a/config/environment.default.js b/config/environment.default.js index df4f89a2fe..24386d6cf7 100644 --- a/config/environment.default.js +++ b/config/environment.default.js @@ -9,10 +9,11 @@ module.exports = { }, // The REST API server settings. rest: { - ssl: true, - host: 'dspace7-entities.atmire.com', - port: 443, - nameSpace: '/server/api' + ssl: true, + host: 'dspace7.4science.cloud', + port: 443, + // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript + nameSpace: '/server/api' }, // Caching settings cache: { diff --git a/src/app/+search-page/search.component.html b/src/app/+search-page/search.component.html index a6e83d2b64..f3731607db 100644 --- a/src/app/+search-page/search.component.html +++ b/src/app/+search-page/search.component.html @@ -48,7 +48,7 @@
- +
diff --git a/src/app/core/data/status-code-only-response-parsing.service.spec.ts b/src/app/core/data/status-code-only-response-parsing.service.spec.ts new file mode 100644 index 0000000000..cbf2a49c48 --- /dev/null +++ b/src/app/core/data/status-code-only-response-parsing.service.spec.ts @@ -0,0 +1,93 @@ +import { StatusCodeOnlyResponseParsingService } from './status-code-only-response-parsing.service'; + +describe('StatusCodeOnlyResponseParsingService', () => { + let service; + let statusCode; + let statusText; + + beforeEach(() => { + service = new StatusCodeOnlyResponseParsingService(); + }); + + describe('parse', () => { + + it('should return a RestResponse that doesn\'t contain the response body', () => { + const payload = 'd9128e44-183b-479d-aa2e-d39435838bf6'; + const result = service.parse(undefined, { + payload, + statusCode: 201, + statusText: '201' + }); + + expect(JSON.stringify(result).indexOf(payload)).toBe(-1); + }); + + describe('when the response is successful', () => { + beforeEach(() => { + statusCode = 201; + statusText = `${statusCode}`; + }); + + it('should return a success RestResponse', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.isSuccessful).toBe(true); + }); + + it('should return a RestResponse with the correct status code', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.statusCode).toBe(statusCode); + }); + + it('should return a RestResponse with the correct status text', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.statusText).toBe(statusText); + }); + }); + + describe('when the response is unsuccessful', () => { + beforeEach(() => { + statusCode = 400; + statusText = `${statusCode}`; + }); + + it('should return an error RestResponse', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.isSuccessful).toBe(false); + }); + + it('should return a RestResponse with the correct status code', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.statusCode).toBe(statusCode); + }); + + it('should return a RestResponse with the correct status text', () => { + const result = service.parse(undefined, { + statusCode, + statusText + }); + + expect(result.statusText).toBe(statusText); + }); + }); + }); +}); diff --git a/src/app/core/data/status-code-only-response-parsing.service.ts b/src/app/core/data/status-code-only-response-parsing.service.ts new file mode 100644 index 0000000000..b9812dcfee --- /dev/null +++ b/src/app/core/data/status-code-only-response-parsing.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { RestResponse } from '../cache/response.models'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; +import { ResponseParsingService } from './parsing.service'; +import { RestRequest } from './request.models'; + +/** + * A responseparser that will only look at the status code and status + * text of the response, and ignore anything else that might be there + */ +@Injectable({ + providedIn: 'root' +}) +export class StatusCodeOnlyResponseParsingService implements ResponseParsingService { + + /** + * Parse the response and only extract the status code and status text + * + * @param request The request that was sent to the server + * @param data The response to parse + */ + parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { + const isSuccessful = data.statusCode >= 200 && data.statusCode < 300; + return new RestResponse(isSuccessful, data.statusCode, data.statusText); + } +} diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index 0d1aa74591..308e4f8a2d 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -125,9 +125,3 @@ export const getFirstOccurrence = () => source.pipe( map((rd) => Object.assign(rd, { payload: rd.payload.page.length > 0 ? rd.payload.page[0] : undefined })) ); - -export const obsLog = (logString?: string) => - (source: Observable): Observable => - source.pipe( - tap((t) => console.log(logString || '', t)) - ); diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts index da3b578fcd..8bc2971922 100644 --- a/src/app/core/submission/submission-response-parsing.service.ts +++ b/src/app/core/submission/submission-response-parsing.service.ts @@ -1,4 +1,6 @@ import { Inject, Injectable } from '@angular/core'; +import { deepClone } from 'fast-json-patch'; +import { DSOResponseParsingService } from '../data/dso-response-parsing.service'; import { ResponseParsingService } from '../data/parsing.service'; import { RestRequest } from '../data/request.models'; @@ -76,7 +78,9 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService protected toCache = false; constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, - protected objectCache: ObjectCacheService) { + protected objectCache: ObjectCacheService, + protected dsoParser: DSOResponseParsingService + ) { super(); } @@ -88,6 +92,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService * @returns {RestResponse} */ parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { + this.dsoParser.parse(deepClone(request), deepClone(data)); if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && this.isSuccessStatus(data.statusCode)) { diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.spec.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.spec.ts new file mode 100644 index 0000000000..34b89cc8aa --- /dev/null +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-suggestions/org-unit-input-suggestions.component.spec.ts @@ -0,0 +1,64 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { OrgUnitInputSuggestionsComponent } from './org-unit-input-suggestions.component'; +import { FormsModule } from '@angular/forms'; + +let component: OrgUnitInputSuggestionsComponent; +let fixture: ComponentFixture; + +let suggestions: string[]; +let testValue; + +function init() { + suggestions = ['test', 'suggestion', 'example'] + testValue = 'bla'; +} + +describe('OrgUnitInputSuggestionsComponent', () => { + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + declarations: [OrgUnitInputSuggestionsComponent], + imports: [ + FormsModule, + ], + providers: [ + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(OrgUnitInputSuggestionsComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitInputSuggestionsComponent); + component = fixture.componentInstance; + component.suggestions = suggestions; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('When the component is initialized', () => { + it('should set the value to the first value of the suggestions', () => { + expect(component.value).toEqual('test'); + }); + }); + + describe('When onSubmit is called', () => { + it('should set the value to parameter of the method', () => { + component.onSubmit(testValue); + expect(component.value).toEqual(testValue); + }); + }); + + describe('When onClickSuggestion is called', () => { + it('should set the value to parameter of the method', () => { + component.onClickSuggestion(testValue); + expect(component.value).toEqual(testValue); + }); + }); + +}); 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 4c9dad7fe9..d2e4fdd2d0 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 @@ -85,8 +85,7 @@ import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/d import { getAllSucceededRemoteData, getRemoteDataPayload, - getSucceededRemoteData, - obsLog + getSucceededRemoteData } from '../../../../core/shared/operators'; import { RemoteData } from '../../../../core/data/remote-data'; import { Item } from '../../../../core/shared/item.model'; @@ -100,7 +99,6 @@ import { PaginatedList } from '../../../../core/data/paginated-list'; import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; -import * as uuidv4 from 'uuid/v4'; import { Collection } from '../../../../core/shared/collection.model'; export function dsDynamicFormControlMapFn(model: DynamicFormControlModel): Type | null { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts index 3d713b15fe..c734766d75 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.spec.ts @@ -26,9 +26,11 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { let item1; let item2; let item3; + let item4; let searchResult1; let searchResult2; let searchResult3; + let searchResult4; let listID; let selection$; @@ -42,9 +44,11 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); item3 = Object.assign(new Item(), { uuid: 'c3bcbff5-ec0c-4831-8e4c-94b9c933ccac' }); + item4 = Object.assign(new Item(), { uuid: 'f96a385e-de10-45b2-be66-7f10bf52f765' }); searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); searchResult3 = Object.assign(new ItemSearchResult(), { indexableObject: item3 }); + searchResult4 = Object.assign(new ItemSearchResult(), { indexableObject: item4 }); listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; selection$ = observableOf([searchResult1, searchResult2]); @@ -102,12 +106,12 @@ describe('DsDynamicLookupRelationSearchTabComponent', () => { describe('selectPage', () => { beforeEach(() => { spyOn(component.selectObject, 'emit'); - component.selectPage([searchResult1, searchResult2, searchResult3]); + component.selectPage([searchResult1, searchResult2, searchResult4]); }); it('should emit the page filtered from already selected objects and call select on the service for all objects', () => { - expect(component.selectObject.emit).toHaveBeenCalledWith(searchResult3); - expect(selectableListService.select).toHaveBeenCalledWith(listID, [searchResult1, searchResult2, searchResult3]); + expect(component.selectObject.emit).toHaveBeenCalledWith(searchResult4); + expect(selectableListService.select).toHaveBeenCalledWith(listID, [searchResult1, searchResult2, searchResult4]); }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts index 32c995ba94..203a4df0b0 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/selection-tab/dynamic-lookup-relation-selection-tab.component.spec.ts @@ -1,46 +1,59 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { SearchConfigurationService } from '../../../../../../core/shared/search/search-configuration.service'; -import { RouterTestingModule } from '@angular/router/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { VarDirective } from '../../../../../utils/var.directive'; -import { of as observableOf } from 'rxjs'; +import { Observable, of as observableOf } from 'rxjs'; import { PaginatedSearchOptions } from '../../../../../search/paginated-search-options.model'; import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; import { Item } from '../../../../../../core/shared/item.model'; import { DsDynamicLookupRelationSelectionTabComponent } from './dynamic-lookup-relation-selection-tab.component'; import { PaginationComponentOptions } from '../../../../../pagination/pagination-component-options.model'; +import { Router } from '@angular/router'; +import { By } from '@angular/platform-browser'; +import { RemoteData } from '../../../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../../../core/data/paginated-list'; +import { ListableObject } from '../../../../../object-collection/shared/listable-object.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../testing/utils'; describe('DsDynamicLookupRelationSelectionTabComponent', () => { let component: DsDynamicLookupRelationSelectionTabComponent; let fixture: ComponentFixture; - let pSearchOptions = new PaginatedSearchOptions({pagination: new PaginationComponentOptions()}); + let pSearchOptions = new PaginatedSearchOptions({ pagination: new PaginationComponentOptions() }); let item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); let item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); let searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); let searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); let listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; - let selection$ = observableOf([searchResult1, searchResult2]); + let selection$; + let selectionRD$; + let router; function init() { - pSearchOptions = new PaginatedSearchOptions({pagination: new PaginationComponentOptions()}); + pSearchOptions = new PaginatedSearchOptions({ pagination: new PaginationComponentOptions() }); item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' }); item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' }); searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 }); searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 }); listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3'; selection$ = observableOf([searchResult1, searchResult2]); + selectionRD$ = createSelection([searchResult1, searchResult2]); + router = jasmine.createSpyObj('router', ['navigate']) } + beforeEach(async(() => { init(); TestBed.configureTestingModule({ declarations: [DsDynamicLookupRelationSelectionTabComponent, VarDirective], - imports: [TranslateModule.forRoot(), RouterTestingModule.withRoutes([])], + imports: [TranslateModule.forRoot()], providers: [ { provide: SearchConfigurationService, useValue: { paginatedSearchOptions: observableOf(pSearchOptions) - } + }, + }, + { + provide: Router, useValue: router } ], schemas: [NO_ERRORS_SCHEMA] @@ -59,4 +72,26 @@ describe('DsDynamicLookupRelationSelectionTabComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should call navigate on the router when is called resetRoute', () => { + component.resetRoute(); + expect(router.navigate).toHaveBeenCalled(); + }); + + it('should call navigate on the router when is called resetRoute', () => { + component.selectionRD$ = createSelection([]); + fixture.detectChanges(); + const colComponent = fixture.debugElement.query(By.css('ds-viewable-collection')); + expect(colComponent).toBe(null); + }); + + it('should call navigate on the router when is called resetRoute', () => { + component.selectionRD$ = selectionRD$; + const colComponent = fixture.debugElement.query(By.css('ds-viewable-collection')); + expect(colComponent).not.toBe(null); + }); }); + +function createSelection(content: ListableObject[]): Observable>> { + return createSuccessfulRemoteDataObject$(new PaginatedList(undefined, content)); +} diff --git a/src/app/shared/mocks/dspace-rest-v2/mocks/mock-response-map.ts b/src/app/shared/mocks/dspace-rest-v2/mocks/mock-response-map.ts index 1d1b47ee78..a7fab782da 100644 --- a/src/app/shared/mocks/dspace-rest-v2/mocks/mock-response-map.ts +++ b/src/app/shared/mocks/dspace-rest-v2/mocks/mock-response-map.ts @@ -5,6 +5,11 @@ export class MockResponseMap extends Map {}; export const MOCK_RESPONSE_MAP: InjectionToken = new InjectionToken('mockResponseMap'); +/** + * List of endpoints with their matching mock response + * Note that this list is only used in development mode + * In production the actual endpoints on the REST server will be called + */ export const mockResponseMap: MockResponseMap = new Map([ // [ '/config/submissionforms/traditionalpageone', mockSubmissionResponse ] ]); diff --git a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.ts b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.ts index d1536c56e6..d47e05c8fe 100644 --- a/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.ts +++ b/src/app/shared/object-collection/shared/selectable-list-item-control/selectable-list-item-control.component.ts @@ -10,7 +10,7 @@ import { Observable } from 'rxjs'; templateUrl: './selectable-list-item-control.component.html' }) /** - * Component for determining what component to use depending on the item's relationship type (relationship.type) + * Component for rendering list item that has a control (checkbox or radio button) because it's selectable */ export class SelectableListItemControlComponent implements OnInit { /** diff --git a/src/app/shared/object-list/object-list.component.ts b/src/app/shared/object-list/object-list.component.ts index 5ebaae668c..60544c4ec5 100644 --- a/src/app/shared/object-list/object-list.component.ts +++ b/src/app/shared/object-list/object-list.component.ts @@ -1,21 +1,11 @@ -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - Output, - ViewEncapsulation -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { RemoteData } from '../../core/data/remote-data'; import { fadeIn } from '../animations/fade'; import { ListableObject } from '../object-collection/shared/listable-object.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { SearchResult } from '../search/search-result.model'; import { SelectableListService } from './selectable-list/selectable-list.service'; -import { map, take, tap } from 'rxjs/operators'; import { ViewMode } from '../../core/shared/view-mode.model'; import { Context } from '../../core/shared/context.model'; import { CollectionElementLinkType } from '../object-collection/collection-element-link.type'; @@ -60,9 +50,6 @@ export class ObjectListComponent { @Input() hidePagerWhenSinglePage = true; @Input() selectable = false; @Input() selectionConfig: { repeatable: boolean, listId: string }; - // @Input() previousSelection: ListableObject[] = []; - // allSelected = false; - // selectAllLoading = false; /** * The link type of the listable elements diff --git a/src/app/shared/object-list/selectable-list/selectable-list.actions.ts b/src/app/shared/object-list/selectable-list/selectable-list.actions.ts index 3dedf7e6a2..010ae5609d 100644 --- a/src/app/shared/object-list/selectable-list/selectable-list.actions.ts +++ b/src/app/shared/object-list/selectable-list/selectable-list.actions.ts @@ -55,7 +55,7 @@ export class SelectableListSelectSingleAction extends SelectableListAction { } /** - * Action to deselect objects in a the selectable list + * Action to deselect a single object in a the selectable list */ export class SelectableListDeselectSingleAction extends SelectableListAction { payload: ListableObject; @@ -67,7 +67,7 @@ export class SelectableListDeselectSingleAction extends SelectableListAction { } /** - * Action to deselect a single object in a the selectable list + * Action to deselect objects in a the selectable list */ export class SelectableListDeselectAction extends SelectableListAction { payload: ListableObject[]; diff --git a/src/app/shared/page-size-selector/page-size-selector.component.ts b/src/app/shared/page-size-selector/page-size-selector.component.ts index 799993d35d..b200c337f8 100644 --- a/src/app/shared/page-size-selector/page-size-selector.component.ts +++ b/src/app/shared/page-size-selector/page-size-selector.component.ts @@ -14,7 +14,7 @@ import { map } from 'rxjs/operators'; }) /** - * This component represents the part of the search sidebar that contains the general search settings. + * This component represents the part of the search sidebar that contains the page size settings. */ export class PageSizeSelectorComponent implements OnInit { /** diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts index e9b5f46fa8..78c40501e6 100644 --- a/src/app/shared/search/search-filters/search-filters.component.ts +++ b/src/app/shared/search/search-filters/search-filters.component.ts @@ -8,7 +8,7 @@ import { RemoteData } from '../../../core/data/remote-data'; import { SearchFilterConfig } from '../search-filter-config.model'; import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service'; import { SearchFilterService } from '../../../core/shared/search/search-filter.service'; -import { getSucceededRemoteData, obsLog } from '../../../core/shared/operators'; +import { getSucceededRemoteData } from '../../../core/shared/operators'; import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component'; import { currentPath } from '../../utils/route.utils'; import { Router } from '@angular/router'; diff --git a/src/app/shared/search/search-labels/search-label/search-label.component.spec.ts b/src/app/shared/search/search-labels/search-label/search-label.component.spec.ts index 0b382015af..8c6860c2d3 100644 --- a/src/app/shared/search/search-labels/search-label/search-label.component.spec.ts +++ b/src/app/shared/search/search-labels/search-label/search-label.component.spec.ts @@ -4,7 +4,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { Observable, of as observableOf } from 'rxjs'; -import { Params } from '@angular/router'; +import { Params, Router } from '@angular/router'; import { SearchLabelComponent } from './search-label.component'; import { ObjectKeysPipe } from '../../../utils/object-keys-pipe'; import { SEARCH_CONFIG_SERVICE } from '../../../../+my-dspace-page/my-dspace-page.component'; @@ -39,7 +39,8 @@ describe('SearchLabelComponent', () => { declarations: [SearchLabelComponent, ObjectKeysPipe], providers: [ { provide: SearchService, useValue: new SearchServiceStub(searchLink) }, - { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() } + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }, + { provide: Router, useValue: {} } // { provide: SearchConfigurationService, useValue: {getCurrentFrontendFilters : () => observableOf({})} } ], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/shared/search/search-labels/search-label/search-label.component.ts b/src/app/shared/search/search-labels/search-label/search-label.component.ts index e821af19c9..956b5b81de 100644 --- a/src/app/shared/search/search-labels/search-label/search-label.component.ts +++ b/src/app/shared/search/search-labels/search-label/search-label.component.ts @@ -1,9 +1,10 @@ import { Component, Input, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; -import { Params } from '@angular/router'; +import { Params, Router } from '@angular/router'; import { map } from 'rxjs/operators'; import { hasValue, isNotEmpty } from '../../../empty.util'; import { SearchService } from '../../../../core/shared/search/search.service'; +import { currentPath } from '../../../utils/route.utils'; @Component({ selector: 'ds-search-label', @@ -25,7 +26,8 @@ export class SearchLabelComponent implements OnInit { * Initialize the instance variable */ constructor( - private searchService: SearchService) { + private searchService: SearchService, + private router: Router) { } ngOnInit(): void { @@ -55,7 +57,7 @@ export class SearchLabelComponent implements OnInit { */ private getSearchLink(): string { if (this.inPlaceSearch) { - return './'; + return currentPath(this.router); } return this.searchService.getSearchLink(); } diff --git a/src/app/shared/utils/relation-query.utils.spec.ts b/src/app/shared/utils/relation-query.utils.spec.ts new file mode 100644 index 0000000000..f70e904422 --- /dev/null +++ b/src/app/shared/utils/relation-query.utils.spec.ts @@ -0,0 +1,18 @@ +import { getFilterByRelation, getQueryByRelations } from './relation-query.utils'; + +describe('Relation Query Utils', () => { + const relationtype = 'isAuthorOfPublication'; + const itemUUID = 'a7939af0-36ad-430d-af09-7be8b0a4dadd'; + describe('getQueryByRelations', () => { + it('Should return the correct query based on relationtype and uuid', () => { + const result = getQueryByRelations(relationtype, itemUUID); + expect(result).toEqual('query=relation.isAuthorOfPublication:a7939af0-36ad-430d-af09-7be8b0a4dadd'); + }); + }); + describe('getFilterByRelation', () => { + it('Should return the correct query based on relationtype and uuid', () => { + const result = getFilterByRelation(relationtype, itemUUID); + expect(result).toEqual('f.isAuthorOfPublication=a7939af0-36ad-430d-af09-7be8b0a4dadd'); + }); + }); +}); diff --git a/src/app/shared/utils/route.utils.spec.ts b/src/app/shared/utils/route.utils.spec.ts new file mode 100644 index 0000000000..610fd8756d --- /dev/null +++ b/src/app/shared/utils/route.utils.spec.ts @@ -0,0 +1,22 @@ +import { currentPath } from './route.utils'; + +describe('Route Utils', () => { + const urlTree = { + root: { + children: { + primary: { + segments: [ + { path: 'test' }, + { path: 'path' } + ] + } + + } + } + }; + const router = { parseUrl: () => urlTree } as any; + it('Should return the correct current path based on the router', () => { + const result = currentPath(router); + expect(result).toEqual('/test/path'); + }); + }); diff --git a/src/app/shared/utils/route.utils.ts b/src/app/shared/utils/route.utils.ts index b0771d4f13..6510fb8894 100644 --- a/src/app/shared/utils/route.utils.ts +++ b/src/app/shared/utils/route.utils.ts @@ -1,5 +1,9 @@ import { Router } from '@angular/router'; +/** + * Util function to retrieve the current path (without query parameters) the user is on + * @param router The router service + */ export function currentPath(router: Router) { const urlTree = router.parseUrl(router.url); return '/' + urlTree.root.children.primary.segments.map((it) => it.path).join('/') diff --git a/src/app/statistics/track-request.model.ts b/src/app/statistics/track-request.model.ts index df3e51c070..770d3146c6 100644 --- a/src/app/statistics/track-request.model.ts +++ b/src/app/statistics/track-request.model.ts @@ -1,4 +1,11 @@ +import { ResponseParsingService } from '../core/data/parsing.service'; import { PostRequest } from '../core/data/request.models'; +import { StatusCodeOnlyResponseParsingService } from '../core/data/status-code-only-response-parsing.service'; +import { GenericConstructor } from '../core/shared/generic-constructor'; export class TrackRequest extends PostRequest { + + getResponseParser(): GenericConstructor { + return StatusCodeOnlyResponseParsingService; + } } diff --git a/src/app/submission/sections/form/section-form.component.ts b/src/app/submission/sections/form/section-form.component.ts index 6c8d7c5468..49dbaea807 100644 --- a/src/app/submission/sections/form/section-form.component.ts +++ b/src/app/submission/sections/form/section-form.component.ts @@ -166,8 +166,8 @@ export class SubmissionSectionformComponent extends SectionModelComponent { .subscribe(([sectionData, workspaceItem]: [WorkspaceitemSectionFormObject, WorkspaceItem]) => { if (isUndefined(this.formModel)) { this.sectionData.errors = []; - // Is the first loading so init form this.workspaceItem = workspaceItem; + // Is the first loading so init form this.initForm(sectionData); this.sectionData.data = sectionData; this.subscriptions();