aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+about
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+about')
-rw-r--r--client/src/app/+about/about-instance/about-instance.component.html4
-rw-r--r--client/src/app/+about/about-instance/about-instance.component.ts8
-rw-r--r--client/src/app/+about/about-instance/about-instance.resolver.ts62
-rw-r--r--client/src/app/+about/about-instance/instance-statistics.component.html101
-rw-r--r--client/src/app/+about/about-instance/instance-statistics.component.scss39
-rw-r--r--client/src/app/+about/about-instance/instance-statistics.component.ts11
-rw-r--r--client/src/app/+about/about.module.ts8
7 files changed, 209 insertions, 24 deletions
diff --git a/client/src/app/+about/about-instance/about-instance.component.html b/client/src/app/+about/about-instance/about-instance.component.html
index fdd6157e5..f602ec1b5 100644
--- a/client/src/app/+about/about-instance/about-instance.component.html
+++ b/client/src/app/+about/about-instance/about-instance.component.html
@@ -210,6 +210,7 @@
210 210
211 <div class="col" myPluginSelector pluginSelectorId="about-instance-statistics"> 211 <div class="col" myPluginSelector pluginSelectorId="about-instance-statistics">
212 <div class="anchor" id="statistics"></div> 212 <div class="anchor" id="statistics"></div>
213
213 <a 214 <a
214 class="anchor-link" 215 class="anchor-link"
215 routerLink="/about/instance" 216 routerLink="/about/instance"
@@ -218,7 +219,8 @@
218 (click)="onClickCopyLink(anchorLink)"> 219 (click)="onClickCopyLink(anchorLink)">
219 <h2 i18n class="middle-title">STATISTICS</h2> 220 <h2 i18n class="middle-title">STATISTICS</h2>
220 </a> 221 </a>
221 <my-instance-statistics></my-instance-statistics> 222
223 <my-instance-statistics [serverStats]="serverStats"></my-instance-statistics>
222 </div> 224 </div>
223</div> 225</div>
224 226
diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts
index e1501d7de..fc5214215 100644
--- a/client/src/app/+about/about-instance/about-instance.component.ts
+++ b/client/src/app/+about/about-instance/about-instance.component.ts
@@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'
4import { Notifier, ServerService } from '@app/core' 4import { Notifier, ServerService } from '@app/core'
5import { AboutHTML } from '@app/shared/shared-instance' 5import { AboutHTML } from '@app/shared/shared-instance'
6import { copyToClipboard } from '@root-helpers/utils' 6import { copyToClipboard } from '@root-helpers/utils'
7import { HTMLServerConfig } from '@shared/models/server' 7import { HTMLServerConfig, ServerStats } from '@shared/models/server'
8import { ResolverData } from './about-instance.resolver' 8import { ResolverData } from './about-instance.resolver'
9import { ContactAdminModalComponent } from './contact-admin-modal.component' 9import { ContactAdminModalComponent } from './contact-admin-modal.component'
10 10
@@ -26,6 +26,8 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
26 26
27 initialized = false 27 initialized = false
28 28
29 serverStats: ServerStats
30
29 private serverConfig: HTMLServerConfig 31 private serverConfig: HTMLServerConfig
30 32
31 private lastScrollHash: string 33 private lastScrollHash: string
@@ -50,7 +52,9 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
50 } 52 }
51 53
52 ngOnInit () { 54 ngOnInit () {
53 const { about, languages, categories, aboutHTML, descriptionElement }: ResolverData = this.route.snapshot.data.instanceData 55 const { about, languages, categories, aboutHTML, descriptionElement, serverStats }: ResolverData = this.route.snapshot.data.instanceData
56
57 this.serverStats = serverStats
54 58
55 this.aboutHTML = aboutHTML 59 this.aboutHTML = aboutHTML
56 this.descriptionElement = descriptionElement 60 this.descriptionElement = descriptionElement
diff --git a/client/src/app/+about/about-instance/about-instance.resolver.ts b/client/src/app/+about/about-instance/about-instance.resolver.ts
index 8818fc582..94388e71d 100644
--- a/client/src/app/+about/about-instance/about-instance.resolver.ts
+++ b/client/src/app/+about/about-instance/about-instance.resolver.ts
@@ -1,12 +1,14 @@
1import { forkJoin } from 'rxjs' 1import { forkJoin, Observable } from 'rxjs'
2import { map, switchMap } from 'rxjs/operators' 2import { map, switchMap } from 'rxjs/operators'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { Resolve } from '@angular/router' 4import { Resolve } from '@angular/router'
5import { ServerService } from '@app/core'
5import { CustomMarkupService } from '@app/shared/shared-custom-markup' 6import { CustomMarkupService } from '@app/shared/shared-custom-markup'
6import { AboutHTML, InstanceService } from '@app/shared/shared-instance' 7import { AboutHTML, InstanceService } from '@app/shared/shared-instance'
7import { About } from '@shared/models/server' 8import { About, ServerStats } from '@shared/models/server'
8 9
9export type ResolverData = { 10export type ResolverData = {
11 serverStats: ServerStats
10 about: About 12 about: About
11 languages: string[] 13 languages: string[]
12 categories: string[] 14 categories: string[]
@@ -19,25 +21,47 @@ export class AboutInstanceResolver implements Resolve<any> {
19 21
20 constructor ( 22 constructor (
21 private instanceService: InstanceService, 23 private instanceService: InstanceService,
22 private customMarkupService: CustomMarkupService 24 private customMarkupService: CustomMarkupService,
23 25 private serverService: ServerService
24 ) {} 26 ) {}
25 27
26 resolve () { 28 resolve (): Observable<ResolverData> {
29 return forkJoin([
30 this.buildInstanceAboutObservable(),
31 this.buildInstanceStatsObservable()
32 ]).pipe(
33 map(([
34 [ about, languages, categories, aboutHTML, { rootElement } ],
35 serverStats
36 ]) => {
37 return {
38 serverStats,
39 about,
40 languages,
41 categories,
42 aboutHTML,
43 descriptionElement: rootElement
44 }
45 })
46 )
47 }
48
49 private buildInstanceAboutObservable () {
27 return this.instanceService.getAbout() 50 return this.instanceService.getAbout()
28 .pipe( 51 .pipe(
29 switchMap(about => { 52 switchMap(about => {
30 return forkJoin([ 53 return forkJoin([
31 Promise.resolve(about), 54 Promise.resolve(about),
32 this.instanceService.buildTranslatedLanguages(about), 55 this.instanceService.buildTranslatedLanguages(about),
33 this.instanceService.buildTranslatedCategories(about), 56 this.instanceService.buildTranslatedCategories(about),
34 this.instanceService.buildHtml(about), 57 this.instanceService.buildHtml(about),
35 this.customMarkupService.buildElement(about.instance.description) 58 this.customMarkupService.buildElement(about.instance.description)
36 ]) 59 ])
37 }), 60 })
38 map(([ about, languages, categories, aboutHTML, { rootElement } ]) => { 61 )
39 return { about, languages, categories, aboutHTML, descriptionElement: rootElement } as ResolverData 62 }
40 }) 63
41 ) 64 private buildInstanceStatsObservable () {
65 return this.serverService.getServerStats()
42 } 66 }
43} 67}
diff --git a/client/src/app/+about/about-instance/instance-statistics.component.html b/client/src/app/+about/about-instance/instance-statistics.component.html
new file mode 100644
index 000000000..68b209990
--- /dev/null
+++ b/client/src/app/+about/about-instance/instance-statistics.component.html
@@ -0,0 +1,101 @@
1<p i18n *ngIf="null === serverStats">Loading instance statistics...</p>
2
3<section *ngIf="null !== serverStats">
4 <h3 i18n>By users on this instance</h3>
5
6 <div class="row">
7 <div class="col-6 col-lg-4 col-xl-3">
8 <div class="card stat">
9 <div class="card-body">
10 <p class="stat-value">{{ serverStats.totalUsers | number }}</p>
11 <p class="stat-label" i18n>users</p>
12 </div>
13 <my-global-icon iconName="user"></my-global-icon>
14 </div>
15 </div>
16
17 <div class="col-6 col-lg-4 col-xl-3">
18 <div class="card stat">
19 <div class="card-body">
20 <p class="stat-value">{{ serverStats.totalLocalVideos | number }}</p>
21 <p class="stat-label" i18n>videos</p>
22 </div>
23 <my-global-icon iconName="film"></my-global-icon>
24 </div>
25 </div>
26
27 <div class="col-6 col-lg-4 col-xl-3">
28 <div class="card stat">
29 <div class="card-body">
30 <p class="stat-value">{{ serverStats.totalLocalVideoViews | number }}</p>
31 <p class="stat-label" i18n>views</p>
32 </div>
33 <my-global-icon iconName="eye-open"></my-global-icon>
34 </div>
35 </div>
36
37 <div class="col-6 col-lg-4 col-xl-3">
38 <div class="card stat">
39 <div class="card-body">
40 <p class="stat-value">{{ serverStats.totalLocalVideoComments | number }}</p>
41 <p class="stat-label" i18n>comments</p>
42 </div>
43 <my-global-icon iconName="message-circle"></my-global-icon>
44 </div>
45 </div>
46
47 <div class="col-6 col-lg-4 col-xl-3">
48 <div class="card stat">
49 <div class="card-body">
50 <p class="stat-value">{{ serverStats.totalLocalVideoFilesSize | bytes:1 }}</p>
51 <p class="stat-label" i18n>hosted video</p>
52 </div>
53 <my-global-icon iconName="home"></my-global-icon>
54 </div>
55 </div>
56 </div>
57
58 <h3 i18n>In this instance federation</h3>
59
60 <div class="row">
61 <div class="col-6 col-lg-4 col-xl-3">
62 <div class="card stat">
63 <div class="card-body">
64 <p class="stat-value">{{ serverStats.totalVideos | number }}</p>
65 <p class="stat-label" i18n>videos</p>
66 </div>
67 <my-global-icon iconName="film"></my-global-icon>
68 </div>
69 </div>
70
71 <div class="col-6 col-lg-4 col-xl-3">
72 <div class="card stat">
73 <div class="card-body">
74 <p class="stat-value">{{ serverStats.totalVideoComments | number }}</p>
75 <p class="stat-label" i18n>comments</p>
76 </div>
77 <my-global-icon iconName="message-circle"></my-global-icon>
78 </div>
79 </div>
80
81 <div class="col-6 col-lg-4 col-xl-3">
82 <div class="card stat">
83 <div class="card-body">
84 <p class="stat-value">{{ serverStats.totalInstanceFollowers | number }}</p>
85 <p class="stat-label" i18n>followers</p>
86 </div>
87 <my-global-icon iconName="share"></my-global-icon>
88 </div>
89 </div>
90
91 <div class="col-6 col-lg-4 col-xl-3">
92 <div class="card stat">
93 <div class="card-body">
94 <p class="stat-value">{{ serverStats.totalInstanceFollowing | number }}</p>
95 <p class="stat-label" i18n>following</p>
96 </div>
97 <my-global-icon iconName="globe"></my-global-icon>
98 </div>
99 </div>
100 </div>
101</section>
diff --git a/client/src/app/+about/about-instance/instance-statistics.component.scss b/client/src/app/+about/about-instance/instance-statistics.component.scss
new file mode 100644
index 000000000..e1d489d28
--- /dev/null
+++ b/client/src/app/+about/about-instance/instance-statistics.component.scss
@@ -0,0 +1,39 @@
1@use '_variables' as *;
2@use '_mixins' as *;
3
4h3 {
5 font-size: 1.25rem;
6}
7
8.stat {
9 text-align: center;
10 margin-bottom: 1em;
11 overflow: hidden;
12
13 .stat-value {
14 font-size: 2.25em;
15 line-height: 1em;
16 margin: 0;
17 }
18
19 .stat-label {
20 font-size: 1.15em;
21 margin: 0;
22 }
23
24 .card-body {
25 z-index: 2;
26 }
27}
28
29my-global-icon {
30 opacity: 0.12;
31 position: absolute;
32 left: 16px;
33 top: -24px;
34 width: 110px;
35
36 &.icon-bottom {
37 top: 4px;
38 }
39}
diff --git a/client/src/app/+about/about-instance/instance-statistics.component.ts b/client/src/app/+about/about-instance/instance-statistics.component.ts
new file mode 100644
index 000000000..ac6984438
--- /dev/null
+++ b/client/src/app/+about/about-instance/instance-statistics.component.ts
@@ -0,0 +1,11 @@
1import { Component, Input } from '@angular/core'
2import { ServerStats } from '@shared/models/server'
3
4@Component({
5 selector: 'my-instance-statistics',
6 templateUrl: './instance-statistics.component.html',
7 styleUrls: [ './instance-statistics.component.scss' ]
8})
9export class InstanceStatisticsComponent {
10 @Input() serverStats: ServerStats
11}
diff --git a/client/src/app/+about/about.module.ts b/client/src/app/+about/about.module.ts
index 6a3d72290..2cdfdf822 100644
--- a/client/src/app/+about/about.module.ts
+++ b/client/src/app/+about/about.module.ts
@@ -3,6 +3,7 @@ import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.c
3import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' 3import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
4import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' 4import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver'
5import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' 5import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
6import { InstanceStatisticsComponent } from '@app/+about/about-instance/instance-statistics.component'
6import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' 7import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
7import { SharedCustomMarkupModule } from '@app/shared/shared-custom-markup' 8import { SharedCustomMarkupModule } from '@app/shared/shared-custom-markup'
8import { SharedFormModule } from '@app/shared/shared-forms' 9import { SharedFormModule } from '@app/shared/shared-forms'
@@ -25,10 +26,13 @@ import { AboutComponent } from './about.component'
25 26
26 declarations: [ 27 declarations: [
27 AboutComponent, 28 AboutComponent,
29
28 AboutInstanceComponent, 30 AboutInstanceComponent,
31 ContactAdminModalComponent,
32 InstanceStatisticsComponent,
33
29 AboutPeertubeComponent, 34 AboutPeertubeComponent,
30 AboutFollowsComponent, 35 AboutFollowsComponent
31 ContactAdminModalComponent
32 ], 36 ],
33 37
34 exports: [ 38 exports: [