From c5eb935ea4cfde914ddc622641d08c8b7c68ea86 Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Wed, 27 Oct 2021 09:44:11 +0200 Subject: [PATCH 1/7] [DSC-213] show graph facets in explore section of research outputs --- .../facet-section.component.html | 20 ++++--- .../facet-section.component.spec.ts | 59 ++++++++++++++++++- .../facet-section/facet-section.component.ts | 21 +++++-- src/assets/i18n/en.json5 | 4 ++ 4 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/app/shared/explore/section-component/facet-section/facet-section.component.html b/src/app/shared/explore/section-component/facet-section/facet-section.component.html index 5a09a826658..1c129ab22ff 100644 --- a/src/app/shared/explore/section-component/facet-section/facet-section.component.html +++ b/src/app/shared/explore/section-component/facet-section/facet-section.component.html @@ -1,15 +1,21 @@

{{ 'explore.facet-section.title' | translate }}

-
+
{{'explore.index.' + facet.name | translate}} -
- - {{facetValue.label}} - - {{facetValue.count}} +
+
+ +
+ + {{facetValue.label}} + + {{facetValue.count}} +
+
+
diff --git a/src/app/shared/explore/section-component/facet-section/facet-section.component.spec.ts b/src/app/shared/explore/section-component/facet-section/facet-section.component.spec.ts index 1b62e0bcf7a..d86b54b9ba5 100644 --- a/src/app/shared/explore/section-component/facet-section/facet-section.component.spec.ts +++ b/src/app/shared/explore/section-component/facet-section/facet-section.component.spec.ts @@ -15,6 +15,12 @@ import { FacetValue } from '../../../search/facet-value.model'; import { FilterType } from '../../../search/filter-type.model'; import { SearchFilterConfig } from '../../../search/search-filter-config.model'; import { FacetSectionComponent } from './facet-section.component'; +import {SEARCH_CONFIG_SERVICE} from '../../../../my-dspace-page/my-dspace-page.component'; +import {SearchConfigurationServiceStub} from '../../../testing/search-configuration-service.stub'; +import {StoreModule} from '@ngrx/store'; +import {authReducer} from '../../../../core/auth/auth.reducer'; +import {storeModuleConfig} from '../../../../app.reducer'; +import {isNotNull} from '../../../empty.util'; describe('FacetSectionComponent', () => { let component: FacetSectionComponent; @@ -75,12 +81,43 @@ describe('FacetSectionComponent', () => { values: [dateIssuedValue] } }); - + const barChartFacetValue: FacetValue = { + label: '2007', + value: '2007', + count: 13, + _links: { + self: { href: 'fa-selectedValue-self-link' }, + search: { href: '' } + } + }; + const mockGraphBarChartFilterConfig = Object.assign(new SearchFilterConfig(), { + name: 'dateIssued', + filterType: FilterType['chart.bar'], + _embedded: { + values: [barChartFacetValue] + } + }); + const pieChartFacetValue: FacetValue = { + label: 'Other', + value: 'Other', + count: 13, + _links: { + self: { href: 'fa-selectedValue-self-link' }, + search: { href: '' } + } + }; + const mockGraphPieChartFilterConfig = Object.assign(new SearchFilterConfig(), { + name: 'dateIssued', + filterType: FilterType['chart.pie'], + _embedded: { + values: [pieChartFacetValue] + } + }); beforeEach(async(() => { searchServiceStub = { searchFacets(scope?: string, configurationName?: string): Observable> { - return createSuccessfulRemoteDataObject$([mockAuthorFilterConfig, mockSubjectFilterConfig, mockDateIssuedFilterConfig]); + return createSuccessfulRemoteDataObject$([mockAuthorFilterConfig, mockSubjectFilterConfig, mockDateIssuedFilterConfig, mockGraphBarChartFilterConfig, mockGraphPieChartFilterConfig]); }, getSearchLink(): string { return '/search'; @@ -89,6 +126,7 @@ describe('FacetSectionComponent', () => { TestBed.configureTestingModule({ imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule, RouterTestingModule, + StoreModule.forRoot({ auth: authReducer }, storeModuleConfig), TranslateModule.forRoot({ loader: { provide: TranslateLoader, @@ -98,7 +136,8 @@ describe('FacetSectionComponent', () => { ], declarations: [FacetSectionComponent], providers: [FacetSectionComponent, - { provide: SearchService, useValue: searchServiceStub }], + { provide: SearchService, useValue: searchServiceStub }, + { provide: SEARCH_CONFIG_SERVICE, useValue: new SearchConfigurationServiceStub() }], schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); @@ -124,6 +163,20 @@ describe('FacetSectionComponent', () => { })); it('should create a facet section foreach not empty filter configs', () => { + // graph facets control + const graphFacets = fixture.debugElement.queryAll(By.css('.col-6.mb-4')); + expect(graphFacets.length).toEqual(2); + const barChartFacet = graphFacets[0]; + expect(barChartFacet.name).toEqual('div'); + expect(barChartFacet.children.length).toEqual(2); + const barChartComponent = barChartFacet.query(By.css('ds-search-chart')); + expect(isNotNull(barChartComponent)).toBe(true); + const pieChartFacet = graphFacets[1]; + expect(pieChartFacet.children.length).toEqual(2); + expect(pieChartFacet.name).toEqual('div'); + const pieChartComponent = pieChartFacet.query(By.css('ds-search-chart')); + expect(isNotNull(pieChartComponent)).toBe(true); + const facets = fixture.debugElement.queryAll(By.css('.col-3.mb-4')); expect(facets.length).toEqual(2); diff --git a/src/app/shared/explore/section-component/facet-section/facet-section.component.ts b/src/app/shared/explore/section-component/facet-section/facet-section.component.ts index 31c19981ff8..369ca9bde6e 100644 --- a/src/app/shared/explore/section-component/facet-section/facet-section.component.ts +++ b/src/app/shared/explore/section-component/facet-section/facet-section.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import {Component, Inject, Input, OnInit} from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { FacetSection } from '../../../../core/layout/models/section.model'; import { getFirstSucceededRemoteDataPayload } from '../../../../core/shared/operators'; @@ -7,13 +7,21 @@ import { SearchFilterConfig } from '../../../search/search-filter-config.model'; import { FilterType } from '../../../search/filter-type.model'; import { FacetValue } from '../../../search/facet-value.model'; import { getFacetValueForTypeAndLabel } from '../../../search/search.utils'; +import {SEARCH_CONFIG_SERVICE} from '../../../../my-dspace-page/my-dspace-page.component'; +import {SearchConfigurationService} from '../../../../core/shared/search/search-configuration.service'; /** * Component representing the Facet component section. */ @Component({ selector: 'ds-facet-section', - templateUrl: './facet-section.component.html' + templateUrl: './facet-section.component.html', + providers: [ + { + provide: SEARCH_CONFIG_SERVICE, + useClass: SearchConfigurationService + } + ] }) export class FacetSectionComponent implements OnInit { @@ -28,7 +36,9 @@ export class FacetSectionComponent implements OnInit { facets: SearchFilterConfig[] = []; facets$ = new BehaviorSubject(this.facets); - constructor(public searchService: SearchService) { + constructor(public searchService: SearchService, + @Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService, + ) { } @@ -75,7 +85,10 @@ export class FacetSectionComponent implements OnInit { return filterType === FilterType.range && value.split('-').length === 2; } - getFacetsBoxCol() { + getFacetsBoxCol(facet) { + if (facet.filterType.includes('chart')) { + return 6; + } const facetsPerRow = this.facetSection.facetsPerRow ? this.facetSection.facetsPerRow : 4; return 12 / facetsPerRow; } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 705e65adda4..feca3de226f 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1566,6 +1566,10 @@ "explore.index.author" : "Author", + "explore.index.graphitemtype" : "Graph by type", + + "explore.index.graphpubldate" : "Graph by date", + "explore.index.birthDate" : "Birthday", "explore.index.metric.view" : "Most viewed", From e4a8331e2c342b3d3011acb6e7e41d1dcb5e347a Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Mon, 1 Nov 2021 18:15:20 +0100 Subject: [PATCH 2/7] [DSC-134] angular implementation for plumX widget + unit testing --- .../metric-loader/metric-loader.service.ts | 17 +++++ .../metric-plumx/metric-plumx.component.html | 4 ++ .../metric-plumx/metric-plumx.component.scss | 0 .../metric-plumx.component.spec.ts | 64 +++++++++++++++++++ .../metric-plumx/metric-plumx.component.ts | 32 ++++++++++ src/app/shared/shared.module.ts | 2 + src/assets/i18n/en.json5 | 2 + 7 files changed, 121 insertions(+) create mode 100644 src/app/shared/metric/metric-plumx/metric-plumx.component.html create mode 100644 src/app/shared/metric/metric-plumx/metric-plumx.component.scss create mode 100644 src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts create mode 100644 src/app/shared/metric/metric-plumx/metric-plumx.component.ts diff --git a/src/app/shared/metric/metric-loader/metric-loader.service.ts b/src/app/shared/metric/metric-loader/metric-loader.service.ts index a5ec44801ed..d6deb4bbbf5 100644 --- a/src/app/shared/metric/metric-loader/metric-loader.service.ts +++ b/src/app/shared/metric/metric-loader/metric-loader.service.ts @@ -6,6 +6,7 @@ import { MetricGooglescholarComponent } from '../metric-googlescholar/metric-goo import { MetricDspacecrisComponent } from '../metric-dspacecris/metric-dspacecris.component'; import {MetricEmbeddedViewComponent} from '../metric-embedded-view/metric-embedded-view.component'; import {MetricEmbeddedDownloadComponent} from '../metric-embedded-download/metric-embedded-download.component'; +import {MetricPlumxComponent} from '../metric-plumx/metric-plumx.component'; declare var document: any; @@ -45,7 +46,13 @@ export const MetricTypesConfig: MetricTypeConf[] = [ id: 'embedded-download', component: MetricEmbeddedDownloadComponent, script: null + }, + { + id: 'plumX', + component: MetricPlumxComponent, + script: '' } + ]; @Injectable({providedIn: 'root'}) @@ -93,6 +100,16 @@ export class MetricLoaderService { return null; } + /** + * Set the Script to run for the metric type. + * @param metricType to which is attached the script + * @param script to be set in dom + */ + public setScript(metricType: string, script: string): void { + this.loadScript(metricType, script); + + } + protected loadScript(metricType: string, src: string): Promise { console.log('Loading script of', metricType); return new Promise((resolve, reject) => { diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.html b/src/app/shared/metric/metric-plumx/metric-plumx.component.html new file mode 100644 index 00000000000..40dc0d4fbfe --- /dev/null +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.html @@ -0,0 +1,4 @@ +
+ {{metric.metricType | translate}} +
+
diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.scss b/src/app/shared/metric/metric-plumx/metric-plumx.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts new file mode 100644 index 00000000000..ede98f2744a --- /dev/null +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts @@ -0,0 +1,64 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {MetricPlumxComponent} from './metric-plumx.component'; +import {Injector} from '@angular/core'; +import {TranslateLoader, TranslateModule} from '@ngx-translate/core'; +import {TranslateLoaderMock} from '../../mocks/translate-loader.mock'; +import {By} from '@angular/platform-browser'; + +describe('MetricPlumxComponent', () => { + let component: MetricPlumxComponent; + let fixture: ComponentFixture; + const metricMock = { + acquisitionDate: new Date(), + deltaPeriod1: null, + deltaPeriod2: null, + endDate: null, + id: '1', + last: true, + metricCount: 333, + metricType: 'plumX', + rank: null, + remark: null, + startDate: null, + type: null, + _links: null + }; + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [MetricPlumxComponent], + imports: [TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: TranslateLoaderMock + } + })], + providers: [ + {provide: Injector, useValue: Injector} + ], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MetricPlumxComponent); + component = fixture.componentInstance; + component.metric = metricMock; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + beforeEach(() => { + metricMock.remark = "\""; + fixture = TestBed.createComponent(MetricPlumxComponent); + component = fixture.componentInstance; + component.metric = metricMock; + fixture.detectChanges(); + }); + it('should create', () => { + const innerHtmlMetric = fixture.debugElement.queryAll(By.css('div'))[1]; + expect(innerHtmlMetric.nativeElement.innerHTML).toBe( ''); + }); +}); + diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts new file mode 100644 index 00000000000..62f95d4a5aa --- /dev/null +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts @@ -0,0 +1,32 @@ +import {Component, Injector, OnInit} from '@angular/core'; +import {DomSanitizer, SafeHtml} from '@angular/platform-browser'; +import {BaseMetricComponent} from '../metric-loader/base-metric.component'; +import {MetricLoaderService} from '../metric-loader/metric-loader.service'; +import {hasValue} from '../../empty.util'; + +@Component({ + selector: 'ds-metric-plumx', + templateUrl: './metric-plumx.component.html', + styleUrls: ['./metric-plumx.component.scss'] +}) +export class MetricPlumxComponent extends BaseMetricComponent implements OnInit { + sanitizedInnerHtml: SafeHtml; + private metricLoaderService: MetricLoaderService; + + constructor(protected sr: DomSanitizer, + protected injector: Injector) { + super(); + } + + ngOnInit() { + if (hasValue(this.metric.remark)) { + const script = this.metric.remark.substring(this.metric.remark.indexOf('//cdn'), this.metric.remark.indexOf('.js') + 3); + // script is dynamic base on entityTyp and is coming from backend + this.metricLoaderService = this.injector.get(MetricLoaderService); + this.metricLoaderService.setScript('plumX', script); + // show the html + const stringToShow = this.metric.remark.substring(this.metric.remark.indexOf('') + 4); + this.sanitizedInnerHtml = this.sr.bypassSecurityTrustHtml(stringToShow); + } + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index cbae0fbb185..4bcd71d5d71 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -278,6 +278,7 @@ import { MultiColumnTopSectionComponent } from './explore/section-component/mult import { EditMetadataSecurityComponent } from '../item-page/edit-item-page/edit-metadata-security/edit-metadata-security.component'; import { MetadataLinkViewComponent } from './metadata-link-view/metadata-link-view.component'; import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component'; +import { MetricPlumxComponent } from './metric/metric-plumx/metric-plumx.component'; /** * Declaration needed to make sure all decorator functions are called in time @@ -687,6 +688,7 @@ const DIRECTIVES = [ ...SHARED_ITEM_PAGE_COMPONENTS, ...SHARED_SEARCH_PAGE_COMPONENTS, ItemExportAlertComponent, + MetricPlumxComponent, ], providers: [ ...PROVIDERS diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index bd79ec65a8d..7b3f71e8a5a 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2431,6 +2431,8 @@ "item.page.metric.label.wosPersonCitation": "Web of ScienceĀ© citations", + "item.page.metric.label.plumX": "PlumX", + "item.page.person.search.title": "Articles by this author", "item.page.related-items.view-more": "Show {{ amount }} more", From 697b40cdaa22d49fac711a906793a111f6b9cec4 Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Tue, 2 Nov 2021 11:24:47 +0100 Subject: [PATCH 3/7] [DSC-134] minor typo fix --- .../metric/metric-plumx/metric-plumx.component.spec.ts | 5 +++-- src/app/shared/metric/metric-plumx/metric-plumx.component.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts index ede98f2744a..685c1685e38 100644 --- a/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts @@ -50,13 +50,14 @@ describe('MetricPlumxComponent', () => { expect(component).toBeTruthy(); }); beforeEach(() => { - metricMock.remark = "\""; + metricMock.remark = "\""; fixture = TestBed.createComponent(MetricPlumxComponent); component = fixture.componentInstance; component.metric = metricMock; fixture.detectChanges(); }); - it('should create', () => { + it('should render plumx widget', () => { const innerHtmlMetric = fixture.debugElement.queryAll(By.css('div'))[1]; expect(innerHtmlMetric.nativeElement.innerHTML).toBe( ''); }); diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts index 62f95d4a5aa..1873e0e5ed5 100644 --- a/src/app/shared/metric/metric-plumx/metric-plumx.component.ts +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts @@ -23,7 +23,7 @@ export class MetricPlumxComponent extends BaseMetricComponent implements OnInit const script = this.metric.remark.substring(this.metric.remark.indexOf('//cdn'), this.metric.remark.indexOf('.js') + 3); // script is dynamic base on entityTyp and is coming from backend this.metricLoaderService = this.injector.get(MetricLoaderService); - this.metricLoaderService.setScript('plumX', script); + this.metricLoaderService.setScript('plumX', script); // show the html const stringToShow = this.metric.remark.substring(this.metric.remark.indexOf('') + 4); this.sanitizedInnerHtml = this.sr.bypassSecurityTrustHtml(stringToShow); From c18bdb4ff0b0cf4301c2770e6507755b2c1bc3b7 Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Wed, 3 Nov 2021 10:26:44 +0100 Subject: [PATCH 4/7] [DSC-155] render metric remark in angular side using json values of metric.remark --- src/app/core/layout/section-data.service.ts | 2 +- .../metric-altmetric.component.html | 11 +++++-- .../metric-altmetric.component.spec.ts | 32 ++++++++++++++++--- .../metric-altmetric.component.ts | 10 +++--- .../metric-googlescholar.component.html | 2 +- .../metric-googlescholar.component.spec.ts | 25 +++++++++++++-- .../metric-googlescholar.component.ts | 4 +-- 7 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/app/core/layout/section-data.service.ts b/src/app/core/layout/section-data.service.ts index 68bc215163c..5ba4e2c7da4 100644 --- a/src/app/core/layout/section-data.service.ts +++ b/src/app/core/layout/section-data.service.ts @@ -73,7 +73,7 @@ export class SectionDataService { * Find all the configured sections. */ findVisibleSections(): Observable>> { - return this.dataService.searchBy("visibleTopBarSections"); + return this.dataService.searchBy('visibleTopBarSections'); } } diff --git a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html index 2828b1e0a0c..115280135b3 100644 --- a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html +++ b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html @@ -1,5 +1,10 @@
- {{metric.metricType | translate}} + {{metric.metricType | translate}} +
+
+
+
-
- diff --git a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.spec.ts b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.spec.ts index 7f5d4d50708..46daedebb66 100644 --- a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.spec.ts +++ b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.spec.ts @@ -1,14 +1,28 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { MetricAltmetricComponent } from './metric-altmetric.component'; -import { metricAltmetricMock } from '../../../layout/default-layout/boxes/metrics/cris-layout-metrics-box.component.spec'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; +import { By } from '@angular/platform-browser'; describe('MetricAltmetricComponent', () => { let component: MetricAltmetricComponent; let fixture: ComponentFixture; - + const metricMock = { + acquisitionDate: new Date(), + deltaPeriod1: null, + deltaPeriod2: null, + endDate: null, + id: '1', + last: true, + metricCount: 333, + metricType: 'altmetric', + rank: null, + remark: '{"popover":"bottom","badgeType":"medium-donut","doiAttr":"10.1056/Test","pmidAttr":"1234567890"}', + startDate: null, + type: null, + _links: null + }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot({ @@ -17,15 +31,15 @@ describe('MetricAltmetricComponent', () => { useClass: TranslateLoaderMock } })], - declarations: [ MetricAltmetricComponent ] + declarations: [MetricAltmetricComponent] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(MetricAltmetricComponent); component = fixture.componentInstance; - component.metric = metricAltmetricMock; + component.metric = metricMock; component.success = true; component.maxRetry = 0; fixture.detectChanges(); @@ -34,4 +48,12 @@ describe('MetricAltmetricComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + it('should render badge div', () => { + const div = fixture.debugElement.queryAll(By.css('div'))[2]; + expect(div.nativeElement.className).toEqual('altmetric-embed'); + expect(div.nativeElement.dataset.badgePopover).toEqual('bottom'); + expect(div.nativeElement.dataset.badgeType).toEqual('medium-donut'); + expect(div.nativeElement.dataset.doi).toEqual('10.1056/Test'); + expect(div.nativeElement.dataset.pmid).toEqual('1234567890'); + }); }); diff --git a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.ts b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.ts index 3b4ab0c522a..c856fdab6c8 100644 --- a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.ts +++ b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { BaseEmbeddedMetricComponent } from '../metric-loader/base-embedded-metric.component'; import { DomSanitizer } from '@angular/platform-browser'; @@ -9,12 +9,14 @@ declare var _altmetric_embed_init: any; templateUrl: './metric-altmetric.component.html', styleUrls: ['./metric-altmetric.component.scss'] }) -export class MetricAltmetricComponent extends BaseEmbeddedMetricComponent { - +export class MetricAltmetricComponent extends BaseEmbeddedMetricComponent implements OnInit { + remark: JSON; constructor(protected sr: DomSanitizer) { super(sr); } - + ngOnInit() { + this.remark = JSON.parse(this.metric.remark); + } applyScript(): void { _altmetric_embed_init(this.metricChild.nativeElement); } diff --git a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.html b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.html index dbf8d6e533b..c4317373e46 100644 --- a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.html +++ b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.html @@ -2,5 +2,5 @@
{{metric.metricType | translate}}
-
+ {{'Check' | translate}}
diff --git a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.spec.ts b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.spec.ts index 7f474664399..cc58cbbe478 100644 --- a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.spec.ts +++ b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.spec.ts @@ -3,12 +3,27 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { MetricGooglescholarComponent } from './metric-googlescholar.component'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoaderMock } from '../../mocks/translate-loader.mock'; -import { metricGoogleScholarMock } from '../../../layout/default-layout/boxes/metrics/cris-layout-metrics-box.component.spec'; +import { By } from '@angular/platform-browser'; describe('MetricGooglescholarComponent', () => { let component: MetricGooglescholarComponent; let fixture: ComponentFixture; - + const href = 'https://scholar.google.com/scholar?q=The+Covid-19+Vaccine-Development+Multiverse'; + const metricMock = { + acquisitionDate: new Date(), + deltaPeriod1: null, + deltaPeriod2: null, + endDate: null, + id: '1', + last: true, + metricCount: 333, + metricType: 'google-scholar', + rank: null, + remark: '{"href":"' + href + '"}', + startDate: null, + type: null, + _links: null + }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [TranslateModule.forRoot({ @@ -25,11 +40,15 @@ describe('MetricGooglescholarComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(MetricGooglescholarComponent); component = fixture.componentInstance; - component.metric = metricGoogleScholarMock; + component.metric = metricMock; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + it('should render anchor with href', () => { + const a = fixture.debugElement.queryAll(By.css('a'))[0]; + expect(a.nativeElement.href).toEqual(href); + }); }); diff --git a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.ts b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.ts index 1b3236124e3..62bea0486ae 100644 --- a/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.ts +++ b/src/app/shared/metric/metric-googlescholar/metric-googlescholar.component.ts @@ -8,14 +8,14 @@ import { DomSanitizer } from '@angular/platform-browser'; styleUrls: ['./metric-googlescholar.component.scss'] }) export class MetricGooglescholarComponent extends BaseMetricComponent implements OnInit { - + remark: JSON; sanitizedInnerHtml; - constructor(protected sr: DomSanitizer) { super(); } ngOnInit() { + this.remark = JSON.parse(this.metric.remark); this.sanitizedInnerHtml = this.sr.bypassSecurityTrustHtml(this.metric.remark); } From 6471268e0a346a820749b5d01b611da8625b36a1 Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Wed, 3 Nov 2021 11:37:09 +0100 Subject: [PATCH 5/7] [DSC-155] add translations --- .../metric/metric-altmetric/metric-altmetric.component.html | 2 +- .../metric-googlescholar/metric-googlescholar.component.html | 2 +- src/assets/i18n/en.json5 | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html index 115280135b3..6aa1815aace 100644 --- a/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html +++ b/src/app/shared/metric/metric-altmetric/metric-altmetric.component.html @@ -1,7 +1,7 @@
{{metric.metricType | translate}}
-
+ diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index bd79ec65a8d..c09e0d4d1b3 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2408,6 +2408,8 @@ "item.page.metric.label.altmetrics": "AltmetricsĀ©", + "item.page.metric.label.check": "Check", + "item.page.metric.label.download": "Downloads", From b70f8e9b7ea5c8292340e25768990b639fb4d8a4 Mon Sep 17 00:00:00 2001 From: Alba Aliu Date: Wed, 3 Nov 2021 16:26:37 +0100 Subject: [PATCH 6/7] [DSC-155] render html of plumx metric in angular side + test fixes --- .../metric-plumx/metric-plumx.component.html | 8 +++++++- .../metric-plumx.component.spec.ts | 19 ++++++------------- .../metric-plumx/metric-plumx.component.ts | 8 +++----- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.html b/src/app/shared/metric/metric-plumx/metric-plumx.component.html index 40dc0d4fbfe..404b069ec67 100644 --- a/src/app/shared/metric/metric-plumx/metric-plumx.component.html +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.html @@ -1,4 +1,10 @@
{{metric.metricType | translate}}
-
+
+ +
+ + + + diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts index 685c1685e38..5b82b8e542c 100644 --- a/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.spec.ts @@ -18,7 +18,7 @@ describe('MetricPlumxComponent', () => { metricCount: 333, metricType: 'plumX', rank: null, - remark: null, + remark: '{"type":"Publication","src":"//cdn.plu.mx/widget-popup.js","href":"https://plu.mx/plum/a/?doi=10.1056/NEJMe2025111"}', startDate: null, type: null, _links: null @@ -45,21 +45,14 @@ describe('MetricPlumxComponent', () => { component.metric = metricMock; fixture.detectChanges(); }); - it('should create', () => { expect(component).toBeTruthy(); }); - beforeEach(() => { - metricMock.remark = "\""; - fixture = TestBed.createComponent(MetricPlumxComponent); - component = fixture.componentInstance; - component.metric = metricMock; - fixture.detectChanges(); - }); - it('should render plumx widget', () => { - const innerHtmlMetric = fixture.debugElement.queryAll(By.css('div'))[1]; - expect(innerHtmlMetric.nativeElement.innerHTML).toBe( ''); + it('should render plumx widget', (done) => { + const innerHtmlMetric = fixture.debugElement.query(By.css('a')); + expect(innerHtmlMetric.nativeElement.className).toEqual('plumx-plum-print-popup'); + expect(innerHtmlMetric.nativeElement.href).toEqual('https://plu.mx/plum/a/?doi=10.1056/NEJMe2025111'); + done(); }); }); diff --git a/src/app/shared/metric/metric-plumx/metric-plumx.component.ts b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts index 1873e0e5ed5..d320f9527f0 100644 --- a/src/app/shared/metric/metric-plumx/metric-plumx.component.ts +++ b/src/app/shared/metric/metric-plumx/metric-plumx.component.ts @@ -10,7 +10,7 @@ import {hasValue} from '../../empty.util'; styleUrls: ['./metric-plumx.component.scss'] }) export class MetricPlumxComponent extends BaseMetricComponent implements OnInit { - sanitizedInnerHtml: SafeHtml; + remark: JSON; private metricLoaderService: MetricLoaderService; constructor(protected sr: DomSanitizer, @@ -20,13 +20,11 @@ export class MetricPlumxComponent extends BaseMetricComponent implements OnInit ngOnInit() { if (hasValue(this.metric.remark)) { - const script = this.metric.remark.substring(this.metric.remark.indexOf('//cdn'), this.metric.remark.indexOf('.js') + 3); + this.remark = JSON.parse(this.metric.remark); + const script = (this.remark as any).src; // script is dynamic base on entityTyp and is coming from backend this.metricLoaderService = this.injector.get(MetricLoaderService); this.metricLoaderService.setScript('plumX', script); - // show the html - const stringToShow = this.metric.remark.substring(this.metric.remark.indexOf('') + 4); - this.sanitizedInnerHtml = this.sr.bypassSecurityTrustHtml(stringToShow); } } } From 087899dcd18f69bdb49ae42530f1ca95be634469 Mon Sep 17 00:00:00 2001 From: Alessandro Martelli Date: Mon, 21 Jun 2021 17:57:48 +0200 Subject: [PATCH 7/7] Suggestions improvements picked from perucris [CSTPER-701] suggestion import include link in notification [CSTPER-590] suggestions recap in profile page card [CSTPER-590] improved suggestions messages with correct source and type [CSTPER-590] possibility to directly import suggestions in configured collection --- .../suggestion-actions.component.html | 25 ++++-- .../suggestion-actions.component.ts | 14 ++- .../suggestion-list-element.component.html | 1 + .../suggestion-list-element.component.ts | 2 + .../suggestions-notification.component.html | 2 +- .../suggestions.service.ts | 57 ++++++++++-- .../profile-page/profile-page.component.html | 5 +- src/app/profile-page/profile-page.module.ts | 4 +- .../suggestions-page.component.html | 5 +- .../suggestions-page.component.ts | 41 +++++++-- src/assets/i18n/en.json5 | 88 +++++++++++++++++-- src/config/global-config.interface.ts | 3 +- src/config/layout-config.interfaces.ts | 5 ++ src/environments/environment.common.ts | 11 ++- 14 files changed, 228 insertions(+), 35 deletions(-) diff --git a/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.html b/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.html index 75e13ad1452..7ec3e61395e 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.html +++ b/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.html @@ -1,16 +1,23 @@
- - + + + + + +
diff --git a/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.ts b/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.ts index d16f4175d3c..cf219011237 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.ts +++ b/src/app/openaire/reciter-suggestions/suggestion-actions/suggestion-actions.component.ts @@ -18,9 +18,11 @@ export class SuggestionActionsComponent { @Input() isBulk = false; - @Input() public hasEvidence = false; + @Input() hasEvidence = false; - @Input() public seeEvidence = false; + @Input() seeEvidence = false; + + @Input() isCollectionFixed = false; /** * The component is used to Delete suggestion @@ -58,6 +60,14 @@ export class SuggestionActionsComponent { }); } + approveAndImportCollectionFixed() { + this.approveAndImport.emit({ + suggestion: this.isBulk ? undefined : this.object, + collectionId: null + }); + } + + /** * Delete the suggestion */ diff --git a/src/app/openaire/reciter-suggestions/suggestion-list-element/suggestion-list-element.component.html b/src/app/openaire/reciter-suggestions/suggestion-list-element/suggestion-list-element.component.html index 7f036bc8bc6..05f9c0ac771 100644 --- a/src/app/openaire/reciter-suggestions/suggestion-list-element/suggestion-list-element.component.html +++ b/src/app/openaire/reciter-suggestions/suggestion-list-element/suggestion-list-element.component.html @@ -27,6 +27,7 @@ -
+
diff --git a/src/app/openaire/reciter-suggestions/suggestions.service.ts b/src/app/openaire/reciter-suggestions/suggestions.service.ts index 82939c2e73c..de743d95e34 100644 --- a/src/app/openaire/reciter-suggestions/suggestions.service.ts +++ b/src/app/openaire/reciter-suggestions/suggestions.service.ts @@ -12,7 +12,7 @@ import { OpenaireSuggestionTarget } from '../../core/openaire/reciter-suggestion import { ResearcherProfileService } from '../../core/profile/researcher-profile.service'; import { AuthService } from '../../core/auth/auth.service'; import { EPerson } from '../../core/eperson/models/eperson.model'; -import { isNotEmpty } from '../../shared/empty.util'; +import { hasValue, isNotEmpty } from '../../shared/empty.util'; import { ResearcherProfile } from '../../core/profile/model/researcher-profile.model'; import { getAllSucceededRemoteDataPayload, @@ -24,6 +24,9 @@ import { OpenaireSuggestion } from '../../core/openaire/reciter-suggestions/mode import { WorkspaceitemDataService } from '../../core/submission/workspaceitem-data.service'; import { TranslateService } from '@ngx-translate/core'; import { NoContent } from '../../core/shared/NoContent.model'; +import { environment } from '../../../environments/environment'; +import { SuggestionConfig } from '../../../config/layout-config.interfaces'; +import { WorkspaceItem } from '../../core/submission/models/workspaceitem.model'; export interface SuggestionBulkResult { success: number; @@ -170,8 +173,10 @@ export class SuggestionsService { */ public approveAndImport(workspaceitemService: WorkspaceitemDataService, suggestion: OpenaireSuggestion, - collectionId: string): Observable { - return workspaceitemService.importExternalSourceEntry(suggestion.externalSourceUri, collectionId) + collectionId: string): Observable { + + const resolvedCollectionId = this.resolveCollectionId(suggestion, collectionId); + return workspaceitemService.importExternalSourceEntry(suggestion.externalSourceUri, resolvedCollectionId) .pipe( getFirstSucceededRemoteDataPayload(), catchError((error) => of(null)) @@ -200,7 +205,7 @@ export class SuggestionsService { return forkJoin(suggestions.map((suggestion: OpenaireSuggestion) => this.approveAndImport(workspaceitemService, suggestion, collectionId))) - .pipe(map((results: string[]) => { + .pipe(map((results: WorkspaceItem[]) => { return { success: results.filter((result) => result != null).length, fails: results.filter((result) => result == null).length @@ -240,10 +245,52 @@ export class SuggestionsService { public getNotificationSuggestionInterpolation(suggestionTarget: OpenaireSuggestionTarget): any { return { count: suggestionTarget.total, - source: this.translateService.instant('reciter.suggestion.source.' + suggestionTarget.source), + source: this.translateService.instant(this.translateSuggestionSource(suggestionTarget.source)), + type: this.translateService.instant(this.translateSuggestionType(suggestionTarget.source)), suggestionId: suggestionTarget.id, displayName: suggestionTarget.display }; } + public translateSuggestionType(source: string): string { + return 'reciter.suggestion.type.' + source; + } + + public translateSuggestionSource(source: string): string { + return 'reciter.suggestion.source.' + source; + } + + /** + * If the provided collectionId ha no value, tries to resolve it by suggestion source. + * @param suggestion + * @param collectionId + */ + public resolveCollectionId(suggestion: OpenaireSuggestion, collectionId): string { + if (hasValue(collectionId)) { + return collectionId; + } + return environment.suggestion + .find((suggestionConf: SuggestionConfig) => suggestionConf.source === suggestion.source) + .collectionId; + } + + /** + * Return true if all the suggestion are configured with the same fixed collection + * in the configuration. + * @param suggestions + */ + public isCollectionFixed(suggestions: OpenaireSuggestion[]): boolean { + return this.getFixedCollectionIds(suggestions).length === 1; + } + + private getFixedCollectionIds(suggestions: OpenaireSuggestion[]): string[] { + const collectionIds = {}; + suggestions.forEach((suggestion: OpenaireSuggestion) => { + const conf = environment.suggestion.find((suggestionConf: SuggestionConfig) => suggestionConf.source === suggestion.source); + if (hasValue(conf)) { + collectionIds[conf.collectionId] = true; + } + }); + return Object.keys(collectionIds); + } } diff --git a/src/app/profile-page/profile-page.component.html b/src/app/profile-page/profile-page.component.html index bd085ef20fa..ed9c96900a0 100644 --- a/src/app/profile-page/profile-page.component.html +++ b/src/app/profile-page/profile-page.component.html @@ -4,7 +4,10 @@

{{'profile.head' | translate}}

{{'profile.card.researcher' | translate}}
- +
+ +
+
diff --git a/src/app/profile-page/profile-page.module.ts b/src/app/profile-page/profile-page.module.ts index 562a01885c7..e25ff0f3f50 100644 --- a/src/app/profile-page/profile-page.module.ts +++ b/src/app/profile-page/profile-page.module.ts @@ -8,13 +8,15 @@ import { ProfilePageSecurityFormComponent } from './profile-page-security-form/p import { ProfilePageResearcherFormComponent } from './profile-page-researcher-form/profile-page-researcher-form.component'; import { ThemedProfilePageComponent } from './themed-profile-page.component'; import { UiSwitchModule } from 'ngx-ui-switch'; +import { OpenaireModule } from '../openaire/openaire.module'; @NgModule({ imports: [ ProfilePageRoutingModule, CommonModule, SharedModule, - UiSwitchModule + UiSwitchModule, + OpenaireModule ], exports: [ ProfilePageSecurityFormComponent diff --git a/src/app/suggestions-page/suggestions-page.component.html b/src/app/suggestions-page/suggestions-page.component.html index 8c37fd319a3..fb5f08b6a4c 100644 --- a/src/app/suggestions-page/suggestions-page.component.html +++ b/src/app/suggestions-page/suggestions-page.component.html @@ -5,9 +5,10 @@

+ {{ translateSuggestionType() | translate }} {{'reciter.suggestion.suggestionFor' | translate}} {{researcherName}} - {{'reciter.suggestion.from.source' | translate}} {{ getSuggestionSourceLabel() | translate}} + {{'reciter.suggestion.from.source' | translate}} {{ translateSuggestionSource() | translate }}

@@ -16,6 +17,7 @@

@@ -32,6 +34,7 @@

diff --git a/src/app/suggestions-page/suggestions-page.component.ts b/src/app/suggestions-page/suggestions-page.component.ts index 7cad975f2b1..47d0b9a0863 100644 --- a/src/app/suggestions-page/suggestions-page.component.ts +++ b/src/app/suggestions-page/suggestions-page.component.ts @@ -20,6 +20,7 @@ import { SuggestionTargetsStateService } from '../openaire/reciter-suggestions/s import { WorkspaceitemDataService } from '../core/submission/workspaceitem-data.service'; import { PaginationService } from '../core/pagination/pagination.service'; import { FindListOptions } from '../core/data/request.models'; +import { WorkspaceItem } from '../core/submission/models/workspaceitem.model'; @Component({ selector: 'ds-suggestion-page', @@ -59,10 +60,11 @@ export class SuggestionsPageComponent implements OnInit { targetRD$: Observable>; targetId$: Observable; + suggestionTarget: OpenaireSuggestionTarget; suggestionId: any; + suggestionSource: any; researcherName: any; researcherUuid: any; - suggestionSource: any; selectedSuggestions: { [id: string]: OpenaireSuggestion } = {}; isBulkOperationPending = false; @@ -93,6 +95,7 @@ export class SuggestionsPageComponent implements OnInit { this.targetRD$.pipe( getFirstSucceededRemoteDataPayload() ).subscribe((suggestionTarget: OpenaireSuggestionTarget) => { + this.suggestionTarget = suggestionTarget; this.suggestionId = suggestionTarget.id; this.researcherName = suggestionTarget.display; this.suggestionSource = suggestionTarget.source; @@ -136,6 +139,15 @@ export class SuggestionsPageComponent implements OnInit { this.processing$.next(false); this.suggestionsRD$.next(results); this.suggestionService.clearSuggestionRequests(); + // navigate to the mydspace if no suggestions remains + + // if (results.totalElements === 0) { + // const content = this.translateService.instant('reciter.suggestion.empty', + // this.suggestionService.getNotificationSuggestionInterpolation(this.suggestionTarget)); + // this.notificationService.success('', content, {timeOut:0}, true); + // TODO if the target is not the current use route to the suggestion target page + // this.router.navigate(['/mydspace']); + // } }); } @@ -181,9 +193,10 @@ export class SuggestionsPageComponent implements OnInit { */ approveAndImport(event: SuggestionApproveAndImport) { this.suggestionService.approveAndImport(this.workspaceItemService, event.suggestion, event.collectionId) - .subscribe((response: any) => { + .subscribe((workspaceitem: WorkspaceItem) => { + const content = this.translateService.instant('reciter.suggestion.approveAndImport.success', { workspaceItemId: workspaceitem.id }); + this.notificationService.success('', content, {timeOut:0}, true); this.suggestionTargetsStateService.dispatchRefreshUserSuggestionsAction(); - this.notificationService.success(this.translateService.get('reciter.suggestion.approveAndImport.success')); this.updatePage(); }); } @@ -248,8 +261,26 @@ export class SuggestionsPageComponent implements OnInit { return Object.keys(this.selectedSuggestions).length; } - getSuggestionSourceLabel(): string { - return 'reciter.suggestion.source.' + this.suggestionSource; + /** + * Return true if all the suggestion are configured with the same fixed collection in the configuration. + * @param suggestions + */ + isCollectionFixed(suggestions: OpenaireSuggestion[]): boolean { + return this.suggestionService.isCollectionFixed(suggestions); + } + + /** + * Label to be used to translate the suggestion source. + */ + translateSuggestionSource() { + return this.suggestionService.translateSuggestionSource(this.suggestionSource); + } + + /** + * Label to be used to translate the suggestion type. + */ + translateSuggestionType() { + return this.suggestionService.translateSuggestionType(this.suggestionSource); } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 90d6cd56bf0..985510d5610 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1,5 +1,7 @@ { + "Biography": "English Biography", + "401.help": "You're not authorized to access this page. You can use the button below to get back to the home page.", "401.link.home-page": "Take me to the home page", @@ -72,6 +74,41 @@ "menu.section.cms.edit.metadata.head": "Edit Metadata", + "admin.institution.new.breadcrumbs": "Create Institution", + + "admin.institution.new.error": "An error occurred while creating the new institution. Check if the template institution is defined and if an institution with the same name already exists.", + + "admin.institution.new.header": "Create Institution", + + "admin.institution.new.name": "Name", + + "admin.institution.new.processing": "Loading", + + "admin.institution.new.submit": "Submit", + + "admin.institution.new.success": "The new institution was successfully created", + + "admin.institution.new.title": "Create Institution", + + + "admin.institution.explore.breadcrumbs": "Explore Institutions", + + "admin.institution.explore.header": "Explore Institutions", + + "admin.institution.explore.entities": "Entities", + + "admin.institution.explore.name": "Institution name", + + "admin.institution.explore.no-entities": "No available entities", + + "admin.institution.explore.no-roles": "No available roles", + + "admin.institution.explore.roles": "Institutional Scoped Roles", + + "admin.institution.explore.title": "Explore Institutions", + + + "admin.registries.bitstream-formats.breadcrumbs": "Format registry", "admin.registries.bitstream-formats.create.breadcrumbs": "Bitstream format", @@ -324,6 +361,10 @@ "admin.access-control.epeople.form.groupsEPersonIsMemberOf": "Member of these groups:", + "admin.access-control.epeople.form.roles": "Roles", + + "admin.access-control.epeople.form.rolesNoAvailable": "No roles available", + "admin.access-control.epeople.form.table.id": "ID", "admin.access-control.epeople.form.table.name": "Name", @@ -337,6 +378,19 @@ "admin.access-control.epeople.notification.deleted.success": "Successfully deleted EPerson: \"{{name}}\"", + "admin.access-control.groups.badge.disabled": "Disabled", + + "admin.access-control.groups.badge.enabled": "Enabled", + + "admin.access-control.groups.badge.permanent": "Permanent", + + "admin.access-control.groups.badge.institutional": "Institutional Role", + + "admin.access-control.groups.badge.normal": "Normal", + + "admin.access-control.groups.badge.role": "Role", + + "admin.access-control.groups.badge.scoped": "Institutional Scoped Role", "admin.access-control.groups.title": "Groups", @@ -350,7 +404,7 @@ "admin.access-control.groups.addGroup.breadcrumbs": "New Group", - "admin.access-control.groups.head": "Groups", + "admin.access-control.groups.head": "Groups/Roles", "admin.access-control.groups.button.add": "Add group", @@ -370,9 +424,13 @@ "admin.access-control.groups.table.edit": "Edit", + "admin.access-control.groups.table.edit.buttons.disable": "Disable \"{{name}}\"", + "admin.access-control.groups.table.edit.buttons.edit": "Edit \"{{name}}\"", - "admin.access-control.groups.table.edit.buttons.remove": "Delete \"{{name}}\"", + "admin.access-control.groups.table.type": "Type", + + "admin.access-control.groups.table.status": "Status", "admin.access-control.groups.no-items": "No groups found with this in their name or this as UUID", @@ -400,6 +458,22 @@ "admin.access-control.groups.form.groupDescription": "Description", + "admin.access-control.groups.form.groupStatus": "Status", + + "admin.access-control.groups.form.groupStatus.enabled": "Enabled", + + "admin.access-control.groups.form.groupStatus.disabled": "Disabled", + + "admin.access-control.groups.form.groupType": "Type", + + "admin.access-control.groups.form.groupType.institutional": "Institutional Role type", + + "admin.access-control.groups.form.groupType.normal": "Normal type", + + "admin.access-control.groups.form.groupType.role": "Role type", + + "admin.access-control.groups.form.groupType.scoped": "Institutional Scoped Role type", + "admin.access-control.groups.form.notification.created.success": "Successfully created Group \"{{name}}\"", "admin.access-control.groups.form.notification.created.failure": "Failed to create Group \"{{name}}\"", @@ -3073,7 +3147,7 @@ "mydspace.notification.suggestion": "We found {{count}} publications
in the {{source}} that seems to be related to your profile.
Please review the suggestions", - "mydspace.notification.suggestion.page": "We found {{count}} publications in the {{source}} that seems to be related to your profile. Please review the suggestions.", + "mydspace.notification.suggestion.page": "We found {{count}} {{type}} in the {{source}} that seems to be related to your profile. Please review the suggestions.", "nav.browse.header": "All of DSpace", @@ -3249,7 +3323,7 @@ "reciter.suggestion.approveAndImport": "Approve & import", - "reciter.suggestion.approveAndImport.success": "The suggestion has been imported successfully", + "reciter.suggestion.approveAndImport.success": "The suggestion has been imported successfully. View.", "reciter.suggestion.approveAndImport.bulk": "Approve & import Selected", @@ -3267,6 +3341,8 @@ "reciter.suggestion.notMine.bulk.error": "{{ count }} suggestions haven't been discarded due to unexpected server errors", + "reciter.suggestion.empty": "All the {{type}} suggestions in the {{source}}
related to your profile have been either approved or rejected.", + "reciter.suggestion.seeEvidence": "See evidence", "reciter.suggestion.hideEvidence": "Hide evidence", @@ -3281,9 +3357,7 @@ "reciter.suggestion.totalScore": "Total Score", - - - + "reciter.suggestion.type.oaire": "Publications", "orgunit.listelement.badge": "Organizational Unit", diff --git a/src/config/global-config.interface.ts b/src/config/global-config.interface.ts index 767eb66daa1..ab40cfacde9 100644 --- a/src/config/global-config.interface.ts +++ b/src/config/global-config.interface.ts @@ -13,7 +13,7 @@ import { ThemeConfig } from './theme.model'; import { AuthConfig } from './auth-config.interfaces'; import { UIServerConfig } from './ui-server-config.interface'; import { MediaViewerConfig } from './media-viewer-config.interface'; -import { LayoutConfig } from './layout-config.interfaces'; +import { LayoutConfig, SuggestionConfig } from './layout-config.interfaces'; import { MetadataSecurityConfig } from './metadata-security-config'; import {CmsMetadata} from './cms-metadata'; @@ -38,4 +38,5 @@ export interface GlobalConfig extends Config { layout: LayoutConfig; security: MetadataSecurityConfig; cms: CmsMetadata; + suggestion: SuggestionConfig[]; } diff --git a/src/config/layout-config.interfaces.ts b/src/config/layout-config.interfaces.ts index 54d89a29bac..296bc0d9066 100644 --- a/src/config/layout-config.interfaces.ts +++ b/src/config/layout-config.interfaces.ts @@ -14,3 +14,8 @@ export interface LayoutConfig extends Config { urn: UrnConfig[]; crisRef: CrisRefConfig[]; } + +export interface SuggestionConfig extends Config { + source: string; + collectionId: string; +} diff --git a/src/environments/environment.common.ts b/src/environments/environment.common.ts index bb0c123eb02..ddd64d9141d 100644 --- a/src/environments/environment.common.ts +++ b/src/environments/environment.common.ts @@ -23,8 +23,8 @@ export const environment: GlobalConfig = { // NOTE: these must be "synced" with the 'dspace.server.url' setting in your backend's local.cfg. rest: { ssl: true, - host: 'localhost', - port: 8080, + host: 'dspacecris7.4science.cloud', + port: 443, // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript nameSpace: '/server', }, @@ -389,6 +389,13 @@ export const environment: GlobalConfig = { } ] }, + suggestion: [ + // { + // // Use this configuration to map a suggestion import to a specific collection based on the suggestion type. + // source: 'suggestionSource', + // collectionId: 'collectionUUID' + // } + ], cms: { metadataList: [ 'cms.homepage.header',