Skip to content

Commit 5f9104d

Browse files
author
Andrea Barbasso
committed
[DSC-2050] use queryParam for item reports
1 parent 8ed08ce commit 5f9104d

7 files changed

Lines changed: 196 additions & 8 deletions

File tree

src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99

1010
import { APP_CONFIG } from '../../../../../config/app-config.interface';
1111
import { environment } from '../../../../../environments/environment.test';
12+
import { Metric } from '../../../../core/shared/metric.model';
1213
import { metricEmbeddedDownload } from '../../../../cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metrics/cris-layout-metrics-box.component.spec';
1314
import { TranslateLoaderMock } from '../../../mocks/translate-loader.mock';
1415
import { MetricEmbeddedDownloadComponent } from './metric-embedded-download.component';
@@ -42,4 +43,25 @@ describe('MetricEmbeddedDownloadComponent', () => {
4243
it('should create', () => {
4344
expect(component).toBeTruthy();
4445
});
46+
47+
it('should append reportType to href if href is defined and does not contain query parameters', () => {
48+
component.href = 'http://example.com';
49+
component.metric = {} as Metric;
50+
component.ngOnInit();
51+
expect(component.href).toBe('http://example.com?reportType=TotalDownloads');
52+
});
53+
54+
it('should append reportType to href if href is defined and contains query parameters', () => {
55+
component.href = 'http://example.com?param=value';
56+
component.metric = {} as Metric;
57+
component.ngOnInit();
58+
expect(component.href).toBe('http://example.com?param=value&reportType=TotalDownloads');
59+
});
60+
61+
it('should not modify href if href is not defined', () => {
62+
component.href = undefined;
63+
component.metric = {} as Metric;
64+
component.ngOnInit();
65+
expect(component.href).toBeUndefined();
66+
});
4567
});

src/app/shared/metric/metric-embedded/metric-embedded-download/metric-embedded-download.component.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { NgIf } from '@angular/common';
22
import {
33
Component,
4+
OnInit,
45
Renderer2,
56
} from '@angular/core';
67
import { TranslateModule } from '@ngx-translate/core';
78

89
import { RedirectWithHrefDirective } from '../../../../directives/redirect/redirect-href.directive';
910
import { BaseEmbeddedHtmlMetricComponent } from '../base-embedded-html-metric.component';
1011

12+
export const METRIC_TYPE_DOWNLOAD = 'TotalDownloads';
1113
@Component({
1214
selector: 'ds-metric-embedded-download',
1315
templateUrl: './metric-embedded-download.component.html',
@@ -19,10 +21,17 @@ import { BaseEmbeddedHtmlMetricComponent } from '../base-embedded-html-metric.co
1921
TranslateModule,
2022
],
2123
})
22-
export class MetricEmbeddedDownloadComponent extends BaseEmbeddedHtmlMetricComponent {
24+
export class MetricEmbeddedDownloadComponent extends BaseEmbeddedHtmlMetricComponent implements OnInit {
2325

2426
constructor(protected render: Renderer2) {
2527
super(render);
2628
}
2729

30+
ngOnInit() {
31+
super.ngOnInit();
32+
if (this.href) {
33+
this.href += (this.href.includes('?') ? '&' : '?') + 'reportType=' + METRIC_TYPE_DOWNLOAD;
34+
}
35+
}
36+
2837
}

src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.spec.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ import {
1414
TranslateLoader,
1515
TranslateModule,
1616
} from '@ngx-translate/core';
17-
import { of as observableOf } from 'rxjs';
17+
import {
18+
of as observableOf,
19+
of,
20+
} from 'rxjs';
1821

1922
import { AuthService } from '../../core/auth/auth.service';
2023
import { SiteDataService } from '../../core/data/site-data.service';
2124
import { DSpaceObject } from '../../core/shared/dspace-object.model';
25+
import { UsageReport } from '../../core/statistics/models/usage-report.model';
2226
import { StatisticsState } from '../../core/statistics/statistics.reducer';
2327
import { StatisticsCategoriesDataService } from '../../core/statistics/statistics-categories-data.service';
2428
import { UsageReportDataService } from '../../core/statistics/usage-report-data.service';
@@ -141,4 +145,71 @@ describe('CrisStatisticsPageComponent', () => {
141145
expect(renderedCategories[0].nativeElement.classList.contains('active')).toBe(true);
142146
});
143147

148+
it('should set selectedReportId to the first report id if no reportType query param is present', () => {
149+
const category = { id: 'category1' };
150+
const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }];
151+
spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[]));
152+
spyOn(component, 'getReportId').and.returnValue(of(null));
153+
spyOn(component, 'getCategoryId').and.returnValue(of(null));
154+
spyOn(component, 'setStatisticsState');
155+
156+
component.getUserReports(category);
157+
158+
expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1');
159+
expect(component.selectedReportId).toBe('report1');
160+
});
161+
162+
it('should set selectedReportId to the report id matching the reportType query param', () => {
163+
const category = { id: 'category1' };
164+
const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }];
165+
spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[]));
166+
spyOn(component, 'getReportId').and.returnValue(of(null));
167+
spyOn(component, 'getCategoryId').and.returnValue(of(null));
168+
spyOn(component, 'setStatisticsState');
169+
170+
component.getUserReports(category, 'type2');
171+
172+
expect(component.setStatisticsState).toHaveBeenCalledWith('report2', 'category1');
173+
expect(component.selectedReportId).toBe('report2');
174+
});
175+
176+
it('should set selectedReportId to the first report id if reportType query param does not match any report', () => {
177+
const category = { id: 'category1' };
178+
const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }];
179+
spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[]));
180+
spyOn(component, 'getReportId').and.returnValue(of(null));
181+
spyOn(component, 'getCategoryId').and.returnValue(of(null));
182+
spyOn(component, 'setStatisticsState');
183+
184+
component.getUserReports(category, 'non_existing_type');
185+
186+
expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1');
187+
expect(component.selectedReportId).toBe('report1');
188+
});
189+
190+
it('should set selectedReportId and categoryId from state if they exist', () => {
191+
const category = { id: 'category1' };
192+
const reports = [{ id: 'report1', reportType: 'type1' }, { id: 'report2', reportType: 'type2' }];
193+
spyOn(component, 'getReports$').and.returnValue(of(reports as UsageReport[]));
194+
spyOn(component, 'getReportId').and.returnValue(of('report1'));
195+
spyOn(component, 'getCategoryId').and.returnValue(of('category1'));
196+
spyOn(component, 'setStatisticsState');
197+
198+
component.getUserReports(category);
199+
200+
expect(component.setStatisticsState).toHaveBeenCalledWith('report1', 'category1');
201+
});
202+
203+
it('should handle null category gracefully', () => {
204+
spyOn(component, 'getReports$').and.returnValue(of([]));
205+
spyOn(component, 'getReportId').and.returnValue(of(null));
206+
spyOn(component, 'getCategoryId').and.returnValue(of(null));
207+
spyOn(component, 'setStatisticsState');
208+
209+
component.getUserReports(null);
210+
211+
expect(component.setStatisticsState).not.toHaveBeenCalled();
212+
expect(component.selectedReportId).toBeUndefined();
213+
});
214+
144215
});

src/app/statistics-page/cris-statistics-page/cris-statistics-page.component.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,9 @@ export class CrisStatisticsPageComponent implements OnInit, OnDestroy {
239239
/**
240240
* Get the user reports for the specific category.
241241
* @param category the that is being selected
242+
* @param reportType
242243
*/
243-
getUserReports(category) {
244+
getUserReports(category, reportType = this.route?.snapshot?.queryParams?.reportType) {
244245
this.reports$ =
245246
of(category)
246247
.pipe(
@@ -250,8 +251,15 @@ export class CrisStatisticsPageComponent implements OnInit, OnDestroy {
250251
this.reports$, this.getReportId(), this.getCategoryId(),
251252
]).subscribe(([report, reportId, categoryId]) => {
252253
if (!reportId && !categoryId) {
253-
this.setStatisticsState(report[0].id, category.id);
254-
this.selectedReportId = report[0].id;
254+
let reportToShowId = report[0].id;
255+
if (reportType) {
256+
const newReport = report.find((r) => r.reportType === reportType)?.id;
257+
if (newReport) {
258+
reportToShowId = newReport;
259+
}
260+
}
261+
this.setStatisticsState(reportToShowId, category.id);
262+
this.selectedReportId = reportToShowId;
255263
} else {
256264
this.setStatisticsState(reportId, categoryId);
257265
}

src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ <h2>{{'statistics.reports.title' | translate}}</h2>
1010
<ul class="nav nav-pills mb-2">
1111
<li class="nav-item mr-3" *ngFor="let report of (reports | dsFilterMap : false)">
1212
<a class="nav-link" [ngClass]="{'active' : !!selectedReport && selectedReport.id === report.id}"
13-
routerLink="./" (click)="$event.preventDefault();changeReport(report)">
13+
href="#"
14+
(click)="$event.preventDefault();$event.stopPropagation();changeReport(report)">
1415
{{'statistics.table.' + categoryType + '.title.' + report.reportType | translate}}
1516
</a>
1617
</li>

src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.spec.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,67 @@ describe('StatisticsChartComponent', () => {
197197
expect(de.query(By.css('.container'))).toBeNull();
198198
});
199199

200-
it('after reports check if container of pills are truthly', () => {
200+
it('after reports check if container of pills are truthy', () => {
201201
component.reports = reports;
202202
fixture.detectChanges();
203203
expect(de.query(By.css('.container'))).toBeTruthy();
204204
});
205205

206+
it('should set selectedReport to the report matching selectedReportId', () => {
207+
component.reports = reports;
208+
component.selectedReportId = '1911e8a4-6939-490c-b58b-a5d70f8d91fb_TotalVisits';
209+
component.ngOnInit();
210+
expect(component.selectedReport.id).toBe('1911e8a4-6939-490c-b58b-a5d70f8d91fb_TotalVisits');
211+
});
212+
213+
it('should set selectedReport to the first report if selectedReportId does not match any report', () => {
214+
component.reports = reports;
215+
component.selectedReportId = 'non_existing_id';
216+
component.ngOnInit();
217+
expect(component.selectedReport.id).toBe('1911e8a4-6939-490c-b58b-a5d70f8d91fb_TotalVisits');
218+
});
219+
220+
it('should emit changeReportEvent with the first report id if selectedReportId does not match any report', () => {
221+
spyOn(component.changeReportEvent, 'emit');
222+
component.reports = reports;
223+
component.selectedReportId = 'non_existing_id';
224+
component.ngOnInit();
225+
expect(component.changeReportEvent.emit).toHaveBeenCalledWith('1911e8a4-6939-490c-b58b-a5d70f8d91fb_TotalVisits');
226+
});
227+
228+
it('should call addQueryParams with the reportType of the selected report', () => {
229+
spyOn(component, 'addQueryParams');
230+
component.reports = reports;
231+
component.selectedReportId = '1911e8a4-6939-490c-b58b-a5d70f8d91fb_TotalVisits';
232+
component.ngOnInit();
233+
expect(component.addQueryParams).toHaveBeenCalledWith('TotalVisits');
234+
});
235+
236+
it('should not set selectedReport if reports is undefined', () => {
237+
component.reports = undefined;
238+
component.ngOnInit();
239+
expect(component.selectedReport).toBeUndefined();
240+
});
241+
242+
it('should not set selectedReport if reports is empty', () => {
243+
component.reports = [];
244+
component.ngOnInit();
245+
expect(component.selectedReport).toBeUndefined();
246+
});
247+
248+
it('should update selectedReport and emit changeReportEvent on changeReport', () => {
249+
spyOn(component.changeReportEvent, 'emit');
250+
const newReport = reports[1];
251+
component.changeReport(newReport);
252+
expect(component.selectedReport).toBe(newReport);
253+
expect(component.changeReportEvent.emit).toHaveBeenCalledWith(newReport.id);
254+
});
255+
256+
it('should call addQueryParams with the reportType of the new report on changeReport', () => {
257+
spyOn(component, 'addQueryParams');
258+
const newReport = reports[1];
259+
component.changeReport(newReport);
260+
expect(component.addQueryParams).toHaveBeenCalledWith(newReport.reportType);
261+
});
262+
206263
});

src/app/statistics-page/cris-statistics-page/statistics-chart/statistics-chart.component.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import {
2+
Location,
23
NgClass,
34
NgFor,
45
NgIf,
56
} from '@angular/common';
67
import {
78
Component,
89
EventEmitter,
10+
inject,
911
Input,
1012
OnInit,
1113
Output,
1214
} from '@angular/core';
13-
import { RouterLink } from '@angular/router';
15+
import {
16+
ActivatedRoute,
17+
Router,
18+
RouterLink,
19+
} from '@angular/router';
1420
import { TranslateModule } from '@ngx-translate/core';
1521

1622
import { StatisticsCategory } from '../../../core/statistics/models/statistics-category.model';
@@ -71,6 +77,10 @@ export class StatisticsChartComponent implements OnInit {
7177
*/
7278
@Output() changeReportEvent = new EventEmitter<string>();
7379

80+
router = inject(Router);
81+
activatedRoute = inject(ActivatedRoute);
82+
location = inject(Location);
83+
7484
/**
7585
* Requests the current set values for this chart
7686
* If the chart config is open by default OR the chart has at least one value, the chart should be initially expanded
@@ -85,6 +95,7 @@ export class StatisticsChartComponent implements OnInit {
8595
this.selectedReport = this.reports[0];
8696
this.changeReportEvent.emit(this.reports[0].id);
8797
}
98+
this.addQueryParams(this.selectedReport.reportType);
8899
}
89100
}
90101

@@ -95,6 +106,15 @@ export class StatisticsChartComponent implements OnInit {
95106
changeReport(report) {
96107
this.selectedReport = report;
97108
this.changeReportEvent.emit(report.id);
109+
this.addQueryParams(report.reportType);
110+
}
111+
112+
addQueryParams(reportType: string) {
113+
this.location.go(this.router.createUrlTree([], {
114+
queryParams: { reportType },
115+
queryParamsHandling: 'merge',
116+
relativeTo: this.activatedRoute,
117+
}).toString());
98118
}
99119

100120
}

0 commit comments

Comments
 (0)