diff --git a/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.spec.ts b/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.spec.ts index fa7245fef99..d9c2f897256 100644 --- a/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.spec.ts +++ b/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.spec.ts @@ -9,6 +9,7 @@ import { import { APP_CONFIG } from '../../../../../config/app-config.interface'; import { environment } from '../../../../../environments/environment.test'; +import { Metric } from '../../../../core/shared/metric.model'; import { metricEmbeddedDownload } from '../../../../cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metrics/cris-layout-metrics-box.component.spec'; import { TranslateLoaderMock } from '../../../mocks/translate-loader.mock'; import { MetricEmbeddedDownloadComponent } from './metric-embedded-download.component'; @@ -42,4 +43,25 @@ describe('MetricEmbeddedDownloadComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should append reportType to href if href is defined and does not contain query parameters', () => { + component.href = 'http://example.com'; + component.metric = {} as Metric; + component.ngOnInit(); + expect(component.href).toBe('http://example.com?reportType=TotalDownloads'); + }); + + it('should append reportType to href if href is defined and contains query parameters', () => { + component.href = 'http://example.com?param=value'; + component.metric = {} as Metric; + component.ngOnInit(); + expect(component.href).toBe('http://example.com?param=value&reportType=TotalDownloads'); + }); + + it('should not modify href if href is not defined', () => { + component.href = undefined; + component.metric = {} as Metric; + component.ngOnInit(); + expect(component.href).toBeUndefined(); + }); }); diff --git a/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.ts b/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.ts index 3afe7d82834..b469decbd15 100644 --- a/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.ts +++ b/src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.ts @@ -1,6 +1,7 @@ import { NgIf } from '@angular/common'; import { Component, + OnInit, Renderer2, } from '@angular/core'; import { TranslateModule } from '@ngx-translate/core'; @@ -8,6 +9,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { RedirectWithHrefDirective } from '../../../../directives/redirect/redirect-href.directive'; import { BaseEmbeddedHtmlMetricComponent } from '../base-embedded-html-metric.component'; +export const METRIC_TYPE_DOWNLOAD = 'TotalDownloads'; @Component({ selector: 'ds-metric-embedded-download', templateUrl: './metric-embedded-download.component.html', @@ -19,10 +21,17 @@ import { BaseEmbeddedHtmlMetricComponent } from '../base-embedded-html-metric.co TranslateModule, ], }) -export class MetricEmbeddedDownloadComponent extends BaseEmbeddedHtmlMetricComponent { +export class MetricEmbeddedDownloadComponent extends BaseEmbeddedHtmlMetricComponent implements OnInit { constructor(protected render: Renderer2) { super(render); } + ngOnInit() { + super.ngOnInit(); + if (this.href) { + this.href += (this.href.includes('?') ? '&' : '?') + 'reportType=' + METRIC_TYPE_DOWNLOAD; + } + } + } diff --git a/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.spec.ts b/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.spec.ts index c79885d19b1..badc9c3f374 100644 --- a/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.spec.ts +++ b/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.spec.ts @@ -14,11 +14,15 @@ import { TranslateLoader, TranslateModule, } from '@ngx-translate/core'; -import { of as observableOf } from 'rxjs'; +import { + of as observableOf, + of, +} from 'rxjs'; import { AuthService } from '../../core/auth/auth.service'; import { SiteDataService } from '../../core/data/site-data.service'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { UsageReport } from '../../core/statistics/models/usage-report.model'; import { StatisticsState } from '../../core/statistics/statistics.reducer'; import { StatisticsCategoriesDataService } from '../../core/statistics/statistics-categories-data.service'; import { UsageReportDataService } from '../../core/statistics/usage-report-data.service'; @@ -141,4 +145,71 @@ describe('CrisStatisticsPageComponent', () => { expect(renderedCategories[0].nativeElement.classList.contains('active')).toBe(true); }); + it('should set selectedReportId to the first report id if no reportType query param is present', () => { + const category = { id: 'category1' }; + const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }]; + spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[])); + spyOn(component, 'getReportId').and.returnValue(of(null)); + spyOn(component, 'getCategoryId').and.returnValue(of(null)); + spyOn(component, 'setStatisticsState'); + + component.getUserReports(category); + + expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1'); + expect(component.selectedReportId).toBe('report1'); + }); + + it('should set selectedReportId to the report id matching the reportType query param', () => { + const category = { id: 'category1' }; + const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }]; + spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[])); + spyOn(component, 'getReportId').and.returnValue(of(null)); + spyOn(component, 'getCategoryId').and.returnValue(of(null)); + spyOn(component, 'setStatisticsState'); + + component.getUserReports(category, 'type2'); + + expect(component.setStatisticsState).toHaveBeenCalledWith('report2', 'category1'); + expect(component.selectedReportId).toBe('report2'); + }); + + it('should set selectedReportId to the first report id if reportType query param does not match any report', () => { + const category = { id: 'category1' }; + const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }]; + spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[])); + spyOn(component, 'getReportId').and.returnValue(of(null)); + spyOn(component, 'getCategoryId').and.returnValue(of(null)); + spyOn(component, 'setStatisticsState'); + + component.getUserReports(category, 'non_existing_type'); + + expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1'); + expect(component.selectedReportId).toBe('report1'); + }); + + it('should set selectedReportId and categoryId from state if they exist', () => { + const category = { id: 'category1' }; + const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }]; + spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[])); + spyOn(component, 'getReportId').and.returnValue(of('report1')); + spyOn(component, 'getCategoryId').and.returnValue(of('category1')); + spyOn(component, 'setStatisticsState'); + + component.getUserReports(category); + + expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1'); + }); + + it('should handle null category gracefully', () => { + spyOn(component, 'getReports$').and.returnValue(of([])); + spyOn(component, 'getReportId').and.returnValue(of(null)); + spyOn(component, 'getCategoryId').and.returnValue(of(null)); + spyOn(component, 'setStatisticsState'); + + component.getUserReports(null); + + expect(component.setStatisticsState).not.toHaveBeenCalled(); + expect(component.selectedReportId).toBeUndefined(); + }); + }); diff --git a/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.ts b/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.ts index 641bd21f06f..fb5c1661eaf 100644 --- a/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.ts +++ b/src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.ts @@ -239,8 +239,9 @@ export class CrisStatisticsPageComponent implements OnInit, OnDestroy { /** * Get the user reports for the specific category. * @param category the that is being selected + * @param reportType */ - getUserReports(category) { + getUserReports(category, reportType = this.route?.snapshot?.queryParams?.reportType) { this.reports$ = of(category) .pipe( @@ -250,8 +251,15 @@ export class CrisStatisticsPageComponent implements OnInit, OnDestroy { this.reports$, this.getReportId(), this.getCategoryId(), ]).subscribe(([report, reportId, categoryId]) => { if (!reportId && !categoryId) { - this.setStatisticsState(report[0].id, category.id); - this.selectedReportId = report[0].id; + let reportToShowId = report[0].id; + if (reportType) { + const newReport = report.find((r) => r.reportType === reportType)?.id; + if (newReport) { + reportToShowId = newReport; + } + } + this.setStatisticsState(reportToShowId, category.id); + this.selectedReportId = reportToShowId; } else { this.setStatisticsState(reportId, categoryId); } diff --git a/src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.html b/src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.html index 4f9e82bd895..e7815f4f2d0 100644 --- a/src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.html +++ b/src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.html @@ -10,7 +10,8 @@

{{'statistics.reports.title' | translate}}