diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
index c79d19e267c..52df841d3b6 100644
--- a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
+++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html
@@ -32,6 +32,18 @@
+
+
-
+
@@ -23,6 +23,17 @@
+
+
+
+
+ {{value}}
+
+
+
{{value}}
diff --git a/src/app/item-page/field-components/metadata-values/metadata-values.component.ts b/src/app/item-page/field-components/metadata-values/metadata-values.component.ts
index cbbae9006da..29c20c6e2ac 100644
--- a/src/app/item-page/field-components/metadata-values/metadata-values.component.ts
+++ b/src/app/item-page/field-components/metadata-values/metadata-values.component.ts
@@ -4,6 +4,7 @@ import { APP_CONFIG, AppConfig } from '../../../../config/app-config.interface';
import { BrowseDefinition } from '../../../core/shared/browse-definition.model';
import { hasValue } from '../../../shared/empty.util';
import { VALUE_LIST_BROWSE_DEFINITION } from '../../../core/shared/value-list-browse-definition.resource-type';
+import { ImageField } from '../../simple/field-components/specific-field/item-page-field.component';
/**
* This component renders the configured 'values' into the ds-metadata-field-wrapper component.
@@ -55,6 +56,11 @@ export class MetadataValuesComponent implements OnChanges {
@Input() browseDefinition?: BrowseDefinition;
+ /**
+ * Optional {@code ImageField} reference that represents an image to be displayed inline.
+ */
+ @Input() img?: ImageField;
+
ngOnChanges(changes: SimpleChanges): void {
this.renderMarkdown = !!this.appConfig.markdown.enabled && this.enableMarkdown;
}
diff --git a/src/app/item-page/item-shared.module.ts b/src/app/item-page/item-shared.module.ts
index 9c2bbba6194..8b7243acde0 100644
--- a/src/app/item-page/item-shared.module.ts
+++ b/src/app/item-page/item-shared.module.ts
@@ -1,21 +1,36 @@
-import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component';
+import {
+ RelatedEntitiesSearchComponent
+} from './simple/related-entities/related-entities-search/related-entities-search.component';
import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
+import { CommonModule, NgOptimizedImage } from '@angular/common';
import { SearchModule } from '../shared/search/search.module';
import { SharedModule } from '../shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { DYNAMIC_FORM_CONTROL_MAP_FN } from '@ng-dynamic-forms/core';
-import { dsDynamicFormControlMapFn } from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
-import { TabbedRelatedEntitiesSearchComponent } from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component';
-import { ItemVersionsDeleteModalComponent } from './versions/item-versions-delete-modal/item-versions-delete-modal.component';
-import { ItemVersionsSummaryModalComponent } from './versions/item-versions-summary-modal/item-versions-summary-modal.component';
+import {
+ dsDynamicFormControlMapFn
+} from '../shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component';
+import {
+ TabbedRelatedEntitiesSearchComponent
+} from './simple/related-entities/tabbed-related-entities-search/tabbed-related-entities-search.component';
+import {
+ ItemVersionsDeleteModalComponent
+} from './versions/item-versions-delete-modal/item-versions-delete-modal.component';
+import {
+ ItemVersionsSummaryModalComponent
+} from './versions/item-versions-summary-modal/item-versions-summary-modal.component';
import { MetadataValuesComponent } from './field-components/metadata-values/metadata-values.component';
-import { GenericItemPageFieldComponent } from './simple/field-components/specific-field/generic/generic-item-page-field.component';
-import { MetadataRepresentationListComponent } from './simple/metadata-representation-list/metadata-representation-list.component';
+import {
+ GenericItemPageFieldComponent
+} from './simple/field-components/specific-field/generic/generic-item-page-field.component';
+import {
+ MetadataRepresentationListComponent
+} from './simple/metadata-representation-list/metadata-representation-list.component';
import { RelatedItemsComponent } from './simple/related-items/related-items-component';
import {
ThemedMetadataRepresentationListComponent
} from './simple/metadata-representation-list/themed-metadata-representation-list.component';
+import { ItemPageImgFieldComponent } from './simple/field-components/specific-field/img/item-page-img-field.component';
const ENTRY_COMPONENTS = [
ItemVersionsDeleteModalComponent,
@@ -32,6 +47,7 @@ const COMPONENTS = [
MetadataRepresentationListComponent,
ThemedMetadataRepresentationListComponent,
RelatedItemsComponent,
+ ItemPageImgFieldComponent,
];
@NgModule({
@@ -42,7 +58,8 @@ const COMPONENTS = [
CommonModule,
SearchModule,
SharedModule,
- TranslateModule
+ TranslateModule,
+ NgOptimizedImage
],
exports: [
...COMPONENTS
diff --git a/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.spec.ts b/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.spec.ts
new file mode 100644
index 00000000000..b96daa47ad6
--- /dev/null
+++ b/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.spec.ts
@@ -0,0 +1,85 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ItemPageImgFieldComponent } from './item-page-img-field.component';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { TranslateLoaderMock } from '../../../../../shared/testing/translate-loader.mock';
+import { APP_CONFIG } from '../../../../../../config/app-config.interface';
+import { environment } from '../../../../../../environments/environment';
+import { BrowseDefinitionDataService } from '../../../../../core/browse/browse-definition-data.service';
+import { BrowseDefinitionDataServiceStub } from '../../../../../shared/testing/browse-definition-data-service.stub';
+import { GenericItemPageFieldComponent } from '../generic/generic-item-page-field.component';
+import { MetadataValuesComponent } from '../../../../field-components/metadata-values/metadata-values.component';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { mockItemWithMetadataFieldsAndValue } from '../item-page-field.component.spec';
+import { By } from '@angular/platform-browser';
+import { ImageField } from '../item-page-field.component';
+
+let component: ItemPageImgFieldComponent;
+let fixture: ComponentFixture;
+
+const mockField = 'organization.identifier.ror';
+const mockValue = 'http://ror.org/awesome-identifier';
+const mockLabel = 'ROR label';
+const mockUrlRegex = '(.*)ror.org';
+const mockImg = {
+ URI: './assets/images/ror-icon.svg',
+ alt: 'item.page.image.alt.ROR',
+ heightVar: '--ds-item-page-img-field-ror-inline-height'
+} as ImageField;
+
+describe('ItemPageImgFieldComponent', () => {
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: TranslateLoaderMock
+ }
+ })],
+ providers: [
+ { provide: APP_CONFIG, useValue: environment },
+ { provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub }
+ ],
+ declarations: [ItemPageImgFieldComponent, GenericItemPageFieldComponent, MetadataValuesComponent],
+ schemas: [NO_ERRORS_SCHEMA]
+ })
+ .overrideComponent(GenericItemPageFieldComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ItemPageImgFieldComponent);
+ component = fixture.componentInstance;
+ component.item = mockItemWithMetadataFieldsAndValue([mockField], mockValue);
+ component.fields = [mockField];
+ component.label = mockLabel;
+ component.urlRegex = mockUrlRegex;
+ component.img = mockImg;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should display display img tag', () => {
+ const image = fixture.debugElement.query(By.css('img.link-logo'));
+ expect(image).not.toBeNull();
+ });
+
+ it('should have right attributes', () => {
+ const image = fixture.debugElement.query(By.css('img.link-logo'));
+ expect(image.attributes.src).toEqual(mockImg.URI);
+ expect(image.attributes.alt).toEqual(mockImg.alt);
+
+ const imageEl = image.nativeElement;
+ expect(imageEl.style.height).toContain(mockImg.heightVar);
+ });
+
+ it('should have the right value', () => {
+ const imageAnchor = fixture.debugElement.query(By.css('a.link-anchor'));
+ const anchorEl = imageAnchor.nativeElement;
+ expect(anchorEl.innerHTML).toContain(mockValue);
+ });
+});
diff --git a/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.ts b/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.ts
new file mode 100644
index 00000000000..d442323b53b
--- /dev/null
+++ b/src/app/item-page/simple/field-components/specific-field/img/item-page-img-field.component.ts
@@ -0,0 +1,46 @@
+import { Component, Input } from '@angular/core';
+import { ImageField, ItemPageFieldComponent } from '../item-page-field.component';
+import { Item } from '../../../../../core/shared/item.model';
+
+@Component({
+ selector: 'ds-item-page-img-field',
+ templateUrl: '../item-page-field.component.html'
+})
+/**
+ * Component that renders an inline image for a given field.
+ * This component uses a given {@code ImageField} configuration to correctly render the img.
+ */
+export class ItemPageImgFieldComponent extends ItemPageFieldComponent {
+
+ /**
+ * The item to display metadata for
+ */
+ @Input() item: Item;
+
+ /**
+ * Separator string between multiple values of the metadata fields defined
+ * @type {string}
+ */
+ @Input() separator: string;
+
+ /**
+ * Fields (schema.element.qualifier) used to render their values.
+ */
+ @Input() fields: string[];
+
+ /**
+ * Label i18n key for the rendered metadata
+ */
+ @Input() label: string;
+
+ /**
+ * Image Configuration
+ */
+ @Input() img: ImageField;
+
+ /**
+ * Whether any valid HTTP(S) URL should be rendered as a link
+ */
+ @Input() urlRegex?: string;
+
+}
diff --git a/src/app/item-page/simple/field-components/specific-field/item-page-field.component.html b/src/app/item-page/simple/field-components/specific-field/item-page-field.component.html
index 91d40b0ad70..f45d4657a46 100644
--- a/src/app/item-page/simple/field-components/specific-field/item-page-field.component.html
+++ b/src/app/item-page/simple/field-components/specific-field/item-page-field.component.html
@@ -6,5 +6,6 @@
[enableMarkdown]="enableMarkdown"
[urlRegex]="urlRegex"
[browseDefinition]="browseDefinition|async"
+ [img]="img"
>
diff --git a/src/app/item-page/simple/field-components/specific-field/item-page-field.component.ts b/src/app/item-page/simple/field-components/specific-field/item-page-field.component.ts
index fc526dabcc5..57f49e36476 100644
--- a/src/app/item-page/simple/field-components/specific-field/item-page-field.component.ts
+++ b/src/app/item-page/simple/field-components/specific-field/item-page-field.component.ts
@@ -6,6 +6,25 @@ import { BrowseDefinition } from '../../../../core/shared/browse-definition.mode
import { BrowseDefinitionDataService } from '../../../../core/browse/browse-definition-data.service';
import { getRemoteDataPayload } from '../../../../core/shared/operators';
+/**
+ * Interface that encapsulate Image configuration for this component.
+ */
+export interface ImageField {
+ /**
+ * URI that is used to retrieve the image.
+ */
+ URI: string;
+ /**
+ * i18n Key that represents the alt text to display
+ */
+ alt: string;
+ /**
+ * CSS variable that contains the height of the inline image.
+ */
+ heightVar: string;
+}
+
+
/**
* This component can be used to represent metadata on a simple item page.
* It expects one input parameter of type Item to which the metadata belongs.
@@ -51,6 +70,11 @@ export class ItemPageFieldComponent {
*/
urlRegex?: string;
+ /**
+ * Image Configuration
+ */
+ img: ImageField;
+
/**
* Return browse definition that matches any field used in this component if it is configured as a browse
* link in dspace.cfg (webui.browse.link.)
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index 3747e0837aa..efa5ee55a3b 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -2510,6 +2510,8 @@
"item.page.claim.tooltip": "Claim this item as profile",
+ "item.page.image.alt.ROR": "ROR logo",
+
"item.preview.dc.identifier.uri": "Identifier:",
"item.preview.dc.contributor.author": "Authors:",
@@ -2562,6 +2564,20 @@
"item.preview.oaire.fundingStream": "Funding Stream:",
+ "item.preview.oairecerif.identifier.url": "URL",
+
+ "item.preview.organization.address.addressCountry": "Country",
+
+ "item.preview.organization.foundingDate": "Founding Date",
+
+ "item.preview.organization.identifier.crossrefid": "CrossRef ID",
+
+ "item.preview.organization.identifier.isni": "ISNI",
+
+ "item.preview.organization.identifier.ror": "ROR ID",
+
+ "item.preview.organization.legalName": "Legal Name",
+
"item.select.confirm": "Confirm selected",
"item.select.empty": "No items to show",
@@ -3308,6 +3324,8 @@
"orgunit.page.titleprefix": "Organizational Unit: ",
+ "orgunit.page.ror": "ROR Identifier",
+
"pagination.options.description": "Pagination options",
"pagination.results-per-page": "Results Per Page",
@@ -4276,6 +4294,8 @@
"submission.import-external.source.lcname": "Library of Congress Names",
+ "submission.import-external.source.ror": "Research Organization Registry (ROR)",
+
"submission.import-external.preview.title": "Item Preview",
"submission.import-external.preview.title.Publication": "Publication Preview",
@@ -4368,6 +4388,8 @@
"submission.sections.describe.relationship-lookup.external-source.import-modal.head.arxiv": "Importing from arXiv",
+ "submission.sections.describe.relationship-lookup.external-source.import-modal.head.ror": "Import from ROR",
+
"submission.sections.describe.relationship-lookup.external-source.import-modal.import": "Import",
"submission.sections.describe.relationship-lookup.external-source.import-modal.Journal.title": "Import Remote Journal",
@@ -4390,6 +4412,12 @@
"submission.sections.describe.relationship-lookup.external-source.import-modal.select": "Select a local match:",
+ "submission.sections.describe.relationship-lookup.external-source.import-modal.isOrgUnitOfProject.title": "Import Remote Organization",
+
+ "submission.sections.describe.relationship-lookup.external-source.import-modal.isOrgUnitOfProject.added.local-entity": "Successfully added local organization to the selection",
+
+ "submission.sections.describe.relationship-lookup.external-source.import-modal.isOrgUnitOfProject.added.new-entity": "Successfully imported and added external organization to the selection",
+
"submission.sections.describe.relationship-lookup.search-tab.deselect-all": "Deselect all",
"submission.sections.describe.relationship-lookup.search-tab.deselect-page": "Deselect page",
@@ -4446,6 +4474,8 @@
"submission.sections.describe.relationship-lookup.search-tab.tab-title.arxiv": "arXiv ({{ count }})",
+ "submission.sections.describe.relationship-lookup.search-tab.tab-title.ror": "ROR ({{ count }})",
+
"submission.sections.describe.relationship-lookup.search-tab.tab-title.orcidWorks": "ORCID ({{ count }})",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.crossref": "CrossRef ({{ count }})",
@@ -4470,6 +4500,8 @@
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author",
+ "submission.sections.describe.relationship-lookup.search-tab.tab-title.isOrgUnitOfProject": "OrgUnit of the Project",
+
"submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Funding OpenAIRE API",
"submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Project",
@@ -4518,6 +4550,8 @@
"submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication",
+ "submission.sections.describe.relationship-lookup.title.isOrgUnitOfProject": "OrgUnit",
+
"submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown",
"submission.sections.describe.relationship-lookup.selection-tab.settings": "Settings",
@@ -4580,6 +4614,8 @@
"submission.sections.describe.relationship-lookup.selection-tab.title.wos": "Search Results",
+ "submission.sections.describe.relationship-lookup.selection-tab.title.ror": "Search Results",
+
"submission.sections.describe.relationship-lookup.selection-tab.title": "Search Results",
"submission.sections.describe.relationship-lookup.name-variant.notification.content": "Would you like to save \"{{ value }}\" as a name variant for this person so you and others can reuse it for future submissions? If you don't you can still use it for this submission.",
@@ -5052,6 +5088,8 @@
"supervision.search.results.head": "Workflow and Workspace tasks",
+ "orgunit.search.results.head": "Organizational Unit Search Results",
+
"workflow-item.edit.breadcrumbs": "Edit workflowitem",
"workflow-item.edit.title": "Edit workflowitem",
diff --git a/src/assets/images/ror-icon.svg b/src/assets/images/ror-icon.svg
new file mode 100644
index 00000000000..24735df519b
--- /dev/null
+++ b/src/assets/images/ror-icon.svg
@@ -0,0 +1,16 @@
+
+
+
diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss
index 0e54ec200cd..48f567b61bc 100644
--- a/src/styles/_custom_variables.scss
+++ b/src/styles/_custom_variables.scss
@@ -105,4 +105,7 @@
--ds-comcol-logo-max-width: 500px;
--ds-comcol-logo-max-height: 500px;
+
+ --ds-item-page-img-field-default-inline-height: 24px;
+
}
diff --git a/src/themes/dspace/styles/_theme_css_variable_overrides.scss b/src/themes/dspace/styles/_theme_css_variable_overrides.scss
index 516eff9f7e9..8512514a405 100644
--- a/src/themes/dspace/styles/_theme_css_variable_overrides.scss
+++ b/src/themes/dspace/styles/_theme_css_variable_overrides.scss
@@ -7,5 +7,7 @@
--ds-home-news-link-color: #{$green};
--ds-home-news-link-hover-color: #{darken($green, 15%)};
--ds-header-navbar-border-bottom-color: #{$green};
+ --ds-item-page-img-field-default-inline-height: 24px;
+ --ds-item-page-img-field-ror-inline-height: var(--ds-item-page-img-field-default-inline-height);
}