From 18728954656fbfd1efb67d5a13884ece087b224e Mon Sep 17 00:00:00 2001 From: dspeed2 Date: Mon, 16 Mar 2026 14:13:54 +0000 Subject: [PATCH 01/73] Merge frontend dspace 8.3 into UoEMainLibrary-dspace-8_x (#8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump sanitize-html from 2.16.0 to 2.17.0 Bumps [sanitize-html](https://github.com/apostrophecms/sanitize-html) from 2.16.0 to 2.17.0. - [Changelog](https://github.com/apostrophecms/sanitize-html/blob/main/CHANGELOG.md) - [Commits](https://github.com/apostrophecms/sanitize-html/compare/2.16.0...2.17.0) --- updated-dependencies: - dependency-name: sanitize-html dependency-version: 2.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * minor translation improvement: use plural in German translation (cherry picked from commit 027a5ec5f0cc39ed857da2297183507ad5c21bb6) * added German translations (cherry picked from commit f12fae3865c4f9053fa27bbce3df0e0c58f4f0cf) * added german translations (cherry picked from commit 4ca1edfc633dba35c8043d2c124a2afe0ee96994) * Fixed search facet deadlock Also fixed minor issue in MetadataService, but this doesn't cause any issues in the current code (cherry picked from commit 446280b59a65c8c0ce24a796ffd14b5eef6eafd0) * fix theming for DS8 * Bump @babel/runtime from 7.27.3 to 7.27.4 Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.27.3 to 7.27.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.27.4/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-version: 7.27.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump postcss from 8.5.3 to 8.5.4 in the postcss group Bumps the postcss group with 1 update: [postcss](https://github.com/postcss/postcss). Updates `postcss` from 8.5.3 to 8.5.4 - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.3...8.5.4) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: postcss ... Signed-off-by: dependabot[bot] * Bump postcss from 8.5.3 to 8.5.4 in the postcss group Bumps the postcss group with 1 update: [postcss](https://github.com/postcss/postcss). Updates `postcss` from 8.5.3 to 8.5.4 - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.3...8.5.4) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: postcss ... Signed-off-by: dependabot[bot] * Bump @babel/runtime from 7.27.3 to 7.27.4 Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.27.3 to 7.27.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.27.4/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-version: 7.27.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * 129964: Fixed the header role structure being invalid in the custom theme - Replaced the menubar role from the parent of all the header buttons like lang switch, auth menu & help toggle with toolbar - Replaced the remaining `` buttons in the header with ` + + + diff --git a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.spec.ts b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.spec.ts index 7c6994f0837..1077dfdfcb1 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.spec.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.spec.ts @@ -18,7 +18,7 @@ import { Community } from '../../../../core/shared/community.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils'; import { RouterStub } from '../../../testing/router.stub'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { CreateCollectionParentSelectorComponent } from './create-collection-parent-selector.component'; describe('CreateCollectionParentSelectorComponent', () => { @@ -64,7 +64,7 @@ describe('CreateCollectionParentSelectorComponent', () => { schemas: [NO_ERRORS_SCHEMA], }) .overrideComponent(CreateCollectionParentSelectorComponent, { - remove: { imports: [DSOSelectorComponent] }, + remove: { imports: [AuthorizedCommunitySelectorComponent] }, }) .compileComponents(); diff --git a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts index 05efb987a33..5159a408bdd 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts @@ -22,7 +22,7 @@ import { } from '../../../../core/cache/models/sort-options.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { DSOSelectorModalWrapperComponent, SelectorActionType, @@ -34,9 +34,9 @@ import { @Component({ selector: 'ds-base-create-collection-parent-selector', - templateUrl: '../dso-selector-modal-wrapper.component.html', + templateUrl: './create-collection-parent-selector.component.html', standalone: true, - imports: [NgIf, DSOSelectorComponent, TranslateModule], + imports: [NgIf, AuthorizedCommunitySelectorComponent, TranslateModule], }) export class CreateCollectionParentSelectorComponent extends DSOSelectorModalWrapperComponent implements OnInit { objectType = DSpaceObjectType.COLLECTION; diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html index a8ec02239d3..1c195e257cd 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html +++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.html @@ -15,6 +15,8 @@ {{'dso-selector.create.community.sub-level' | translate}} - + diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.spec.ts b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.spec.ts index 04922d4deb4..b457419d913 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.spec.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.spec.ts @@ -21,7 +21,7 @@ import { Community } from '../../../../core/shared/community.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils'; import { RouterStub } from '../../../testing/router.stub'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { CreateCommunityParentSelectorComponent } from './create-community-parent-selector.component'; describe('CreateCommunityParentSelectorComponent', () => { @@ -69,7 +69,7 @@ describe('CreateCommunityParentSelectorComponent', () => { schemas: [NO_ERRORS_SCHEMA], }) .overrideComponent(CreateCommunityParentSelectorComponent, { - remove: { imports: [DSOSelectorComponent] }, + remove: { imports: [AuthorizedCommunitySelectorComponent] }, }) .compileComponents(); diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts index dc49fcaa8af..0e950dc562c 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts @@ -29,7 +29,7 @@ import { FeatureID } from '../../../../core/data/feature-authorization/feature-i import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; import { hasValue } from '../../../empty.util'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { DSOSelectorModalWrapperComponent, SelectorActionType, @@ -49,7 +49,7 @@ import { standalone: true, imports: [ AsyncPipe, - DSOSelectorComponent, + AuthorizedCommunitySelectorComponent, NgIf, TranslateModule, ], diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.html b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.html new file mode 100644 index 00000000000..92041b39705 --- /dev/null +++ b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.html @@ -0,0 +1,13 @@ +
+ + +
diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.spec.ts b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.spec.ts index 43b12889254..08280fb85c7 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.spec.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.spec.ts @@ -18,7 +18,7 @@ import { Collection } from '../../../../core/shared/collection.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils'; import { RouterStub } from '../../../testing/router.stub'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCollectionSelectorComponent } from '../../dso-selector/authorized-collection-selector/authorized-collection-selector.component'; import { EditCollectionSelectorComponent } from './edit-collection-selector.component'; describe('EditCollectionSelectorComponent', () => { @@ -64,7 +64,7 @@ describe('EditCollectionSelectorComponent', () => { }) .overrideComponent(EditCollectionSelectorComponent, { remove: { - imports: [DSOSelectorComponent], + imports: [AuthorizedCollectionSelectorComponent], }, }) .compileComponents(); diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts index 611a4f13dec..3972a8053b5 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts @@ -18,7 +18,7 @@ import { } from '../../../../core/cache/models/sort-options.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCollectionSelectorComponent } from '../../dso-selector/authorized-collection-selector/authorized-collection-selector.component'; import { DSOSelectorModalWrapperComponent, SelectorActionType, @@ -31,9 +31,9 @@ import { @Component({ selector: 'ds-base-edit-collection-selector', - templateUrl: '../dso-selector-modal-wrapper.component.html', + templateUrl: './edit-collection-selector.component.html', standalone: true, - imports: [NgIf, DSOSelectorComponent, TranslateModule], + imports: [NgIf, AuthorizedCollectionSelectorComponent, TranslateModule], }) export class EditCollectionSelectorComponent extends DSOSelectorModalWrapperComponent implements OnInit { objectType = DSpaceObjectType.COLLECTION; diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.html b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.html new file mode 100644 index 00000000000..1f8e6ec79f6 --- /dev/null +++ b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.html @@ -0,0 +1,12 @@ +
+ + +
diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.spec.ts b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.spec.ts index cd5c0d1831a..750df1c268f 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.spec.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.spec.ts @@ -18,7 +18,7 @@ import { Community } from '../../../../core/shared/community.model'; import { MetadataValue } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils'; import { RouterStub } from '../../../testing/router.stub'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { EditCommunitySelectorComponent } from './edit-community-selector.component'; describe('EditCommunitySelectorComponent', () => { @@ -64,7 +64,7 @@ describe('EditCommunitySelectorComponent', () => { }) .overrideComponent(EditCommunitySelectorComponent, { remove: { - imports: [DSOSelectorComponent], + imports: [AuthorizedCommunitySelectorComponent], }, }) .compileComponents(); diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts index 3f7ede0de0d..dda75a7d936 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts @@ -18,7 +18,7 @@ import { } from '../../../../core/cache/models/sort-options.model'; import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; import { DSpaceObjectType } from '../../../../core/shared/dspace-object-type.model'; -import { DSOSelectorComponent } from '../../dso-selector/dso-selector.component'; +import { AuthorizedCommunitySelectorComponent } from '../../dso-selector/authorized-community-selector/authorized-community-selector.component'; import { DSOSelectorModalWrapperComponent, SelectorActionType, @@ -31,9 +31,9 @@ import { @Component({ selector: 'ds-base-edit-community-selector', - templateUrl: '../dso-selector-modal-wrapper.component.html', + templateUrl: './edit-community-selector.component.html', standalone: true, - imports: [NgIf, DSOSelectorComponent, TranslateModule], + imports: [NgIf, AuthorizedCommunitySelectorComponent, TranslateModule], }) export class EditCommunitySelectorComponent extends DSOSelectorModalWrapperComponent implements OnInit { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html index 7224f1843dd..e54705bb19a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html @@ -1,4 +1,4 @@ -
@@ -19,8 +19,7 @@ -
+
@@ -78,7 +77,7 @@ -
+
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 4e58759f4e7..ca8924da1ab 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 @@ -14,3 +14,13 @@ -moz-appearance: none; appearance: none; } + +.invalid-feedback { + margin-top: 0; +} + +.col-form-label { + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0.5rem; +} 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 ab50bd19dfc..48a8ebbc0cc 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 @@ -440,6 +440,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo * Unsubscribe from all subscriptions */ ngOnDestroy(): void { + super.ngOnDestroy(); this.subs .filter((sub) => hasValue(sub)) .forEach((sub) => sub.unsubscribe()); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.spec.ts index a54e379cacb..883da2295ab 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.spec.ts @@ -9,12 +9,9 @@ import { } from '@angular/forms'; import { DISABLED_MATCHER_PROVIDER, - DynamicFormControlRelation, DynamicFormRelationService, HIDDEN_MATCHER, HIDDEN_MATCHER_PROVIDER, - MATCH_VISIBLE, - OR_OPERATOR, REQUIRED_MATCHER_PROVIDER, } from '@ng-dynamic-forms/core'; @@ -26,6 +23,7 @@ import { import { FormBuilderService } from '../form-builder.service'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { DsDynamicTypeBindRelationService } from './ds-dynamic-type-bind-relation.service'; +import { getTypeBindRelations } from './type-bind.utils'; describe('DSDynamicTypeBindRelationService test suite', () => { let service: DsDynamicTypeBindRelationService; @@ -85,7 +83,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => { }); it('Should get 1 related form models for mock relation model data', () => { const testModel = mockInputWithTypeBindModel; - testModel.typeBindRelations = getTypeBindRelations(['boundType']); + testModel.typeBindRelations = getTypeBindRelations(['boundType'], 'dc.type'); const relatedModels = service.getRelatedFormModel(testModel); expect(relatedModels).toHaveSize(1); }); @@ -94,7 +92,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => { describe('Test matchesCondition method', () => { it('Should receive one subscription to dc.type type binding"', () => { const testModel = mockInputWithTypeBindModel; - testModel.typeBindRelations = getTypeBindRelations(['boundType']); + testModel.typeBindRelations = getTypeBindRelations(['boundType'], 'dc.type'); const dcTypeControl = new UntypedFormControl(); dcTypeControl.setValue('boundType'); let subscriptions = service.subscribeRelations(testModel, dcTypeControl); @@ -103,7 +101,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => { it('Expect hasMatch to be true (ie. this should be hidden)', () => { const testModel = mockInputWithTypeBindModel; - testModel.typeBindRelations = getTypeBindRelations(['boundType']); + testModel.typeBindRelations = getTypeBindRelations(['boundType'], 'dc.type'); const dcTypeControl = new UntypedFormControl(); dcTypeControl.setValue('boundType'); testModel.typeBindRelations[0].when[0].value = 'anotherType'; @@ -118,7 +116,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => { it('Expect hasMatch to be false (ie. this should NOT be hidden)', () => { const testModel = mockInputWithTypeBindModel; - testModel.typeBindRelations = getTypeBindRelations(['boundType']); + testModel.typeBindRelations = getTypeBindRelations(['boundType'], 'dc.type'); const dcTypeControl = new UntypedFormControl(); dcTypeControl.setValue('boundType'); testModel.typeBindRelations[0].when[0].value = 'boundType'; @@ -134,18 +132,3 @@ describe('DSDynamicTypeBindRelationService test suite', () => { }); }); - -function getTypeBindRelations(configuredTypeBindValues: string[]): DynamicFormControlRelation[] { - const bindValues = []; - configuredTypeBindValues.forEach((value) => { - bindValues.push({ - id: 'dc.type', - value: value, - }); - }); - return [{ - match: MATCH_VISIBLE, - operator: OR_OPERATOR, - when: bindValues, - }]; -} diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts index 03ca4b26cfc..4f8cff747e6 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service.ts @@ -13,7 +13,6 @@ import { DynamicFormControlModel, DynamicFormControlRelation, DynamicFormRelationService, - MATCH_VISIBLE, OR_OPERATOR, } from '@ng-dynamic-forms/core'; import { Subscription } from 'rxjs'; @@ -216,23 +215,4 @@ export class DsDynamicTypeBindRelationService { return subscriptions; } - /** - * Helper function to construct a typeBindRelations array - * @param configuredTypeBindValues - */ - public getTypeBindRelations(configuredTypeBindValues: string[]): DynamicFormControlRelation[] { - const bindValues = []; - configuredTypeBindValues.forEach((value) => { - bindValues.push({ - id: 'dc.type', - value: value, - }); - }); - return [{ - match: MATCH_VISIBLE, - operator: OR_OPERATOR, - when: bindValues, - }]; - } - } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html index 944e4650abd..a71f6fa5a26 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html @@ -1,5 +1,5 @@
- + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.scss index 97698b2102e..c76d9fa95c3 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.scss @@ -4,4 +4,5 @@ legend { font-size: initial; + margin-bottom: 0; } 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 78e50de898d..68a5d5bc84b 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 @@ -45,10 +45,10 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat import { DsDynamicTagComponent } from './dynamic-tag.component'; import { DynamicTagModel } from './dynamic-tag.model'; -function createKeyUpEvent(key: number) { +function createKeyUpEvent(key: string) { /* eslint-disable no-empty,@typescript-eslint/no-empty-function */ const event = { - keyCode: key, preventDefault: () => { + key: key, preventDefault: () => { }, stopPropagation: () => { }, }; @@ -278,8 +278,8 @@ describe('DsDynamicTagComponent test suite', () => { expect(tagComp.chips.getChipsItems()).toEqual(chips.getChipsItems()); }); - it('should add an item on ENTER or key press is \',\' or \';\'', fakeAsync(() => { - let event = createKeyUpEvent(13); + it('should add an item on ENTER or key press is \',\'', fakeAsync(() => { + let event = createKeyUpEvent('Enter'); tagComp.currentValue = 'test value'; tagFixture.detectChanges(); @@ -290,7 +290,7 @@ describe('DsDynamicTagComponent test suite', () => { expect(tagComp.model.value).toEqual(['test value']); expect(tagComp.currentValue).toBeNull(); - event = createKeyUpEvent(188); + event = createKeyUpEvent(','); tagComp.currentValue = 'test value'; tagFixture.detectChanges(); 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 d8f12197d2a..431ca32c375 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 @@ -220,13 +220,15 @@ export class DsDynamicTagComponent extends DsDynamicVocabularyComponent implemen } /** - * Add a new tag with typed text when typing 'Enter' or ',' or ';' + * Add a new tag with typed text when typing 'Enter' or ',' + * Tests the key rather than keyCode as keyCodes can vary + * based on keyboard layout (and do not consider Shift mod) * @param event the keyUp event */ onKeyUp(event) { - if (event.keyCode === 13 || event.keyCode === 188) { + if (event.key === 'Enter' || event.key === ',') { event.preventDefault(); - // Key: 'Enter' or ',' or ';' + // Key: 'Enter' or ',' this.addTagsToChips(); event.stopPropagation(); } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/type-bind.utils.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/type-bind.utils.ts new file mode 100644 index 00000000000..1d09e9fafbe --- /dev/null +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/type-bind.utils.ts @@ -0,0 +1,48 @@ +import { + DynamicFormControlRelation, + MATCH_ENABLED, + MATCH_VISIBLE, + OR_OPERATOR, +} from '@ng-dynamic-forms/core'; + +/** + * Get the type bind values from the REST data for a specific field + * The return value is any[] in the method signature but in reality it's + * returning the 'relation' that'll be used for a dynamic matcher when filtering + * fields in type bind, made up of a 'match' outcome (make this field visible), an 'operator' + * (OR) and a 'when' condition (the bindValues array). + * @param configuredTypeBindValues array of types from the submission definition (CONFIG_DATA) + * @param typeField + * @private + * @return DynamicFormControlRelation[] array with one relation in it, for type bind matching to show a field + */ +export function getTypeBindRelations(configuredTypeBindValues: string[], typeField: string): DynamicFormControlRelation[] { + const bindValues = []; + configuredTypeBindValues.forEach((value) => { + bindValues.push({ + id: typeField, + value: value, + }); + }); + // match: MATCH_VISIBLE means that if true, the field / component will be visible + // operator: OR means that all the values in the 'when' condition will be compared with OR, not AND + // when: the list of values to match against, in this case the list of strings from ... + // Example: Field [x] will be VISIBLE if item type = book OR item type = book_part + // + // The opposing match value will be the dc.type for the workspace item + // + // MATCH_ENABLED is now also returned, so that hidden type-bound fields that are 'required' + // do not trigger false validation errors + return [ + { + match: MATCH_ENABLED, + operator: OR_OPERATOR, + when: bindValues, + }, + { + match: MATCH_VISIBLE, + operator: OR_OPERATOR, + when: bindValues, + }, + ]; +} diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts index 590d5f564e9..1f510fb6e77 100644 --- a/src/app/shared/form/builder/parsers/field-parser.ts +++ b/src/app/shared/form/builder/parsers/field-parser.ts @@ -2,12 +2,7 @@ import { Inject, InjectionToken, } from '@angular/core'; -import { - DynamicFormControlLayout, - DynamicFormControlRelation, - MATCH_VISIBLE, - OR_OPERATOR, -} from '@ng-dynamic-forms/core'; +import { DynamicFormControlLayout } from '@ng-dynamic-forms/core'; import { TranslateService } from '@ngx-translate/core'; import uniqueId from 'lodash/uniqueId'; @@ -28,6 +23,7 @@ import { DynamicRowArrayModel, DynamicRowArrayModelConfig, } from '../ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; +import { getTypeBindRelations } from '../ds-dynamic-form-ui/type-bind.utils'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { RelationshipOptions } from '../models/relationship-options.model'; @@ -98,7 +94,7 @@ export abstract class FieldParser { metadataFields: this.getAllFieldIds(), hasSelectableMetadata: isNotEmpty(this.configData.selectableMetadata), isDraggable, - typeBindRelations: isNotEmpty(this.configData.typeBind) ? this.getTypeBindRelations(this.configData.typeBind, + typeBindRelations: isNotEmpty(this.configData.typeBind) ? getTypeBindRelations(this.configData.typeBind, this.parserOptions.typeField) : null, groupFactory: () => { let model; @@ -327,7 +323,7 @@ export abstract class FieldParser { // If typeBind is configured if (isNotEmpty(this.configData.typeBind)) { - (controlModel as DsDynamicInputModel).typeBindRelations = this.getTypeBindRelations(this.configData.typeBind, + (controlModel as DsDynamicInputModel).typeBindRelations = getTypeBindRelations(this.configData.typeBind, this.parserOptions.typeField); } @@ -356,38 +352,6 @@ export abstract class FieldParser { ); } - /** - * Get the type bind values from the REST data for a specific field - * The return value is any[] in the method signature but in reality it's - * returning the 'relation' that'll be used for a dynamic matcher when filtering - * fields in type bind, made up of a 'match' outcome (make this field visible), an 'operator' - * (OR) and a 'when' condition (the bindValues array). - * @param configuredTypeBindValues array of types from the submission definition (CONFIG_DATA) - * @param typeField - * @private - * @return DynamicFormControlRelation[] array with one relation in it, for type bind matching to show a field - */ - private getTypeBindRelations(configuredTypeBindValues: string[], typeField: string): DynamicFormControlRelation[] { - const bindValues = []; - configuredTypeBindValues.forEach((value) => { - bindValues.push({ - id: typeField, - value: value, - }); - }); - // match: MATCH_VISIBLE means that if true, the field / component will be visible - // operator: OR means that all the values in the 'when' condition will be compared with OR, not AND - // when: the list of values to match against, in this case the list of strings from ... - // Example: Field [x] will be VISIBLE if item type = book OR item type = book_part - // - // The opposing match value will be the dc.type for the workspace item - return [{ - match: MATCH_VISIBLE, - operator: OR_OPERATOR, - when: bindValues, - }]; - } - protected hasRegex() { return hasValue(this.configData.input.regex); } diff --git a/src/app/shared/mocks/item.mock.ts b/src/app/shared/mocks/item.mock.ts index 7f723bfd61a..c8a8c19ede4 100644 --- a/src/app/shared/mocks/item.mock.ts +++ b/src/app/shared/mocks/item.mock.ts @@ -293,4 +293,55 @@ export const ItemMock: Item = Object.assign(new Item(), { }, ), }); + +export const NonDiscoverableItemMock: Item = Object.assign(new Item(), { + handle: '10673/7', + lastModified: '2017-04-24T19:44:08.178+0000', + isArchived: true, + isDiscoverable: false, + isWithdrawn: false, + bundles: createSuccessfulRemoteDataObject$(createPaginatedList([ + MockOriginalBundle, + ])), + _links:{ + self: { + href: 'https://dspace7.4science.it/dspace-spring-rest/api/core/items/0ec7ff22-f211-40ab-a69e-c819b0b1f358', + }, + }, + id: '0ec7ff22-f211-40ab-a69e-c819b0b1f358', + uuid: '0ec7ff22-f211-40ab-a69e-c819b0b1f358', + type: 'item', + metadata: { + 'dc.date.accessioned': [ + { + language: null, + value: '1650-06-26T19:58:25Z', + }, + ], + 'dc.date.available': [ + { + language: null, + value: '1650-06-26T19:58:25Z', + }, + ], + 'dc.date.issued': [ + { + language: null, + value: '1650-06-26', + }, + ], + 'dc.identifier.uri': [ + { + language: null, + value: 'http://dspace7.4science.it/xmlui/handle/10673/7', + }, + ], + 'dc.title': [ + { + language: 'en_US', + value: 'Test Non-Discoverable', + }, + ], + }, +}); /* eslint-enable @typescript-eslint/no-shadow */ diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts index 5bcda378375..7366bca9dba 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts @@ -49,6 +49,11 @@ export class ItemDetailPreviewFieldComponent { */ @Input() metadata: string | string[]; + /** + * Escape HTML in the metadata value + */ + @Input() escapeMetadataHTML: boolean; + /** * The placeholder if there are no value to show */ @@ -66,6 +71,6 @@ export class ItemDetailPreviewFieldComponent { * @returns {string[]} the matching string values or an empty array. */ allMetadataValues(keyOrKeys: string | string[]): string[] { - return Metadata.allValues([this.object.hitHighlights, this.item.metadata], keyOrKeys); + return Metadata.allValues(this.item.metadata, keyOrKeys, this.object.hitHighlights, undefined, this.escapeMetadataHTML); } } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/themed-item-detail-preview-field.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/themed-item-detail-preview-field.component.ts index ebb283728a4..93c1665cfe3 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/themed-item-detail-preview-field.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/themed-item-detail-preview-field.component.ts @@ -24,6 +24,7 @@ export class ThemedItemDetailPreviewFieldComponent extends ThemedComponent , K ext * Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute * @returns {string[]} the matching string values or an empty array. */ - allMetadataValues(keyOrKeys: string | string[]): string[] { - return Metadata.allValues([this.object.hitHighlights, this.dso.metadata], keyOrKeys); + allMetadataValues(keyOrKeys: string | string[], escapeHTML = true): string[] { + return Metadata.allValues(this.dso.metadata, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); } /** * Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute * @returns {string} the first matching string value, or `undefined`. */ - firstMetadataValue(keyOrKeys: string | string[]): string { - return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); + firstMetadataValue(keyOrKeys: string | string[], escapeHTML = true): string { + return Metadata.firstValue(this.dso.metadata, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); } } diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html index 464f8fec909..57e37ae8ceb 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html @@ -29,9 +29,9 @@

- +

- +

diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts index d5c8ea42e89..7b5461e7ca6 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts @@ -28,6 +28,7 @@ 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 { MetadataValue } from '../../../../../core/shared/metadata.models'; import { PageInfo } from '../../../../../core/shared/page-info.model'; import { UUIDService } from '../../../../../core/shared/uuid.service'; import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; @@ -43,20 +44,21 @@ import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { ItemSearchResultGridElementComponent } from './item-search-result-grid-element.component'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; const dcTitle = 'This is just another title'; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { - hitHighlights: { - 'dc.title': [{ +mockItemWithMetadata.hitHighlights = { + 'dc.title': [ + Object.assign(new MetadataValue(), { value: dcTitle, - }], - }, + }), + ], +}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ { language: 'en_US', - value: dcTitle, + value: 'This is just another title', }, ], 'dc.contributor.author': [ diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts index a0c8ec84cef..cd9a09b40a1 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts @@ -57,6 +57,6 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen ngOnInit(): void { super.ngOnInit(); this.itemPageRoute = getItemPageRoute(this.dso); - this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso); + this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso, true); } } 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 e8b999fb9fc..7824e759f82 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 @@ -51,20 +51,22 @@ export class SearchResultGridElementComponent, K exten * Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute * @returns {string[]} the matching string values or an empty array. */ - allMetadataValues(keyOrKeys: string | string[]): string[] { - return Metadata.allValues([this.object.hitHighlights, this.dso.metadata], keyOrKeys); + allMetadataValues(keyOrKeys: string | string[], escapeHTML = true): string[] { + return Metadata.allValues(this.dso.metadata, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); } /** * Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute * @returns {string} the first matching string value, or `undefined`. */ - firstMetadataValue(keyOrKeys: string | string[]): string { - return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); + firstMetadataValue(keyOrKeys: string | string[], escapeHTML = true): string { + return Metadata.firstValue(this.dso.metadata, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); } private isCollapsed(): Observable { diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html index 035a7ff9f59..b0c16f1f1d9 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.html @@ -14,16 +14,16 @@

( + [innerHTML]="item.firstMetadataValue('dc.publisher', undefined, true) + ', '"> ) + [innerHTML]="item.firstMetadataValue('dc.date.issued', undefined, true) || ('mydspace.results.no-date' | translate)">) {{'mydspace.results.no-authors' | translate}} + *ngFor="let author of item.allMetadataValues(['dc.contributor.author', 'dc.creator', 'dc.contributor.*'], undefined, true); let last=last;"> ; @@ -33,8 +33,8 @@

- +

diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts index 583b857063b..8398acdbcb9 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts @@ -94,7 +94,7 @@ export class ItemListPreviewComponent implements OnInit { ngOnInit(): void { this.showThumbnails = this.appConfig.browseBy.showThumbnails; - this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item); + this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item, true); } diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html index 20e11953030..b8318b1b15f 100644 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.html @@ -23,22 +23,22 @@ [innerHTML]="dsoTitle"> - - ( - , - ) + + ( + , + ) - - + + ; -
+
+ [innerHTML]="abstract">
diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index c4251c3597f..d45eea80827 100644 --- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts @@ -41,7 +41,7 @@ export class SearchResultListElementComponent, K exten ngOnInit(): void { if (hasValue(this.object)) { this.dso = this.object.indexableObject; - this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso); + this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso, true); } } @@ -49,11 +49,13 @@ export class SearchResultListElementComponent, K exten * Gets all matching metadata string values from hitHighlights or dso metadata. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute. Defaults to `true` because we + * always use `[innerHTML]` in the templates to render metadata due to the hit highlights. * @returns {string[]} the matching string values or an empty array. */ - allMetadataValues(keyOrKeys: string | string[]): string[] { - const dsoMetadata: string[] = Metadata.allValues([this.dso.metadata], keyOrKeys); - const highlights: string[] = Metadata.allValues([this.object.hitHighlights], keyOrKeys); + allMetadataValues(keyOrKeys: string | string[], escapeHTML = true): string[] { + const dsoMetadata: string[] = Metadata.allValues(this.dso.metadata, keyOrKeys, undefined, undefined, escapeHTML); + const highlights: string[] = Metadata.allValues({}, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); const removedHighlights: string[] = highlights.map(str => str.replace(/<\/?em>/g, '')); for (let i = 0; i < removedHighlights.length; i++) { const index = dsoMetadata.indexOf(removedHighlights[i]); @@ -68,10 +70,12 @@ export class SearchResultListElementComponent, K exten * Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. + * @param escapeHTML Whether the HTML is used inside a `[innerHTML]` attribute. Defaults to `true` because we + * always use `[innerHTML]` in the templates to render metadata due to the hit highlights. * @returns {string} the first matching string value, or `undefined`. */ - firstMetadataValue(keyOrKeys: string | string[]): string { - return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); + firstMetadataValue(keyOrKeys: string | string[], escapeHTML = true): string { + return Metadata.firstValue(this.dso.metadata, keyOrKeys, this.object.hitHighlights, undefined, escapeHTML); } /** diff --git a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts index e65883cd3ec..882cc6df83c 100644 --- a/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts +++ b/src/app/shared/object-list/sidebar-search-list-element/sidebar-search-list-element.component.ts @@ -87,7 +87,7 @@ export class SidebarSearchListElementComponent, K exte getParentTitle(): Observable { return this.getParent().pipe( map((parentRD: RemoteData) => { - return hasValue(parentRD) && hasValue(parentRD.payload) ? this.dsoNameService.getName(parentRD.payload) : undefined; + return hasValue(parentRD) && hasValue(parentRD.payload) ? this.dsoNameService.getName(parentRD.payload, true) : undefined; }), ); } diff --git a/src/app/shared/object-select/collection-select/collection-select.component.html b/src/app/shared/object-select/collection-select/collection-select.component.html index 03491e74912..a2f2176986a 100644 --- a/src/app/shared/object-select/collection-select/collection-select.component.html +++ b/src/app/shared/object-select/collection-select/collection-select.component.html @@ -36,7 +36,7 @@ [ngClass]="{'btn-danger': dangerConfirm, 'btn-primary': !dangerConfirm}" [dsBtnDisabled]="selectedIds?.length === 0" (click)="confirmSelected()"> - {{confirmButton | translate}} + {{confirmButton | translate}}
diff --git a/src/app/shared/resource-policies/form/resource-policy-form.model.ts b/src/app/shared/resource-policies/form/resource-policy-form.model.ts index 98ecd678278..2920830b2c2 100644 --- a/src/app/shared/resource-policies/form/resource-policy-form.model.ts +++ b/src/app/shared/resource-policies/form/resource-policy-form.model.ts @@ -39,6 +39,10 @@ const policyActionList: DynamicFormOptionConfig[] = [ label: ActionType.WRITE.toString(), value: ActionType.WRITE, }, + { + label: ActionType.ADD.toString(), + value: ActionType.ADD, + }, { label: ActionType.REMOVE.toString(), value: ActionType.REMOVE, diff --git a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html index c97af4bc250..1c60c59bcd5 100644 --- a/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html +++ b/src/app/shared/search/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html @@ -2,7 +2,8 @@ [tabIndex]="-1" [routerLink]="[searchLink]" [queryParams]="addQueryParams$ | async" - (click)="announceFilter(); filterService.minimizeAll()"> + (click)="announceFilter(); filterService.minimizeAll()" + rel="nofollow">