diff --git a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts index 60fa679777..6d02ac8292 100644 --- a/src/app/admin/admin-notifications/admin-notifications-routing.module.ts +++ b/src/app/admin/admin-notifications/admin-notifications-routing.module.ts @@ -49,6 +49,21 @@ import { SourceDataResolver } from './admin-quality-assurance-source-page-compon showBreadcrumbsFluid: false } }, + { + canActivate: [ AuthenticatedGuard ], + path: `${QUALITY_ASSURANCE_EDIT_PATH}/:sourceId/:targetId`, + component: AdminQualityAssuranceTopicsPageComponent, + pathMatch: 'full', + resolve: { + breadcrumb: I18nBreadcrumbResolver, + openaireQualityAssuranceTopicsParams: AdminQualityAssuranceTopicsPageResolver + }, + data: { + title: 'admin.quality-assurance.page.title', + breadcrumbKey: 'admin.quality-assurance', + showBreadcrumbsFluid: false + } + }, { canActivate: [ AuthenticatedGuard ], path: `${QUALITY_ASSURANCE_EDIT_PATH}`, diff --git a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts index 7f7e68afaa..6c333cc6f5 100644 --- a/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts +++ b/src/app/core/suggestion-notifications/qa/events/quality-assurance-event-data.service.ts @@ -84,6 +84,16 @@ export class QualityAssuranceEventDataService extends IdentifiableDataService[]): Observable>> { + return this.searchData.searchBy('findByTopic', options, true, true, ...linksToFollow); + } + /** * Clear findByTopic requests from cache */ diff --git a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts index 03a5da2e8c..130e7261d1 100644 --- a/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts +++ b/src/app/core/suggestion-notifications/qa/source/quality-assurance-source-data.service.ts @@ -16,6 +16,7 @@ import { PaginatedList } from '../../../data/paginated-list.model'; import { FindListOptions } from '../../../data/find-list-options.model'; import { IdentifiableDataService } from '../../../data/base/identifiable-data.service'; import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; +import { SearchData, SearchDataImpl } from 'src/app/core/data/base/search-data'; /** * The service handling all Quality Assurance source REST requests. @@ -25,6 +26,9 @@ import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; export class QualityAssuranceSourceDataService extends IdentifiableDataService { private findAllData: FindAllData; + private searchAllData: SearchData; + + private searchByTargetMethod = 'byTarget'; /** * Initialize service variables @@ -43,6 +47,7 @@ export class QualityAssuranceSourceDataService extends IdentifiableDataService[]): Observable> { return this.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } + + /** + * Retrieves a paginated list of QualityAssuranceSourceObject objects that are associated with a given target object. + * @param options The options for the search query. + * @param useCachedVersionIfAvailable Whether to use a cached version of the data if available. + * @param reRequestOnStale Whether to re-request the data if the cached version is stale. + * @param linksToFollow The links to follow to retrieve the data. + * @returns An observable that emits a RemoteData object containing the paginated list of QualityAssuranceSourceObject objects. + */ + public getSourcesByTarget(options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { + return this.searchAllData.searchBy(this.searchByTargetMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } } diff --git a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts index 2bf5195bf1..bb98e6fabf 100644 --- a/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts +++ b/src/app/core/suggestion-notifications/qa/topics/quality-assurance-topic-data.service.ts @@ -16,6 +16,7 @@ import { IdentifiableDataService } from '../../../data/base/identifiable-data.se import { dataService } from '../../../data/base/data-service.decorator'; import { QUALITY_ASSURANCE_TOPIC_OBJECT } from '../models/quality-assurance-topic-object.resource-type'; import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; +import { SearchData, SearchDataImpl } from '../../../../core/data/base/search-data'; /** * The service handling all Quality Assurance topic REST requests. @@ -25,6 +26,9 @@ import { FindAllData, FindAllDataImpl } from '../../../data/base/find-all-data'; export class QualityAssuranceTopicDataService extends IdentifiableDataService { private findAllData: FindAllData; + private searchData: SearchData; + + private searchByTargetMethod = 'byTarget'; /** * Initialize service variables @@ -43,6 +47,7 @@ export class QualityAssuranceTopicDataService extends IdentifiableDataService[]): Observable>> { + return this.searchData.searchBy(this.searchByTargetMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } + /** * Clear FindAll topics requests from cache */ diff --git a/src/app/item-page/item-page.module.ts b/src/app/item-page/item-page.module.ts index a8d41d1535..5aa1b6e508 100644 --- a/src/app/item-page/item-page.module.ts +++ b/src/app/item-page/item-page.module.ts @@ -60,6 +60,7 @@ import { ThemedItemAlertsComponent } from './alerts/themed-item-alerts.component import { ThemedFullFileSectionComponent } from './full/field-components/file-section/themed-full-file-section.component'; +import { QaEventNotificationComponent } from './simple/qa-event-notification/qa-event-notification.component'; const ENTRY_COMPONENTS = [ // put only entry components that use custom decorator @@ -103,6 +104,7 @@ const DECLARATIONS = [ ItemAlertsComponent, ThemedItemAlertsComponent, BitstreamRequestACopyPageComponent, + QaEventNotificationComponent ]; @NgModule({ diff --git a/src/app/item-page/simple/item-page.component.html b/src/app/item-page/simple/item-page.component.html index cc9983bb35..37a5e0c4cb 100644 --- a/src/app/item-page/simple/item-page.component.html +++ b/src/app/item-page/simple/item-page.component.html @@ -2,6 +2,7 @@
+ diff --git a/src/app/item-page/simple/item-page.component.ts b/src/app/item-page/simple/item-page.component.ts index 2e4e357572..a057e99715 100644 --- a/src/app/item-page/simple/item-page.component.ts +++ b/src/app/item-page/simple/item-page.component.ts @@ -33,7 +33,7 @@ import { NotifyInfoService } from 'src/app/core/coar-notify/notify-info/notify-i styleUrls: ['./item-page.component.scss'], templateUrl: './item-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, - animations: [fadeInOut] + animations: [fadeInOut], }) export class ItemPageComponent implements OnInit, OnDestroy { diff --git a/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.html b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.html new file mode 100644 index 0000000000..2e47916fd7 --- /dev/null +++ b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.html @@ -0,0 +1,14 @@ + + +
+ +
+
{{'item.qa-event-notification.check.notification-info' | translate : {num: + source.totalEvents } }}
+ +
+
+
+
diff --git a/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.scss b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.scss new file mode 100644 index 0000000000..ab33b46fca --- /dev/null +++ b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.scss @@ -0,0 +1,8 @@ + +.source-logo { + max-height: var(--ds-header-logo-height); +} + +.sections-gap { + gap: 1rem; +} diff --git a/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.spec.ts b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.spec.ts new file mode 100644 index 0000000000..1be125c73c --- /dev/null +++ b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { QaEventNotificationComponent } from './qa-event-notification.component'; + +describe('QaEventNotificationComponent', () => { + let component: QaEventNotificationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ QaEventNotificationComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(QaEventNotificationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.ts b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.ts new file mode 100644 index 0000000000..f85925373a --- /dev/null +++ b/src/app/item-page/simple/qa-event-notification/qa-event-notification.component.ts @@ -0,0 +1,53 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { Item } from '../../../core/shared/item.model'; +import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../../core/shared/operators'; +import { Observable, tap } from 'rxjs'; +import { AlertType } from '../../../shared/alert/aletr-type'; +import { FindListOptions } from '../../../core/data/find-list-options.model'; +import { RequestParam } from '../../../core/cache/models/request-param.model'; +import { QualityAssuranceSourceDataService } from '../../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +import { QualityAssuranceSourceObject } from '../../../core/suggestion-notifications/qa/models/quality-assurance-source.model'; + +@Component({ + selector: 'ds-qa-event-notification', + templateUrl: './qa-event-notification.component.html', + styleUrls: ['./qa-event-notification.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [QualityAssuranceSourceDataService] +}) +/** + * Component for displaying quality assurance event notifications for an item. + */ +export class QaEventNotificationComponent { + + /** + * The item to display quality assurance event notifications for. + */ + @Input() item: Item; + + /** + * The type of alert to display for the notification. + */ + AlertTypeInfo = AlertType.Info; + + constructor( + private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService, + ) { } + + /** + * Returns an Observable of QualityAssuranceSourceObject[] for the current item. + * @returns An Observable of QualityAssuranceSourceObject[] for the current item. + * Note: sourceId is composed as: id: "sourceName:" + */ + getQualityAssuranceSources$(): Observable { + const findListTopicOptions: FindListOptions = { + searchParams: [new RequestParam('target', this.item.uuid)] + }; + return this.qualityAssuranceSourceDataService.getSourcesByTarget(findListTopicOptions) + .pipe( + getFirstCompletedRemoteData(), + getRemoteDataPayload(), + getPaginatedListPayload(), + ); + } +} diff --git a/src/app/my-dspace-page/my-dspace-page.component.html b/src/app/my-dspace-page/my-dspace-page.component.html index c5e49b0cec..70bcf1b7bc 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.html +++ b/src/app/my-dspace-page/my-dspace-page.component.html @@ -1,4 +1,5 @@
+
diff --git a/src/app/my-dspace-page/my-dspace-page.module.ts b/src/app/my-dspace-page/my-dspace-page.module.ts index b75806cec7..60726bacc4 100644 --- a/src/app/my-dspace-page/my-dspace-page.module.ts +++ b/src/app/my-dspace-page/my-dspace-page.module.ts @@ -16,6 +16,7 @@ import { ThemedMyDSpacePageComponent } from './themed-my-dspace-page.component'; import { SearchModule } from '../shared/search/search.module'; import { UploadModule } from '../shared/upload/upload.module'; import { SuggestionNotificationsModule } from '../suggestion-notifications/suggestion-notifications.module'; +import { MyDspaceQaEventsNotificationsComponent } from './my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component'; const DECLARATIONS = [ MyDSpacePageComponent, @@ -23,7 +24,8 @@ const DECLARATIONS = [ MyDSpaceNewSubmissionComponent, CollectionSelectorComponent, MyDSpaceNewSubmissionDropdownComponent, - MyDSpaceNewExternalDropdownComponent + MyDSpaceNewExternalDropdownComponent, + MyDspaceQaEventsNotificationsComponent, ]; @NgModule({ diff --git a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html new file mode 100644 index 0000000000..baf90fdf53 --- /dev/null +++ b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.html @@ -0,0 +1,28 @@ + + +
+ +
+
+ {{ + "mydspace.qa-event-notification.check.notification-info" + | translate : { num: source.totalEvents } + }} +
+ +
+
+
+
diff --git a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.scss b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.scss new file mode 100644 index 0000000000..ab33b46fca --- /dev/null +++ b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.scss @@ -0,0 +1,8 @@ + +.source-logo { + max-height: var(--ds-header-logo-height); +} + +.sections-gap { + gap: 1rem; +} diff --git a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.spec.ts b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.spec.ts new file mode 100644 index 0000000000..177dd92fd0 --- /dev/null +++ b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MyDspaceQaEventsNotificationsComponent } from './my-dspace-qa-events-notifications.component'; + +describe('MyDspaceQaEventsNotificationsComponent', () => { + let component: MyDspaceQaEventsNotificationsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ MyDspaceQaEventsNotificationsComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MyDspaceQaEventsNotificationsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.ts b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.ts new file mode 100644 index 0000000000..9992ec9ff8 --- /dev/null +++ b/src/app/my-dspace-page/my-dspace-qa-events-notifications/my-dspace-qa-events-notifications.component.ts @@ -0,0 +1,44 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { QualityAssuranceSourceDataService } from '../../core/suggestion-notifications/qa/source/quality-assurance-source-data.service'; +import { getFirstCompletedRemoteData, getPaginatedListPayload, getRemoteDataPayload } from '../../core/shared/operators'; +import { Observable, of, tap } from 'rxjs'; +import { QualityAssuranceSourceObject } from 'src/app/core/suggestion-notifications/qa/models/quality-assurance-source.model'; + +@Component({ + selector: 'ds-my-dspace-qa-events-notifications', + templateUrl: './my-dspace-qa-events-notifications.component.html', + styleUrls: ['./my-dspace-qa-events-notifications.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MyDspaceQaEventsNotificationsComponent implements OnInit { + + /** + * An Observable that emits an array of QualityAssuranceSourceObject. + */ + sources$: Observable = of([]); + + constructor(private qualityAssuranceSourceDataService: QualityAssuranceSourceDataService) { } + + ngOnInit(): void { + this.getSources(); + } + + /** + * Retrieves the sources for Quality Assurance. + * @returns An Observable of the sources for Quality Assurance. + * @throws An error if the retrieval of Quality Assurance sources fails. + */ + getSources() { + this.sources$ = this.qualityAssuranceSourceDataService.getSources() + .pipe( + getFirstCompletedRemoteData(), + tap((rd) => { + if (rd.hasFailed) { + throw new Error('Can\'t retrieve Quality Assurance sources'); + } + }), + getRemoteDataPayload(), + getPaginatedListPayload(), + ); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0f7871f7f9..6c9cf1c3b3 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -284,6 +284,7 @@ import { } from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component'; import { NgxPaginationModule } from 'ngx-pagination'; +import { SplitPipe } from './utils/split.pipe'; const MODULES = [ CommonModule, @@ -323,7 +324,8 @@ const PIPES = [ ObjNgFor, BrowserOnlyPipe, MarkdownPipe, - ShortNumberPipe + ShortNumberPipe, + SplitPipe, ]; const COMPONENTS = [ diff --git a/src/app/shared/utils/split.pipe.ts b/src/app/shared/utils/split.pipe.ts new file mode 100644 index 0000000000..4da1b1323e --- /dev/null +++ b/src/app/shared/utils/split.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'dsSplit' +}) +export class SplitPipe implements PipeTransform { + + transform(value: string, separator: string): string[] { + return value.split(separator); + } + +} diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts index 3c8b4f8f38..6d96795ea3 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.component.ts @@ -60,6 +60,12 @@ export class QualityAssuranceTopicsComponent implements OnInit { */ public sourceId: string; + /** + * This property represents a targetId (item-id) which is used to retrive a topic + * @type {string} + */ + public targetId: string; + /** * Initialize the component variables. * @param {PaginationService} paginationService @@ -80,7 +86,9 @@ export class QualityAssuranceTopicsComponent implements OnInit { */ ngOnInit(): void { this.sourceId = this.activatedRoute.snapshot.paramMap.get('sourceId'); + this.targetId = this.activatedRoute.snapshot.paramMap.get('targetId'); this.qualityAssuranceTopicsService.setSourceId(this.sourceId); + this.qualityAssuranceTopicsService.setTargetId(this.targetId); this.topics$ = this.notificationsStateService.getQualityAssuranceTopics(); this.totalElements$ = this.notificationsStateService.getQualityAssuranceTopicsTotals(); } diff --git a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts index 6820791dff..c94ffe72d4 100644 --- a/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts +++ b/src/app/suggestion-notifications/qa/topics/quality-assurance-topics.service.ts @@ -13,6 +13,7 @@ import { import { RequestParam } from '../../../core/cache/models/request-param.model'; import { FindListOptions } from '../../../core/data/find-list-options.model'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; +import { hasValue } from '../../../shared/empty.util'; /** * The service handling all Quality Assurance topic requests to the REST service. @@ -33,6 +34,11 @@ export class QualityAssuranceTopicsService { */ sourceId: string; + /** + * targetId used to get topics + */ + targetId: string; + /** * Return the list of Quality Assurance topics managing pagination and errors. * @@ -53,6 +59,10 @@ export class QualityAssuranceTopicsService { searchParams: [new RequestParam('source', this.sourceId)] }; + if (hasValue(this.targetId)) { + findListOptions.searchParams.push(new RequestParam('target', this.targetId)); + } + return this.qualityAssuranceTopicRestService.getTopics(findListOptions).pipe( getFirstCompletedRemoteData(), map((rd: RemoteData>) => { @@ -72,4 +82,12 @@ export class QualityAssuranceTopicsService { setSourceId(sourceId: string) { this.sourceId = sourceId; } + + /** + * set targetId which is used to get topics + * @param targetId string + */ + setTargetId(targetId: string) { + this.targetId = targetId; + } } diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index edc88e3e9b..fd887d742c 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -2480,6 +2480,14 @@ "item.truncatable-part.show-less": "Collapse", + "item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + + "item.qa-event-notification-info.check.button": "Check", + + "mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + + "mydspace.qa-event-notification-info.check.button": "Check", + "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", "workflow-item.search.result.delete-supervision.modal.info": "Are you sure you want to delete Supervision Order", diff --git a/src/assets/i18n/it.json5 b/src/assets/i18n/it.json5 index 9fa58062b8..0606fa8032 100644 --- a/src/assets/i18n/it.json5 +++ b/src/assets/i18n/it.json5 @@ -3723,6 +3723,22 @@ // "item.truncatable-part.show-less": "Collapse", "item.truncatable-part.show-less": "Riduci", + // "item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + // TODO New key - Add a translation + "item.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + + // "item.qa-event-notification-info.check.button": "Check", + // TODO New key - Add a translation + "item.qa-event-notification-info.check.button": "Check", + + // "mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + // TODO New key - Add a translation + "mydspace.qa-event-notification.check.notification-info": "There are {{num}} pending review to check", + + // "mydspace.qa-event-notification-info.check.button": "Check", + // TODO New key - Add a translation + "mydspace.qa-event-notification-info.check.button": "Check", + // "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", // TODO New key - Add a translation "workflow-item.search.result.delete-supervision.modal.header": "Delete Supervision Order", diff --git a/src/assets/images/qa-coar-notify-logo.png b/src/assets/images/qa-coar-notify-logo.png new file mode 100644 index 0000000000..0ba021dfd2 Binary files /dev/null and b/src/assets/images/qa-coar-notify-logo.png differ diff --git a/src/assets/images/qa-openaire-logo.png b/src/assets/images/qa-openaire-logo.png new file mode 100644 index 0000000000..359fd73b84 Binary files /dev/null and b/src/assets/images/qa-openaire-logo.png differ