1 |
61381
|
k.triantaf
|
import {Component, Input, Output, EventEmitter, ChangeDetectorRef} from '@angular/core';
|
2 |
|
|
import {Metrics} from '../../../utils/entities/metrics';
|
3 |
|
|
import {MetricsService} from '../../../services/metrics.service';
|
4 |
|
|
import {ErrorCodes} from '../../../utils/properties/errorCodes';
|
5 |
|
|
|
6 |
|
|
import {Subscription} from 'rxjs';
|
7 |
|
|
import {EnvProperties} from '../../../utils/properties/env-properties';
|
8 |
|
|
import {animate, state, style, transition, trigger} from "@angular/animations";
|
9 |
|
|
|
10 |
|
|
@Component({
|
11 |
|
|
selector: 'metrics',
|
12 |
|
|
styleUrls: ['metrics.component.css'],
|
13 |
|
|
template: `
|
14 |
|
|
<div *ngIf="metrics && (pageViews >0 || metrics.totalViews > 0|| metrics.totalDownloads >0)" class="metrics"
|
15 |
|
|
click-outside-or-esc (clickOutside)="close($event)"
|
16 |
|
|
id="metrics" targetId="metrics">
|
17 |
|
|
<div class="m-badge clickable" (click)="toggle($event)">
|
18 |
|
|
<img src="assets/common-assets/logo-small-usage-counts.png" loading="lazy">
|
19 |
|
|
<div class="number">{{total | number}}</div>
|
20 |
|
|
</div>
|
21 |
|
|
<div class="widget" [@widget]="state.toString()">
|
22 |
|
|
<div class="body">
|
23 |
|
|
<div [@body]="state.toString()">
|
24 |
|
|
<div *ngIf="entityType == 'projects'" class="uk-margin-bottom">
|
25 |
|
|
<i class="uk-text-center">Project metrics
|
26 |
|
|
are derived from aggregating individual research results metrics.
|
27 |
|
|
</i>
|
28 |
|
|
</div>
|
29 |
|
|
<div class="uk-child-width-1-3@m uk-grid-small uk-grid-divider uk-grid-match" uk-grid>
|
30 |
|
|
<div class="uk-text-center uk-first-column">
|
31 |
|
|
<div class="number">{{metrics.totalDownloads | number}}</div>
|
32 |
|
|
<div>Downloads</div>
|
33 |
|
|
</div>
|
34 |
|
|
<div class="uk-text-center">
|
35 |
|
|
<div class="number">{{pageViews | number}}</div>
|
36 |
|
|
<div>OpenAIRE views</div>
|
37 |
|
|
</div>
|
38 |
|
|
<div class="uk-text-center">
|
39 |
|
|
<div class="number">{{metrics.totalViews | number}}</div>
|
40 |
|
|
<div>Total views</div>
|
41 |
|
|
</div>
|
42 |
|
|
</div>
|
43 |
|
|
<div *ngIf="(metrics.totalViews > 0 && viewsFrameUrl) || (metrics.totalDownloads > 0 && downloadsFrameUrl)"
|
44 |
|
|
[@charts]="state.toString()"
|
45 |
|
|
class="charts uk-visible-toggle" tabindex="-1" uk-slider>
|
46 |
|
|
<ul class="uk-slider-items uk-child-width-1-1">
|
47 |
|
|
<li *ngIf="metrics && metrics.infos.size > 0" class="uk-overflow-auto" style="height: 200px">
|
48 |
|
|
<table
|
49 |
|
|
class="uk-table uk-table-small uk-table-striped">
|
50 |
|
|
<thead>
|
51 |
|
|
<tr>
|
52 |
|
|
<th class="uk-text-center uk-text-bold">From</th>
|
53 |
|
|
<th class="uk-text-center uk-text-bold">Views</th>
|
54 |
|
|
<th class="uk-text-center uk-text-bold">Downloads</th>
|
55 |
|
|
</tr>
|
56 |
|
|
</thead>
|
57 |
|
|
<tbody>
|
58 |
|
|
<tr *ngFor="let key of getKeys(metrics.infos)">
|
59 |
|
|
<td class="uk-text-center">
|
60 |
|
|
<a href="{{metrics.infos.get(key).url}}">
|
61 |
|
|
{{metrics.infos.get(key).name}}
|
62 |
|
|
</a>
|
63 |
|
|
</td>
|
64 |
|
|
<td class="uk-text-center">
|
65 |
|
|
{{metrics.infos.get(key).numOfViews | number}}
|
66 |
|
|
<!-- <span *ngIf="metrics.infos.get(key).numOfViews > 0 && metrics.infos.get(key).openaireViews > 0">
|
67 |
|
|
( {{metrics.infos.get(key).openaireViews | number}} from OpenAIRE )
|
68 |
|
|
</span>-->
|
69 |
|
|
</td>
|
70 |
|
|
<td class="uk-text-center">
|
71 |
|
|
{{metrics.infos.get(key).numOfDownloads | number}}
|
72 |
|
|
<!--<span *ngIf="metrics.infos.get(key).numOfDownloads > 0 && metrics.infos.get(key).openaireDownloads > 0">
|
73 |
|
|
( {{metrics.infos.get(key).openaireDownloads | number}} from OpenAIRE )
|
74 |
|
|
</span>-->
|
75 |
|
|
</td>
|
76 |
|
|
</tr>
|
77 |
|
|
</tbody>
|
78 |
|
|
</table>
|
79 |
|
|
</li>
|
80 |
|
|
<!-- remove check for datasources when with the new charts -->
|
81 |
|
|
<li *ngIf="entityType == 'datasources'" #element>
|
82 |
|
|
<i-frame *ngIf="metricsClicked && metrics.totalViews > 0 && viewsFrameUrl"
|
83 |
|
|
[height]="200"
|
84 |
|
|
[url]=viewsFrameUrl>
|
85 |
|
|
</i-frame>
|
86 |
|
|
</li>
|
87 |
|
|
<li *ngIf="entityType == 'datasources'" #element>
|
88 |
|
|
<i-frame *ngIf="metricsClicked && metrics.totalDownloads > 0 && downloadsFrameUrl"
|
89 |
|
|
[height]="200"
|
90 |
|
|
[url]=downloadsFrameUrl>
|
91 |
|
|
</i-frame>
|
92 |
|
|
</li>
|
93 |
|
|
</ul>
|
94 |
|
|
<div class="uk-text-right uk-margin-small-top">
|
95 |
|
|
<a href="#" uk-slidenav-previous uk-slider-item="previous"></a>
|
96 |
|
|
<a href="#" class="space" uk-slidenav-next uk-slider-item="next"></a>
|
97 |
|
|
</div>
|
98 |
|
|
</div>
|
99 |
|
|
</div>
|
100 |
|
|
</div>
|
101 |
|
|
<div class="footer uk-flex uk-flex-middle" [@footer]="state.toString()">
|
102 |
|
|
<span>Powered by</span>
|
103 |
|
|
<a href="https://usagecounts.openaire.eu" target="_blank">
|
104 |
|
|
<img width="120" src="assets/common-assets/logo-large-usage-counts.png" loading="lazy">
|
105 |
|
|
</a>
|
106 |
|
|
</div>
|
107 |
|
|
</div>
|
108 |
|
|
</div>
|
109 |
|
|
`,
|
110 |
|
|
animations: [
|
111 |
|
|
trigger('widget', [
|
112 |
|
|
state('-1', style({
|
113 |
|
|
width: '150px',
|
114 |
|
|
opacity: 0,
|
115 |
|
|
height: '60px',
|
116 |
|
|
})),
|
117 |
|
|
state('0', style({
|
118 |
|
|
width: '150px',
|
119 |
|
|
opacity: 0,
|
120 |
|
|
height: '60px',
|
121 |
|
|
"margin-top": '-25px'
|
122 |
|
|
})),
|
123 |
|
|
state('1', style({
|
124 |
|
|
width: '150px',
|
125 |
|
|
opacity: 1,
|
126 |
|
|
height: '60px',
|
127 |
|
|
})),
|
128 |
|
|
state('2', style({
|
129 |
|
|
width: '350px',
|
130 |
|
|
height: 'auto',
|
131 |
|
|
})),
|
132 |
|
|
state('3', style({
|
133 |
|
|
width: '350px',
|
134 |
|
|
height: 'auto',
|
135 |
|
|
})),
|
136 |
|
|
state('4', style({
|
137 |
|
|
width: '350px',
|
138 |
|
|
height: 'auto',
|
139 |
|
|
})),
|
140 |
|
|
transition('0 => 1', [
|
141 |
|
|
animate('300ms ease-out')
|
142 |
|
|
]),
|
143 |
|
|
transition('1 => 2', [
|
144 |
|
|
animate('400ms cubic-bezier(.18,.89,.56,1)')
|
145 |
|
|
])
|
146 |
|
|
]),
|
147 |
|
|
trigger('body', [
|
148 |
|
|
state('2', style({
|
149 |
|
|
opacity: 1,
|
150 |
|
|
height: 'auto',
|
151 |
|
|
})),
|
152 |
|
|
state('3', style({
|
153 |
|
|
opacity: 1,
|
154 |
|
|
height: 'auto'
|
155 |
|
|
})),
|
156 |
|
|
state('4', style({
|
157 |
|
|
opacity: 1,
|
158 |
|
|
height: 'auto'
|
159 |
|
|
})),
|
160 |
|
|
transition('* => 2', [
|
161 |
|
|
animate('400ms cubic-bezier(.18,.89,.56,1)')
|
162 |
|
|
])
|
163 |
|
|
]),
|
164 |
|
|
trigger('charts', [
|
165 |
|
|
state('3', style({
|
166 |
|
|
opacity: 1
|
167 |
|
|
})),
|
168 |
|
|
state('4', style({
|
169 |
|
|
opacity: 1
|
170 |
|
|
})),
|
171 |
|
|
transition('* => 3', [
|
172 |
|
|
animate('800ms ease-out')
|
173 |
|
|
])
|
174 |
|
|
]),
|
175 |
|
|
trigger('footer', [
|
176 |
|
|
state('4', style({
|
177 |
|
|
transform: 'translateY(0)'
|
178 |
|
|
})),
|
179 |
|
|
transition('3 => 4', [
|
180 |
|
|
animate('800ms ease-out')
|
181 |
|
|
])
|
182 |
|
|
])
|
183 |
|
|
]
|
184 |
|
|
})
|
185 |
|
|
|
186 |
|
|
export class MetricsComponent {
|
187 |
|
|
@Output() metricsResults = new EventEmitter();
|
188 |
|
|
@Input() id: string;
|
189 |
|
|
@Input() entityType: string;
|
190 |
|
|
@Input() entity: string;
|
191 |
|
|
//@Input() name: string = "";
|
192 |
|
|
@Input() pageViews: number = 0;
|
193 |
|
|
@Input() properties: EnvProperties;
|
194 |
|
|
@Input() shortView: boolean = false;
|
195 |
|
|
@Input() open = false;
|
196 |
|
|
@Input() viewsFrameUrl: string;
|
197 |
|
|
@Input() downloadsFrameUrl: string;
|
198 |
|
|
|
199 |
|
|
public metrics: Metrics;
|
200 |
|
|
public errorCodes: ErrorCodes;
|
201 |
|
|
private sub: Subscription;
|
202 |
|
|
private timeouts: any[] = [];
|
203 |
|
|
|
204 |
|
|
public metricsClicked: boolean = false;
|
205 |
|
|
|
206 |
|
|
public status: number;
|
207 |
|
|
public state: number = -1;
|
208 |
|
|
|
209 |
|
|
constructor(private metricsService: MetricsService, private cdr: ChangeDetectorRef) {
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
ngOnInit() {
|
213 |
|
|
this.errorCodes = new ErrorCodes();
|
214 |
|
|
if (typeof document !== 'undefined') {
|
215 |
|
|
this.status = this.errorCodes.LOADING;
|
216 |
|
|
this.getMetrics();
|
217 |
|
|
}
|
218 |
|
|
}
|
219 |
|
|
|
220 |
|
|
ngOnDestroy() {
|
221 |
|
|
if(this.sub) {
|
222 |
|
|
this.sub.unsubscribe();
|
223 |
|
|
}
|
224 |
|
|
}
|
225 |
|
|
|
226 |
|
|
public get total(): number {
|
227 |
|
|
return +this.pageViews + +this.metrics.totalViews + +this.metrics.totalDownloads;
|
228 |
|
|
}
|
229 |
|
|
|
230 |
|
|
private getMetrics() {
|
231 |
|
|
this.sub = this.metricsService.getMetrics(this.id, this.entityType, this.properties).subscribe(
|
232 |
|
|
data => {
|
233 |
|
|
this.metrics = data;
|
234 |
|
|
this.cdr.detectChanges();
|
235 |
|
|
this.status = this.errorCodes.DONE;
|
236 |
|
|
this.metricsResults.emit({
|
237 |
|
|
totalViews: this.metrics.totalViews,
|
238 |
|
|
totalDownloads: this.metrics.totalDownloads,
|
239 |
|
|
pageViews: this.metrics.pageViews
|
240 |
|
|
});
|
241 |
|
|
},
|
242 |
|
|
err => {
|
243 |
|
|
if (err.status == '404') {
|
244 |
|
|
this.status = this.errorCodes.NOT_FOUND;
|
245 |
|
|
} else if (err.status == '500') {
|
246 |
|
|
this.status = this.errorCodes.ERROR;
|
247 |
|
|
} else {
|
248 |
|
|
this.status = this.errorCodes.NOT_AVAILABLE;
|
249 |
|
|
}
|
250 |
|
|
this.metricsResults.emit({
|
251 |
|
|
totalViews: 0,
|
252 |
|
|
totalDownloads: 0
|
253 |
|
|
});
|
254 |
|
|
}
|
255 |
|
|
);
|
256 |
|
|
}
|
257 |
|
|
|
258 |
|
|
public close(event) {
|
259 |
|
|
if(event.value && this.state !== -1) {
|
260 |
|
|
this.timeouts.forEach(timeout => {
|
261 |
|
|
clearTimeout(timeout);
|
262 |
|
|
});
|
263 |
|
|
this.state = -1;
|
264 |
|
|
this.timeouts = [];
|
265 |
|
|
}
|
266 |
|
|
}
|
267 |
|
|
|
268 |
|
|
|
269 |
|
|
public toggle(event) {
|
270 |
|
|
this.metricsClicked = true;
|
271 |
|
|
|
272 |
|
|
event.stopPropagation();
|
273 |
|
|
if(this.state !== -1) {
|
274 |
|
|
this.timeouts.forEach(timeout => {
|
275 |
|
|
clearTimeout(timeout);
|
276 |
|
|
});
|
277 |
|
|
this.state = -1;
|
278 |
|
|
this.timeouts = [];
|
279 |
|
|
} else {
|
280 |
|
|
this.state++;
|
281 |
|
|
this.timeouts.push(setTimeout(() => {
|
282 |
|
|
this.state++;
|
283 |
|
|
this.timeouts.push(setTimeout(() => {
|
284 |
|
|
this.state++;
|
285 |
|
|
this.timeouts.push(setTimeout(() => {
|
286 |
|
|
this.state++;
|
287 |
|
|
this.timeouts.push(setTimeout(() => {
|
288 |
|
|
this.state++;
|
289 |
|
|
}, 400));
|
290 |
|
|
}, 800));
|
291 |
|
|
}, 300));
|
292 |
|
|
}, 100));
|
293 |
|
|
}
|
294 |
|
|
this.cdr.detectChanges();
|
295 |
|
|
}
|
296 |
|
|
|
297 |
|
|
public getKeys(map) {
|
298 |
|
|
return Array.from(map.keys());
|
299 |
|
|
}
|
300 |
|
|
}
|