Add statistics pages - add support for parameters in menu sections and add id params

This commit is contained in:
Samuel
2020-09-23 15:59:26 +02:00
parent e7e408dacb
commit 6ff9429bc0
8 changed files with 64 additions and 21 deletions

View File

@@ -75,7 +75,7 @@ import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
data: { data: {
menu: { menu: {
public: [{ public: [{
id: 'statistics_collection', id: 'statistics_collection_:id',
active: true, active: true,
visible: true, visible: true,
model: { model: {

View File

@@ -51,7 +51,7 @@ import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
data: { data: {
menu: { menu: {
public: [{ public: [{
id: 'statistics_community', id: 'statistics_community_:id',
active: true, active: true,
visible: true, visible: true,
model: { model: {

View File

@@ -48,7 +48,7 @@ import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
data: { data: {
menu: { menu: {
public: [{ public: [{
id: 'statistics_item', id: 'statistics_item_:id',
active: true, active: true,
visible: true, visible: true,
model: { model: {

View File

@@ -14,6 +14,7 @@ import { MenuEffects } from './menu.effects';
describe('MenuEffects', () => { describe('MenuEffects', () => {
let menuEffects: MenuEffects; let menuEffects: MenuEffects;
let routeDataMenuSection: MenuSection; let routeDataMenuSection: MenuSection;
let routeDataMenuSectionResolved: MenuSection;
let routeDataMenuChildSection: MenuSection; let routeDataMenuChildSection: MenuSection;
let toBeRemovedMenuSection: MenuSection; let toBeRemovedMenuSection: MenuSection;
let alreadyPresentMenuSection: MenuSection; let alreadyPresentMenuSection: MenuSection;
@@ -23,13 +24,23 @@ describe('MenuEffects', () => {
function init() { function init() {
routeDataMenuSection = { routeDataMenuSection = {
id: 'mockSection', id: 'mockSection_:idparam',
active: false, active: false,
visible: true, visible: true,
model: { model: {
type: MenuItemType.LINK, type: MenuItemType.LINK,
text: 'menu.section.mockSection', text: 'menu.section.mockSection',
link: '' link: 'path/:linkparam'
} as LinkMenuItemModel
};
routeDataMenuSectionResolved = {
id: 'mockSection_id_param_resolved',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.mockSection',
link: 'path/link_param_resolved'
} as LinkMenuItemModel } as LinkMenuItemModel
}; };
routeDataMenuChildSection = { routeDataMenuChildSection = {
@@ -70,6 +81,10 @@ describe('MenuEffects', () => {
menu: { menu: {
[MenuID.PUBLIC]: [routeDataMenuSection, alreadyPresentMenuSection] [MenuID.PUBLIC]: [routeDataMenuSection, alreadyPresentMenuSection]
} }
},
params: {
idparam: 'id_param_resolved',
linkparam: 'link_param_resolved',
} }
}, },
firstChild: { firstChild: {
@@ -120,7 +135,7 @@ describe('MenuEffects', () => {
}); });
expect(menuEffects.buildRouteMenuSections$).toBeObservable(expected); expect(menuEffects.buildRouteMenuSections$).toBeObservable(expected);
expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuSection); expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuSectionResolved);
expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuChildSection); expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuChildSection);
expect(menuService.addSection).not.toHaveBeenCalledWith(MenuID.PUBLIC, alreadyPresentMenuSection); expect(menuService.addSection).not.toHaveBeenCalledWith(MenuID.PUBLIC, alreadyPresentMenuSection);
expect(menuService.removeSection).toHaveBeenCalledWith(MenuID.PUBLIC, toBeRemovedMenuSection.id); expect(menuService.removeSection).toHaveBeenCalledWith(MenuID.PUBLIC, toBeRemovedMenuSection.id);

View File

@@ -19,7 +19,7 @@ export class MenuEffects {
/** /**
* On route change, build menu sections for every menu type depending on the current route data * On route change, build menu sections for every menu type depending on the current route data
*/ */
@Effect({ dispatch: false }) @Effect({dispatch: false})
public buildRouteMenuSections$: Observable<Action> = this.actions$ public buildRouteMenuSections$: Observable<Action> = this.actions$
.pipe( .pipe(
ofType(ROUTER_NAVIGATED), ofType(ROUTER_NAVIGATED),
@@ -73,20 +73,8 @@ export class MenuEffects {
if (hasValue(data) && hasValue(data.menu) && hasValue(data.menu[menuID])) { if (hasValue(data) && hasValue(data.menu) && hasValue(data.menu[menuID])) {
const menuSections = data.menu[menuID]; let menuSections: MenuSection[] | MenuSection = data.menu[menuID];
[...menuSections] menuSections = this.resolveSubstitutions(menuSections, params);
.forEach((menuSection) => {
if (hasValue(menuSection.model) && hasValue(menuSection.model.link)) {
let substitute: RegExpMatchArray;
do {
substitute = menuSection.model.link.match(/\/:(.*?)\//);
if (substitute) {
menuSection.model.link = menuSection.model.link.replace(substitute[0], `/${params[substitute[1]]}/`);
}
} while (substitute);
}
});
if (!last) { if (!last) {
return [...menuSections, ...this.resolveRouteMenuSections(route.firstChild, menuID)] return [...menuSections, ...this.resolveRouteMenuSections(route.firstChild, menuID)]
@@ -98,4 +86,30 @@ export class MenuEffects {
return !last ? this.resolveRouteMenuSections(route.firstChild, menuID) : []; return !last ? this.resolveRouteMenuSections(route.firstChild, menuID) : [];
} }
private resolveSubstitutions(object, params) {
if (typeof object === 'string') {
let match: RegExpMatchArray;
do {
match = object.match(/:(\w+)/);
if (match) {
const substitute = params[match[1]];
if (hasValue(substitute)) {
object = object.replace(match[0], `${substitute}`);
}
}
} while (match);
} else if (Array.isArray(object)) {
object.forEach((entry, index) => {
object[index] = this.resolveSubstitutions(object[index], params);
});
} else {
Object.keys(object).forEach((key) => {
object = Object.assign({}, object, {
[key]: this.resolveSubstitutions(object[key], params)
});
});
}
return object;
}
} }

View File

@@ -12,5 +12,10 @@
[report]="report" [report]="report"
class="m-2 {{ report.id }}"> class="m-2 {{ report.id }}">
</ds-statistics-table> </ds-statistics-table>
<ng-container *ngIf="!!hasData$">
<div *ngIf="!(hasData$ | async)">
{{ 'statistics.page.no-data' | translate }}
</div>
</ng-container>
</div> </div>

View File

@@ -29,6 +29,8 @@ export abstract class StatisticsPageComponent<T extends DSpaceObject> implements
*/ */
reports$: Observable<UsageReport[]>; reports$: Observable<UsageReport[]>;
hasData$: Observable<boolean>;
constructor( constructor(
protected route: ActivatedRoute, protected route: ActivatedRoute,
protected router: Router, protected router: Router,
@@ -40,6 +42,11 @@ export abstract class StatisticsPageComponent<T extends DSpaceObject> implements
ngOnInit(): void { ngOnInit(): void {
this.scope$ = this.getScope$(); this.scope$ = this.getScope$();
this.reports$ = this.getReports$(); this.reports$ = this.getReports$();
this.hasData$ = this.reports$.pipe(
map((reports) => reports.some(
(report) => report.points.length > 0
)),
);
} }
/** /**

View File

@@ -2783,6 +2783,8 @@
"statistics.breadcrumbs": "Statistics", "statistics.breadcrumbs": "Statistics",
"statistics.page.no-data": "No data available",
"statistics.table.no-data": "No data available", "statistics.table.no-data": "No data available",
"statistics.table.title.TotalVisits": "Total visits", "statistics.table.title.TotalVisits": "Total visits",