mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Add statistics pages
This commit is contained in:
@@ -20,6 +20,8 @@ import {
|
||||
COLLECTION_CREATE_PATH
|
||||
} from './collection-page-routing-paths';
|
||||
import { CollectionPageAdministratorGuard } from './collection-page-administrator.guard';
|
||||
import { MenuItemType } from '../shared/menu/initial-menus-state';
|
||||
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -69,7 +71,21 @@ import { CollectionPageAdministratorGuard } from './collection-page-administrato
|
||||
pathMatch: 'full',
|
||||
canActivate: [AuthenticatedGuard]
|
||||
}
|
||||
]
|
||||
],
|
||||
data: {
|
||||
menu: {
|
||||
public: [{
|
||||
id: 'statistics',
|
||||
active: true,
|
||||
visible: true,
|
||||
model: {
|
||||
type: MenuItemType.LINK,
|
||||
text: 'menu.section.statistics',
|
||||
link: 'statistics/collections/:id/',
|
||||
} as LinkMenuItemModel,
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
],
|
||||
|
@@ -12,6 +12,8 @@ import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.servi
|
||||
import { LinkService } from '../core/cache/builders/link.service';
|
||||
import { COMMUNITY_EDIT_PATH, COMMUNITY_CREATE_PATH } from './community-page-routing-paths';
|
||||
import { CommunityPageAdministratorGuard } from './community-page-administrator.guard';
|
||||
import { MenuItemType } from '../shared/menu/initial-menus-state';
|
||||
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -45,7 +47,21 @@ import { CommunityPageAdministratorGuard } from './community-page-administrator.
|
||||
component: CommunityPageComponent,
|
||||
pathMatch: 'full',
|
||||
}
|
||||
]
|
||||
],
|
||||
data: {
|
||||
menu: {
|
||||
public: [{
|
||||
id: 'statistics',
|
||||
active: true,
|
||||
visible: true,
|
||||
model: {
|
||||
type: MenuItemType.LINK,
|
||||
text: 'menu.section.statistics',
|
||||
link: 'statistics/communities/:id/',
|
||||
} as LinkMenuItemModel,
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
],
|
||||
|
@@ -3,6 +3,8 @@ import { RouterModule } from '@angular/router';
|
||||
|
||||
import { HomePageComponent } from './home-page.component';
|
||||
import { HomePageResolver } from './home-page.resolver';
|
||||
import { MenuItemType } from '../shared/menu/initial-menus-state';
|
||||
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -11,7 +13,21 @@ import { HomePageResolver } from './home-page.resolver';
|
||||
path: '',
|
||||
component: HomePageComponent,
|
||||
pathMatch: 'full',
|
||||
data: {title: 'home.title'},
|
||||
data: {
|
||||
title: 'home.title',
|
||||
menu: {
|
||||
public: [{
|
||||
id: 'statistics',
|
||||
active: true,
|
||||
visible: true,
|
||||
model: {
|
||||
type: MenuItemType.LINK,
|
||||
text: 'menu.section.statistics',
|
||||
link: 'statistics',
|
||||
} as LinkMenuItemModel,
|
||||
}],
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
site: HomePageResolver
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ import { LinkService } from '../core/cache/builders/link.service';
|
||||
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
|
||||
import { UPLOAD_BITSTREAM_PATH, ITEM_EDIT_PATH } from './item-page-routing-paths';
|
||||
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
|
||||
import { MenuItemType } from '../shared/menu/initial-menus-state';
|
||||
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -43,6 +45,20 @@ import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
|
||||
canActivate: [AuthenticatedGuard]
|
||||
}
|
||||
],
|
||||
data: {
|
||||
menu: {
|
||||
public: [{
|
||||
id: 'statistics',
|
||||
active: true,
|
||||
visible: true,
|
||||
model: {
|
||||
type: MenuItemType.LINK,
|
||||
text: 'menu.section.statistics',
|
||||
link: 'statistics/items/:id/',
|
||||
} as LinkMenuItemModel,
|
||||
}],
|
||||
},
|
||||
},
|
||||
}
|
||||
])
|
||||
],
|
||||
|
@@ -0,0 +1,109 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CollectionStatisticsPageComponent } from './collection-statistics-page.component';
|
||||
import { StatisticsTableComponent } from '../statistics-table/statistics-table.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
|
||||
describe('CollectionStatisticsPageComponent', () => {
|
||||
|
||||
let component: CollectionStatisticsPageComponent;
|
||||
let de: DebugElement;
|
||||
let fixture: ComponentFixture<CollectionStatisticsPageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
||||
const activatedRoute = {
|
||||
data: observableOf({
|
||||
scope: new RemoteData(
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
undefined,
|
||||
Object.assign(new Collection(), {
|
||||
id: 'collection_id',
|
||||
}),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
const router = {
|
||||
};
|
||||
|
||||
const usageReportService = {
|
||||
getStatistic: (scope, type) => undefined,
|
||||
};
|
||||
|
||||
spyOn(usageReportService, 'getStatistic').and.callFake(
|
||||
(scope, type) => observableOf(
|
||||
Object.assign(
|
||||
new UsageReport(), {
|
||||
id: `${scope}-${type}-report`,
|
||||
points: [],
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const nameService = {
|
||||
getName: () => observableOf('test dso name'),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [
|
||||
CollectionStatisticsPageComponent,
|
||||
StatisticsTableComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: UsageReportService, useValue: usageReportService },
|
||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||
{ provide: DSONameService, useValue: nameService },
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CollectionStatisticsPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should resolve to the correct collection', () => {
|
||||
expect(de.query(By.css('.header')).nativeElement.id)
|
||||
.toEqual('collection_id');
|
||||
});
|
||||
|
||||
it('should show a statistics table for each usage report', () => {
|
||||
expect(de.query(By.css('ds-statistics-table.collection_id-TotalVisits-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.collection_id-TotalVisitsPerMonth-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.collection_id-TopCountries-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.collection_id-TopCities-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,41 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { StatisticsPageComponent } from '../statistics-page/statistics-page.component';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { ActivatedRoute , Router} from '@angular/router';
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Component representing the statistics page for a collection.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-collection-statistics-page',
|
||||
templateUrl: '../statistics-page/statistics-page.component.html',
|
||||
styleUrls: ['./collection-statistics-page.component.scss']
|
||||
})
|
||||
export class CollectionStatisticsPageComponent extends StatisticsPageComponent<Collection> {
|
||||
|
||||
/**
|
||||
* The report types to show on this statistics page.
|
||||
*/
|
||||
types: string[] = [
|
||||
'TotalVisits',
|
||||
'TotalVisitsPerMonth',
|
||||
'TopCountries',
|
||||
'TopCities',
|
||||
];
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected usageReportService: UsageReportService,
|
||||
protected nameService: DSONameService,
|
||||
) {
|
||||
super(
|
||||
route,
|
||||
router,
|
||||
usageReportService,
|
||||
nameService,
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CommunityStatisticsPageComponent } from './community-statistics-page.component';
|
||||
import { StatisticsTableComponent } from '../statistics-table/statistics-table.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
|
||||
describe('CommunityStatisticsPageComponent', () => {
|
||||
|
||||
let component: CommunityStatisticsPageComponent;
|
||||
let de: DebugElement;
|
||||
let fixture: ComponentFixture<CommunityStatisticsPageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
||||
const activatedRoute = {
|
||||
data: observableOf({
|
||||
scope: new RemoteData(
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
undefined,
|
||||
Object.assign(new Community(), {
|
||||
id: 'community_id',
|
||||
}),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
const router = {
|
||||
};
|
||||
|
||||
const usageReportService = {
|
||||
getStatistic: (scope, type) => undefined,
|
||||
};
|
||||
|
||||
spyOn(usageReportService, 'getStatistic').and.callFake(
|
||||
(scope, type) => observableOf(
|
||||
Object.assign(
|
||||
new UsageReport(), {
|
||||
id: `${scope}-${type}-report`,
|
||||
points: [],
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const nameService = {
|
||||
getName: () => observableOf('test dso name'),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [
|
||||
CommunityStatisticsPageComponent,
|
||||
StatisticsTableComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: UsageReportService, useValue: usageReportService },
|
||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||
{ provide: DSONameService, useValue: nameService },
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CommunityStatisticsPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should resolve to the correct community', () => {
|
||||
expect(de.query(By.css('.header')).nativeElement.id)
|
||||
.toEqual('community_id');
|
||||
});
|
||||
|
||||
it('should show a statistics table for each usage report', () => {
|
||||
expect(de.query(By.css('ds-statistics-table.community_id-TotalVisits-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.community_id-TotalVisitsPerMonth-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.community_id-TopCountries-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.community_id-TopCities-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,41 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { StatisticsPageComponent } from '../statistics-page/statistics-page.component';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Component representing the statistics page for a community.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-community-statistics-page',
|
||||
templateUrl: '../statistics-page/statistics-page.component.html',
|
||||
styleUrls: ['./community-statistics-page.component.scss']
|
||||
})
|
||||
export class CommunityStatisticsPageComponent extends StatisticsPageComponent<Community> {
|
||||
|
||||
/**
|
||||
* The report types to show on this statistics page.
|
||||
*/
|
||||
types: string[] = [
|
||||
'TotalVisits',
|
||||
'TotalVisitsPerMonth',
|
||||
'TopCountries',
|
||||
'TopCities',
|
||||
];
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected usageReportService: UsageReportService,
|
||||
protected nameService: DSONameService,
|
||||
) {
|
||||
super(
|
||||
route,
|
||||
router,
|
||||
usageReportService,
|
||||
nameService,
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ItemStatisticsPageComponent } from './item-statistics-page.component';
|
||||
import { StatisticsTableComponent } from '../statistics-table/statistics-table.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
|
||||
describe('ItemStatisticsPageComponent', () => {
|
||||
|
||||
let component: ItemStatisticsPageComponent;
|
||||
let de: DebugElement;
|
||||
let fixture: ComponentFixture<ItemStatisticsPageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
||||
const activatedRoute = {
|
||||
data: observableOf({
|
||||
scope: new RemoteData(
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
undefined,
|
||||
Object.assign(new Item(), {
|
||||
id: 'item_id',
|
||||
}),
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
const router = {
|
||||
};
|
||||
|
||||
const usageReportService = {
|
||||
getStatistic: (scope, type) => undefined,
|
||||
};
|
||||
|
||||
spyOn(usageReportService, 'getStatistic').and.callFake(
|
||||
(scope, type) => observableOf(
|
||||
Object.assign(
|
||||
new UsageReport(), {
|
||||
id: `${scope}-${type}-report`,
|
||||
points: [],
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const nameService = {
|
||||
getName: () => observableOf('test dso name'),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [
|
||||
ItemStatisticsPageComponent,
|
||||
StatisticsTableComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: UsageReportService, useValue: usageReportService },
|
||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||
{ provide: DSONameService, useValue: nameService },
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ItemStatisticsPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should resolve to the correct item', () => {
|
||||
expect(de.query(By.css('.header')).nativeElement.id)
|
||||
.toEqual('item_id');
|
||||
});
|
||||
|
||||
it('should show a statistics table for each usage report', () => {
|
||||
expect(de.query(By.css('ds-statistics-table.item_id-TotalVisits-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.item_id-TotalVisitsPerMonth-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.item_id-TotalDownloads-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.item_id-TopCountries-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
expect(de.query(By.css('ds-statistics-table.item_id-TopCities-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,42 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { StatisticsPageComponent } from '../statistics-page/statistics-page.component';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Component representing the statistics page for an item.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-item-statistics-page',
|
||||
templateUrl: '../statistics-page/statistics-page.component.html',
|
||||
styleUrls: ['./item-statistics-page.component.scss']
|
||||
})
|
||||
export class ItemStatisticsPageComponent extends StatisticsPageComponent<Item> {
|
||||
|
||||
/**
|
||||
* The report types to show on this statistics page.
|
||||
*/
|
||||
types: string[] = [
|
||||
'TotalVisits',
|
||||
'TotalVisitsPerMonth',
|
||||
'TotalDownloads',
|
||||
'TopCountries',
|
||||
'TopCities',
|
||||
];
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected usageReportService: UsageReportService,
|
||||
protected nameService: DSONameService,
|
||||
) {
|
||||
super(
|
||||
route,
|
||||
router,
|
||||
usageReportService,
|
||||
nameService,
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { SiteStatisticsPageComponent } from './site-statistics-page.component';
|
||||
import { StatisticsTableComponent } from '../statistics-table/statistics-table.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { Site } from '../../core/shared/site.model';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { SiteDataService } from '../../core/data/site-data.service';
|
||||
|
||||
describe('SiteStatisticsPageComponent', () => {
|
||||
|
||||
let component: SiteStatisticsPageComponent;
|
||||
let de: DebugElement;
|
||||
let fixture: ComponentFixture<SiteStatisticsPageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
||||
const activatedRoute = {
|
||||
};
|
||||
|
||||
const router = {
|
||||
};
|
||||
|
||||
const usageReportService = {
|
||||
searchStatistics: () => observableOf([
|
||||
Object.assign(
|
||||
new UsageReport(), {
|
||||
id: `site_id-TotalVisits-report`,
|
||||
points: [],
|
||||
}
|
||||
),
|
||||
]),
|
||||
};
|
||||
|
||||
const nameService = {
|
||||
getName: () => observableOf('test dso name'),
|
||||
};
|
||||
|
||||
const siteService = {
|
||||
find: () => observableOf(Object.assign(new Site(), {
|
||||
id: 'site_id',
|
||||
_links: {
|
||||
self: {
|
||||
href: 'test_site_link',
|
||||
},
|
||||
},
|
||||
}))
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [
|
||||
SiteStatisticsPageComponent,
|
||||
StatisticsTableComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: activatedRoute },
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: UsageReportService, useValue: usageReportService },
|
||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||
{ provide: DSONameService, useValue: nameService },
|
||||
{ provide: SiteDataService, useValue: siteService },
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SiteStatisticsPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should resolve to the correct site', () => {
|
||||
expect(de.query(By.css('.header')).nativeElement.id)
|
||||
.toEqual('site_id');
|
||||
});
|
||||
|
||||
it('should show a statistics table for each usage report', () => {
|
||||
expect(de.query(By.css('ds-statistics-table.site_id-TotalVisits-report')).nativeElement)
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,53 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { StatisticsPageComponent } from '../statistics-page/statistics-page.component';
|
||||
import { SiteDataService } from '../../core/data/site-data.service';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Site } from '../../core/shared/site.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
|
||||
/**
|
||||
* Component representing the site-wide statistics page.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-site-statistics-page',
|
||||
templateUrl: '../statistics-page/statistics-page.component.html',
|
||||
styleUrls: ['./site-statistics-page.component.scss']
|
||||
})
|
||||
export class SiteStatisticsPageComponent extends StatisticsPageComponent<Site> {
|
||||
|
||||
/**
|
||||
* The report types to show on this statistics page.
|
||||
*/
|
||||
types: string[] = [
|
||||
'TotalVisits',
|
||||
];
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected usageReportService: UsageReportService,
|
||||
protected nameService: DSONameService,
|
||||
protected siteService: SiteDataService,
|
||||
) {
|
||||
super(
|
||||
route,
|
||||
router,
|
||||
usageReportService,
|
||||
nameService,
|
||||
);
|
||||
}
|
||||
|
||||
protected getScope$() {
|
||||
return this.siteService.find();
|
||||
}
|
||||
|
||||
protected getReports$() {
|
||||
return this.scope$.pipe(
|
||||
switchMap((scope) =>
|
||||
this.usageReportService.searchStatistics(scope._links.self.href, 0, 10),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
81
src/app/+statistics-page/statistics-page-routing.module.ts
Normal file
81
src/app/+statistics-page/statistics-page-routing.module.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||
import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service';
|
||||
import { StatisticsPageModule } from './statistics-page.module';
|
||||
import { SiteStatisticsPageComponent } from './site-statistics-page/site-statistics-page.component';
|
||||
import { ItemPageResolver } from '../+item-page/item-page.resolver';
|
||||
import { ItemStatisticsPageComponent } from './item-statistics-page/item-statistics-page.component';
|
||||
import { CollectionPageResolver } from '../+collection-page/collection-page.resolver';
|
||||
import { CollectionStatisticsPageComponent } from './collection-statistics-page/collection-statistics-page.component';
|
||||
import { CommunityPageResolver } from '../+community-page/community-page.resolver';
|
||||
import { CommunityStatisticsPageComponent } from './community-statistics-page/community-statistics-page.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
StatisticsPageModule,
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
resolve: {
|
||||
breadcrumb: I18nBreadcrumbResolver
|
||||
},
|
||||
data: {
|
||||
title: 'statistics.title',
|
||||
breadcrumbKey: 'statistics'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: SiteStatisticsPageComponent,
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: `items/:id`,
|
||||
resolve: {
|
||||
scope: ItemPageResolver,
|
||||
breadcrumb: I18nBreadcrumbResolver
|
||||
},
|
||||
data: {
|
||||
title: 'statistics.title',
|
||||
breadcrumbKey: 'statistics'
|
||||
},
|
||||
component: ItemStatisticsPageComponent,
|
||||
},
|
||||
{
|
||||
path: `collections/:id`,
|
||||
resolve: {
|
||||
scope: CollectionPageResolver,
|
||||
breadcrumb: I18nBreadcrumbResolver
|
||||
},
|
||||
data: {
|
||||
title: 'statistics.title',
|
||||
breadcrumbKey: 'statistics'
|
||||
},
|
||||
component: CollectionStatisticsPageComponent,
|
||||
},
|
||||
{
|
||||
path: `communities/:id`,
|
||||
resolve: {
|
||||
scope: CommunityPageResolver,
|
||||
breadcrumb: I18nBreadcrumbResolver
|
||||
},
|
||||
data: {
|
||||
title: 'statistics.title',
|
||||
breadcrumbKey: 'statistics'
|
||||
},
|
||||
component: CommunityStatisticsPageComponent,
|
||||
},
|
||||
]
|
||||
)
|
||||
],
|
||||
providers: [
|
||||
I18nBreadcrumbResolver,
|
||||
I18nBreadcrumbsService,
|
||||
CollectionPageResolver,
|
||||
CommunityPageResolver,
|
||||
]
|
||||
})
|
||||
export class StatisticsPageRoutingModule {
|
||||
}
|
39
src/app/+statistics-page/statistics-page.module.ts
Normal file
39
src/app/+statistics-page/statistics-page.module.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CoreModule } from '../core/core.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { StatisticsModule } from '../statistics/statistics.module';
|
||||
import { UsageReportService } from '../core/submission/usage-report-data.service';
|
||||
import { SiteStatisticsPageComponent } from './site-statistics-page/site-statistics-page.component';
|
||||
import { StatisticsTableComponent } from './statistics-table/statistics-table.component';
|
||||
import { ItemStatisticsPageComponent } from './item-statistics-page/item-statistics-page.component';
|
||||
import { CollectionStatisticsPageComponent } from './collection-statistics-page/collection-statistics-page.component';
|
||||
import { CommunityStatisticsPageComponent } from './community-statistics-page/community-statistics-page.component';
|
||||
|
||||
const components = [
|
||||
StatisticsTableComponent,
|
||||
SiteStatisticsPageComponent,
|
||||
ItemStatisticsPageComponent,
|
||||
CollectionStatisticsPageComponent,
|
||||
CommunityStatisticsPageComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
CoreModule.forRoot(),
|
||||
StatisticsModule.forRoot()
|
||||
],
|
||||
declarations: components,
|
||||
providers: [
|
||||
UsageReportService,
|
||||
],
|
||||
exports: components
|
||||
})
|
||||
|
||||
/**
|
||||
* This module handles all components and pipes that are necessary for the search page
|
||||
*/
|
||||
export class StatisticsPageModule {
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
<div class="container">
|
||||
|
||||
<ng-container *ngVar="(scope$ | async) as scope">
|
||||
<h2 *ngIf="scope"
|
||||
class="header"
|
||||
id="{{ scope.id }}">
|
||||
{{ 'statistics.header' | translate: { scope: getName(scope) } }}
|
||||
</h2>
|
||||
</ng-container>
|
||||
|
||||
<ds-statistics-table *ngFor="let report of reports$ | async"
|
||||
[report]="report"
|
||||
class="m-2 {{ report.id }}">
|
||||
</ds-statistics-table>
|
||||
|
||||
</div>
|
@@ -0,0 +1,77 @@
|
||||
import { OnInit } from '@angular/core';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { UsageReportService } from '../../core/submission/usage-report-data.service';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData, redirectToPageNotFoundOn404 } from '../../core/shared/operators';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Class representing an abstract statistics page component.
|
||||
*/
|
||||
export abstract class StatisticsPageComponent<T extends DSpaceObject> implements OnInit {
|
||||
|
||||
/**
|
||||
* The scope dso for this statistics page, as an Observable.
|
||||
*/
|
||||
scope$: Observable<DSpaceObject>;
|
||||
|
||||
/**
|
||||
* The report types to show on this statistics page.
|
||||
*/
|
||||
types: string[];
|
||||
|
||||
/**
|
||||
* The usage report types to show on this statistics page, as an Observable list.
|
||||
*/
|
||||
reports$: Observable<UsageReport[]>;
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected usageReportService: UsageReportService,
|
||||
protected nameService: DSONameService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.scope$ = this.getScope$();
|
||||
this.reports$ = this.getReports$();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope dso for this statistics page, as an Observable.
|
||||
*/
|
||||
protected getScope$(): Observable<DSpaceObject> {
|
||||
return this.route.data.pipe(
|
||||
map((data) => data.scope as RemoteData<T>),
|
||||
redirectToPageNotFoundOn404(this.router),
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage reports for this statistics page, as an Observable list
|
||||
*/
|
||||
protected getReports$(): Observable<UsageReport[]> {
|
||||
return this.scope$.pipe(
|
||||
switchMap((scope) =>
|
||||
combineLatest(
|
||||
this.types.map((type) => this.usageReportService.getStatistic(scope.id, type))
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the scope dso.
|
||||
* @param scope the scope dso to get the name for
|
||||
*/
|
||||
getName(scope: DSpaceObject): string {
|
||||
return this.nameService.getName(scope);
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<div *ngIf="hasData"
|
||||
class="m-1">
|
||||
|
||||
<h3 class="m-1">
|
||||
{{ 'statistics.table.title.' + report.reportType | translate }}
|
||||
</h3>
|
||||
|
||||
<table class="table table-striped">
|
||||
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"
|
||||
*ngFor="let header of headers"
|
||||
class="{{header}}-header">
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr *ngFor="let point of report.points"
|
||||
class="{{point.id}}-data">
|
||||
<th scope="row">
|
||||
{{ getLabel(point) | async }}
|
||||
</th>
|
||||
<td *ngFor="let header of headers"
|
||||
class="{{point.id}}-{{header}}-data">
|
||||
{{ point.values[header] }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
@@ -0,0 +1,8 @@
|
||||
th, td {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
td {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StatisticsTableComponent } from './statistics-table.component';
|
||||
import { UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
describe('StatisticsTableComponent', () => {
|
||||
|
||||
let component: StatisticsTableComponent;
|
||||
let de: DebugElement;
|
||||
let fixture: ComponentFixture<StatisticsTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
declarations: [
|
||||
StatisticsTableComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: DSpaceObjectDataService, useValue: {} },
|
||||
{ provide: DSONameService, useValue: {} },
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StatisticsTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
de = fixture.debugElement;
|
||||
component.report = Object.assign(new UsageReport(), {
|
||||
points: [],
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when the storage report is empty', () => {
|
||||
|
||||
it ('should not display a table', () => {
|
||||
expect(de.query(By.css('table'))).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the storage report has data', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
component.report = Object.assign(new UsageReport(), {
|
||||
points: [
|
||||
{
|
||||
id: 'item_1',
|
||||
values: {
|
||||
views: 7,
|
||||
downloads: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'item_2',
|
||||
values: {
|
||||
views: 8,
|
||||
downloads: 8,
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
component.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it ('should display a table with the correct data', () => {
|
||||
|
||||
expect(de.query(By.css('table'))).toBeTruthy();
|
||||
|
||||
expect(de.query(By.css('th.views-header')).nativeElement.innerText)
|
||||
.toEqual('views');
|
||||
expect(de.query(By.css('th.downloads-header')).nativeElement.innerText)
|
||||
.toEqual('downloads');
|
||||
|
||||
expect(de.query(By.css('td.item_1-views-data')).nativeElement.innerText)
|
||||
.toEqual('7');
|
||||
expect(de.query(By.css('td.item_1-downloads-data')).nativeElement.innerText)
|
||||
.toEqual('4');
|
||||
expect(de.query(By.css('td.item_2-views-data')).nativeElement.innerText)
|
||||
.toEqual('8');
|
||||
expect(de.query(By.css('td.item_2-downloads-data')).nativeElement.innerText)
|
||||
.toEqual('8');
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,67 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Point, UsageReport } from '../../core/statistics/models/usage-report.model';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators';
|
||||
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
|
||||
|
||||
/**
|
||||
* Component representing a statistics table for a given usage report.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-statistics-table',
|
||||
templateUrl: './statistics-table.component.html',
|
||||
styleUrls: ['./statistics-table.component.scss']
|
||||
})
|
||||
export class StatisticsTableComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The usage report to display a statistics table for
|
||||
*/
|
||||
@Input()
|
||||
report: UsageReport;
|
||||
|
||||
/**
|
||||
* Boolean indicating whether the usage report has data
|
||||
*/
|
||||
hasData: boolean;
|
||||
|
||||
/**
|
||||
* The table headers
|
||||
*/
|
||||
headers: string[];
|
||||
|
||||
constructor(
|
||||
protected dsoService: DSpaceObjectDataService,
|
||||
protected nameService: DSONameService,
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.hasData = this.report.points.length > 0;
|
||||
if (this.hasData) {
|
||||
this.headers = Object.keys(this.report.points[0].values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the row label to display for a statistics point.
|
||||
* @param point the statistics point to get the label for
|
||||
*/
|
||||
getLabel(point: Point): Observable<string> {
|
||||
switch (this.report.reportType) {
|
||||
case 'TotalVisits':
|
||||
return this.dsoService.findById(point.id).pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
map((item) => this.nameService.getName(item)),
|
||||
);
|
||||
case 'TopCities':
|
||||
case 'topCountries':
|
||||
default:
|
||||
return of(point.label);
|
||||
}
|
||||
}
|
||||
}
|
@@ -69,6 +69,10 @@ import { SiteRegisterGuard } from './core/data/feature-authorization/feature-aut
|
||||
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] },
|
||||
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
|
||||
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
|
||||
{
|
||||
path: 'statistics',
|
||||
loadChildren: './+statistics-page/statistics-page-routing.module#StatisticsPageRoutingModule',
|
||||
},
|
||||
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
||||
]}
|
||||
],
|
||||
|
@@ -171,6 +171,7 @@ import { EndUserAgreementCurrentUserGuard } from './end-user-agreement/end-user-
|
||||
import { EndUserAgreementCookieGuard } from './end-user-agreement/end-user-agreement-cookie.guard';
|
||||
import { EndUserAgreementService } from './end-user-agreement/end-user-agreement.service';
|
||||
import { SiteRegisterGuard } from './data/feature-authorization/feature-authorization-guard/site-register.guard';
|
||||
import { UsageReport } from './statistics/models/usage-report.model';
|
||||
|
||||
/**
|
||||
* When not in production, endpoint responses can be mocked for testing purposes
|
||||
@@ -371,7 +372,8 @@ export const models =
|
||||
Vocabulary,
|
||||
VocabularyEntry,
|
||||
VocabularyEntryDetail,
|
||||
ConfigurationProperty
|
||||
ConfigurationProperty,
|
||||
UsageReport,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
45
src/app/core/statistics/models/usage-report.model.ts
Normal file
45
src/app/core/statistics/models/usage-report.model.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||
import { typedObject } from '../../cache/builders/build-decorators';
|
||||
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
import { HALResource } from '../../shared/hal-resource.model';
|
||||
import { USAGE_REPORT } from './usage-report.resource-type';
|
||||
import { HALLink } from '../../shared/hal-link.model';
|
||||
import { deserialize, autoserializeAs } from 'cerialize';
|
||||
|
||||
@typedObject
|
||||
@inheritSerialization(HALResource)
|
||||
export class UsageReport extends HALResource {
|
||||
|
||||
static type = USAGE_REPORT;
|
||||
|
||||
/**
|
||||
* The object type
|
||||
*/
|
||||
@excludeFromEquals
|
||||
@autoserialize
|
||||
type: ResourceType;
|
||||
|
||||
@autoserialize
|
||||
id: string;
|
||||
|
||||
@autoserializeAs('report-type')
|
||||
reportType: string;
|
||||
|
||||
@autoserialize
|
||||
points: Point[];
|
||||
|
||||
@deserialize
|
||||
_links: {
|
||||
self: HALLink;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Point {
|
||||
id: string;
|
||||
label: string;
|
||||
type: string;
|
||||
values: Array<{
|
||||
views: number;
|
||||
}>;
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
import { ResourceType } from '../../shared/resource-type';
|
||||
|
||||
/**
|
||||
* The resource type for License
|
||||
*
|
||||
* Needs to be in a separate file to prevent circular
|
||||
* dependencies in webpack.
|
||||
*/
|
||||
export const USAGE_REPORT = new ResourceType('usagereport');
|
59
src/app/core/submission/usage-report-data.service.ts
Normal file
59
src/app/core/submission/usage-report-data.service.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from '../data/data.service';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||
import { USAGE_REPORT } from '../statistics/models/usage-report.resource-type';
|
||||
import { UsageReport } from '../statistics/models/usage-report.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../shared/operators';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
@dataService(USAGE_REPORT)
|
||||
export class UsageReportService extends DataService<UsageReport> {
|
||||
|
||||
protected linkPath = 'statistics/usagereports';
|
||||
|
||||
constructor(
|
||||
protected comparator: DefaultChangeAnalyzer<UsageReport>,
|
||||
protected halService: HALEndpointService,
|
||||
protected http: HttpClient,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected requestService: RequestService,
|
||||
protected store: Store<CoreState>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
getStatistic(scope: string, type: string): Observable<UsageReport> {
|
||||
return this.findById(`${scope}_${type}`).pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
);
|
||||
}
|
||||
|
||||
searchStatistics(uri: string, page: number, size: number): Observable<UsageReport[]> {
|
||||
return this.searchBy('object', {
|
||||
searchParams: [{
|
||||
fieldName: `uri`,
|
||||
fieldValue: uri,
|
||||
}],
|
||||
currentPage: page,
|
||||
elementsPerPage: size,
|
||||
}).pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
map((list) => list.page),
|
||||
);
|
||||
}
|
||||
}
|
@@ -64,19 +64,6 @@ export class NavbarComponent extends MenuComponent {
|
||||
link: `/community-list`
|
||||
} as LinkMenuItemModel
|
||||
},
|
||||
|
||||
/* Statistics */
|
||||
{
|
||||
id: 'statistics',
|
||||
active: false,
|
||||
visible: true,
|
||||
model: {
|
||||
type: MenuItemType.LINK,
|
||||
text: 'menu.section.statistics',
|
||||
link: ''
|
||||
} as LinkMenuItemModel,
|
||||
index: 2
|
||||
},
|
||||
];
|
||||
// Read the different Browse-By types from config and add them to the browse menu
|
||||
const types = environment.browseBy.types;
|
||||
|
@@ -68,13 +68,30 @@ export class MenuEffects {
|
||||
*/
|
||||
resolveRouteMenuSections(route: ActivatedRoute, menuID: MenuID): MenuSection[] {
|
||||
const data = route.snapshot.data;
|
||||
const params = route.snapshot.params;
|
||||
const last: boolean = hasNoValue(route.firstChild);
|
||||
|
||||
if (hasValue(data) && hasValue(data.menu) && hasValue(data.menu[menuID])) {
|
||||
|
||||
const menuSections = data.menu[menuID];
|
||||
[...menuSections]
|
||||
.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) {
|
||||
return [...data.menu[menuID], ...this.resolveRouteMenuSections(route.firstChild, menuID)]
|
||||
return [...menuSections, ...this.resolveRouteMenuSections(route.firstChild, menuID)]
|
||||
} else {
|
||||
return [...data.menu[menuID]];
|
||||
return [...menuSections];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2777,6 +2777,28 @@
|
||||
|
||||
|
||||
|
||||
"statistics.title": "Statistics",
|
||||
|
||||
"statistics.header": "Statistics for {{ scope }}",
|
||||
|
||||
"statistics.breadcrumbs": "Statistics",
|
||||
|
||||
"statistics.table.no-data": "No data available",
|
||||
|
||||
"statistics.table.title.TotalVisits": "Total visits",
|
||||
|
||||
"statistics.table.title.TotalVisitsPerMonth": "Total visits per month",
|
||||
|
||||
"statistics.table.title.TotalDownloads": "File Visits",
|
||||
|
||||
"statistics.table.title.TopCountries": "Top country views",
|
||||
|
||||
"statistics.table.title.TopCities": "Top city views",
|
||||
|
||||
"statistics.table.header.views": "Views",
|
||||
|
||||
|
||||
|
||||
"submission.edit.title": "Edit Submission",
|
||||
|
||||
"submission.general.cannot_submit": "You have not the privilege to make a new submission.",
|
||||
|
Reference in New Issue
Block a user