diff --git a/src/app/item-page/edit-item-page/item-status/item-status.component.ts b/src/app/item-page/edit-item-page/item-status/item-status.component.ts index c2db518415..ce84786304 100644 --- a/src/app/item-page/edit-item-page/item-status/item-status.component.ts +++ b/src/app/item-page/edit-item-page/item-status/item-status.component.ts @@ -9,9 +9,9 @@ import { RemoteData } from '../../../core/data/remote-data'; import { getItemEditRoute, getItemPageRoute } from '../../item-page-routing-paths'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { FeatureID } from '../../../core/data/feature-authorization/feature-id'; -import { hasValue } from '../../../shared/empty.util'; +import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { - getAllSucceededRemoteDataPayload, getFirstSucceededRemoteData, getRemoteDataPayload, + getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload, } from '../../../core/shared/operators'; import { IdentifierDataService } from '../../../core/data/identifier-data.service'; import { Identifier } from '../../../shared/object-list/identifier-data/identifier.model'; @@ -105,12 +105,13 @@ export class ItemStatusComponent implements OnInit { // Observable for configuration determining whether the Register DOI feature is enabled let registerConfigEnabled$: Observable = this.configurationService.findByPropertyName('identifiers.item-status.register-doi').pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - map((enabled: ConfigurationProperty) => { - if (enabled !== undefined && enabled.values) { - return true; + getFirstCompletedRemoteData(), + map((rd: RemoteData) => { + // If the config property is exposed via rest and has a value set, return it + if (rd.hasSucceeded && hasValue(rd.payload) && isNotEmpty(rd.payload.values)) { + return rd.payload.values[0] === 'true'; } + // Otherwise, return false return false; }) ); diff --git a/src/app/shared/menu/menu.service.spec.ts b/src/app/shared/menu/menu.service.spec.ts index f4b0fe3db8..0d8d669a0a 100644 --- a/src/app/shared/menu/menu.service.spec.ts +++ b/src/app/shared/menu/menu.service.spec.ts @@ -567,4 +567,41 @@ describe('MenuService', () => { }); }); + describe(`resolveSubstitutions`, () => { + let linkPrefix; + let link; + let uuid; + + beforeEach(() => { + linkPrefix = 'statistics_collection_'; + link = `${linkPrefix}:id`; + uuid = 'f7cc3ca4-3c2c-464d-8af8-add9f84f711c'; + }); + + it(`shouldn't do anything when there are no params`, () => { + let result = (service as any).resolveSubstitutions(link, undefined); + expect(result).toEqual(link); + result = (service as any).resolveSubstitutions(link, null); + expect(result).toEqual(link); + result = (service as any).resolveSubstitutions(link, {}); + expect(result).toEqual(link); + }); + + it(`should replace link params that are also route params`, () => { + const result = (service as any).resolveSubstitutions(link,{ 'id': uuid }); + expect(result).toEqual(linkPrefix + uuid); + }); + + it(`should not replace link params that aren't route params`, () => { + const result = (service as any).resolveSubstitutions(link,{ 'something': 'else' }); + expect(result).toEqual(link); + }); + + it(`should gracefully deal with routes that contain the name of the route param`, () => { + const selfReferentialParam = `:id:something`; + const result = (service as any).resolveSubstitutions(link,{ 'id': selfReferentialParam }); + expect(result).toEqual(linkPrefix + selfReferentialParam); + }); + }); + }); diff --git a/src/app/shared/menu/menu.service.ts b/src/app/shared/menu/menu.service.ts index 2253e9ce09..fac3b3fba7 100644 --- a/src/app/shared/menu/menu.service.ts +++ b/src/app/shared/menu/menu.service.ts @@ -17,7 +17,7 @@ import { ToggleActiveMenuSectionAction, ToggleMenuAction, } from './menu.actions'; -import { hasNoValue, hasValue, hasValueOperator, isNotEmpty } from '../empty.util'; +import { hasNoValue, hasValue, hasValueOperator, isNotEmpty, isEmpty } from '../empty.util'; import { MenuState } from './menu-state.model'; import { MenuSections } from './menu-sections.model'; import { MenuSection } from './menu-section.model'; @@ -409,20 +409,14 @@ export class MenuService { } protected resolveSubstitutions(object, params) { - let resolved; - if (typeof object === 'string') { + if (isEmpty(params)) { resolved = object; - let match: RegExpMatchArray; - do { - match = resolved.match(/:(\w+)/); - if (match) { - const substitute = params[match[1]]; - if (hasValue(substitute)) { - resolved = resolved.replace(match[0], `${substitute}`); - } - } - } while (match); + } else if (typeof object === 'string') { + resolved = object; + Object.entries(params).forEach(([key, value]: [string, string]) => + resolved = resolved.replaceAll(`:${key}`, value) + ); } else if (Array.isArray(object)) { resolved = []; object.forEach((entry, index) => { diff --git a/src/app/shared/mocks/submission.mock.ts b/src/app/shared/mocks/submission.mock.ts index b90cababcb..268ae33ab3 100644 --- a/src/app/shared/mocks/submission.mock.ts +++ b/src/app/shared/mocks/submission.mock.ts @@ -1668,11 +1668,7 @@ export const mockFileFormData = { ], endDate: [ { - value: { - year: 2019, - month: 1, - day: 16 - }, + value: new Date('2019-01-16'), language: null, authority: null, display: { @@ -1694,7 +1690,7 @@ export const mockFileFormData = { value: 'embargo', language: null, authority: null, - display: 'lease', + display: 'embargo', confidence: -1, place: 0, otherInformation: null @@ -1702,11 +1698,7 @@ export const mockFileFormData = { ], startDate: [ { - value: { - year: 2019, - month: 1, - day: 16 - }, + value: new Date('2019-01-16'), language: null, authority: null, display: { 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 83cde97bcb..9ee4a7dda5 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 @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { @@ -66,7 +66,8 @@ import { DynamicDateControlValue } from '@ng-dynamic-forms/core/lib/model/dynami styleUrls: ['./section-upload-file-edit.component.scss'], templateUrl: './section-upload-file-edit.component.html', }) -export class SubmissionSectionUploadFileEditComponent implements OnInit { +export class SubmissionSectionUploadFileEditComponent + implements OnInit, OnDestroy { /** * The FormComponent reference @@ -435,13 +436,31 @@ export class SubmissionSectionUploadFileEditComponent implements OnInit { delete currentAccessCondition.startDate; } else if (accessCondition.startDate) { const startDate = this.retrieveValueFromField(accessCondition.startDate); - currentAccessCondition.startDate = dateToISOFormat(startDate); + // Clamp the start date to the maximum, if any, since the + // datepicker sometimes exceeds it. + let startDateDate = new Date(startDate); + if (accessConditionOpt.maxStartDate) { + const maxStartDateDate = new Date(accessConditionOpt.maxStartDate); + if (startDateDate > maxStartDateDate) { + startDateDate = maxStartDateDate; + } + } + currentAccessCondition.startDate = dateToISOFormat(startDateDate); } if (!accessConditionOpt.hasEndDate) { delete currentAccessCondition.endDate; } else if (accessCondition.endDate) { const endDate = this.retrieveValueFromField(accessCondition.endDate); - currentAccessCondition.endDate = dateToISOFormat(endDate); + // Clamp the end date to the maximum, if any, since the + // datepicker sometimes exceeds it. + let endDateDate = new Date(endDate); + if (accessConditionOpt.maxEndDate) { + const maxEndDateDate = new Date(accessConditionOpt.maxEndDate); + if (endDateDate > maxEndDateDate) { + endDateDate = maxEndDateDate; + } + } + currentAccessCondition.endDate = dateToISOFormat(endDateDate); } accessConditionsToSave.push(currentAccessCondition); } diff --git a/yarn.lock b/yarn.lock index d1d0f56ab5..730966fcdb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10377,9 +10377,9 @@ socket.io-client@^4.4.1: socket.io-parser "~4.2.1" socket.io-parser@~4.2.1: - version "4.2.2" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz" - integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + version "4.2.3" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.3.tgz#926bcc6658e2ae0883dc9dee69acbdc76e4e3667" + integrity sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1"