diff options
author | Chocobozzz <me@florianbigard.com> | 2023-02-15 15:53:40 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-02-15 16:08:32 +0100 |
commit | f6cf8e8d8e9bc61dac266886c873613bb715936d (patch) | |
tree | e5fb73f19ff933f8d816faf0755a8085b085605c /client/src/app/+about | |
parent | 343d1395df2e07ea9eb3540724c9fd689e617cb8 (diff) | |
download | PeerTube-f6cf8e8d8e9bc61dac266886c873613bb715936d.tar.gz PeerTube-f6cf8e8d8e9bc61dac266886c873613bb715936d.tar.zst PeerTube-f6cf8e8d8e9bc61dac266886c873613bb715936d.zip |
Fix stats anchor link
Diffstat (limited to 'client/src/app/+about')
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' | |||
4 | import { Notifier, ServerService } from '@app/core' | 4 | import { Notifier, ServerService } from '@app/core' |
5 | import { AboutHTML } from '@app/shared/shared-instance' | 5 | import { AboutHTML } from '@app/shared/shared-instance' |
6 | import { copyToClipboard } from '@root-helpers/utils' | 6 | import { copyToClipboard } from '@root-helpers/utils' |
7 | import { HTMLServerConfig } from '@shared/models/server' | 7 | import { HTMLServerConfig, ServerStats } from '@shared/models/server' |
8 | import { ResolverData } from './about-instance.resolver' | 8 | import { ResolverData } from './about-instance.resolver' |
9 | import { ContactAdminModalComponent } from './contact-admin-modal.component' | 9 | import { 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 @@ | |||
1 | import { forkJoin } from 'rxjs' | 1 | import { forkJoin, Observable } from 'rxjs' |
2 | import { map, switchMap } from 'rxjs/operators' | 2 | import { map, switchMap } from 'rxjs/operators' |
3 | import { Injectable } from '@angular/core' | 3 | import { Injectable } from '@angular/core' |
4 | import { Resolve } from '@angular/router' | 4 | import { Resolve } from '@angular/router' |
5 | import { ServerService } from '@app/core' | ||
5 | import { CustomMarkupService } from '@app/shared/shared-custom-markup' | 6 | import { CustomMarkupService } from '@app/shared/shared-custom-markup' |
6 | import { AboutHTML, InstanceService } from '@app/shared/shared-instance' | 7 | import { AboutHTML, InstanceService } from '@app/shared/shared-instance' |
7 | import { About } from '@shared/models/server' | 8 | import { About, ServerStats } from '@shared/models/server' |
8 | 9 | ||
9 | export type ResolverData = { | 10 | export 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 | |||
4 | h3 { | ||
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 | |||
29 | my-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 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | import { 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 | }) | ||
9 | export 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 | |||
3 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' | 3 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' |
4 | import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' | 4 | import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' |
5 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' | 5 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' |
6 | import { InstanceStatisticsComponent } from '@app/+about/about-instance/instance-statistics.component' | ||
6 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' | 7 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' |
7 | import { SharedCustomMarkupModule } from '@app/shared/shared-custom-markup' | 8 | import { SharedCustomMarkupModule } from '@app/shared/shared-custom-markup' |
8 | import { SharedFormModule } from '@app/shared/shared-forms' | 9 | import { 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: [ |