aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/+about/about-instance/about-instance.component.html63
-rw-r--r--client/src/app/+my-account/my-account.component.html37
-rw-r--r--client/src/app/+my-account/my-account.component.scss15
-rw-r--r--client/src/app/+my-account/my-account.component.ts97
-rw-r--r--client/src/app/core/core.module.ts2
-rw-r--r--client/src/app/core/server/server.service.ts3
-rw-r--r--client/src/app/login/login.component.html7
-rw-r--r--client/src/app/login/login.component.ts9
-rw-r--r--client/src/app/menu/language-chooser.component.html5
-rw-r--r--client/src/app/menu/language-chooser.component.scss7
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.html18
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.scss14
-rw-r--r--client/src/app/shared/menu/top-menu-dropdown.component.ts75
-rw-r--r--client/src/app/shared/moderation/user-moderation-dropdown.component.ts44
-rw-r--r--client/src/app/shared/shared.module.ts5
-rw-r--r--client/src/app/signup/signup.component.html2
-rw-r--r--client/src/app/videos/+video-watch/modal/video-report.component.html5
-rw-r--r--client/src/app/videos/+video-watch/modal/video-report.component.scss4
-rw-r--r--client/src/app/videos/+video-watch/modal/video-report.component.ts16
19 files changed, 277 insertions, 151 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 5970cac01..37ff795f5 100644
--- a/client/src/app/+about/about-instance/about-instance.component.html
+++ b/client/src/app/+about/about-instance/about-instance.component.html
@@ -1,39 +1,48 @@
1<div i18n class="about-instance-title"> 1<div class="row">
2 About {{ instanceName }} instance 2 <div class="col-md-12 col-xl-6">
3</div> 3 <div i18n class="about-instance-title">
4 About {{ instanceName }} instance
5 </div>
4 6
5<div class="short-description"> 7 <div class="short-description">
6 <div>{{ shortDescription }}</div> 8 <div>{{ shortDescription }}</div>
7</div> 9 </div>
8 10
9<div class="description"> 11 <div class="description">
10 <div i18n class="section-title">Description</div> 12 <div i18n class="section-title">Description</div>
11 13
12 <div [innerHTML]="descriptionHTML"></div> 14 <div [innerHTML]="descriptionHTML"></div>
13</div> 15 </div>
14 16
15<div class="terms" id="terms-section"> 17 <div class="terms" id="terms-section">
16 <div i18n class="section-title">Terms</div> 18 <div i18n class="section-title">Terms</div>
17 19
18 <div [innerHTML]="termsHTML"></div> 20 <div [innerHTML]="termsHTML"></div>
19</div> 21 </div>
22
23 <div class="signup">
24 <div i18n class="section-title">Signup</div>
20 25
21<div class="signup"> 26 <div *ngIf="isSignupAllowed">
22 <div i18n class="section-title">Signup</div> 27 <ng-container i18n>User registration is allowed and</ng-container>
23 28
24 <div *ngIf="isSignupAllowed"> 29 <ng-container i18n *ngIf="userVideoQuota !== -1">
25 <ng-container i18n>User registration is allowed and</ng-container> 30 this instance provides a baseline quota of {{ userVideoQuota | bytes: 0 }} space for the videos of its users.
31 </ng-container>
26 32
27 <ng-container i18n *ngIf="userVideoQuota !== -1"> 33 <ng-container i18n *ngIf="userVideoQuota === -1">
28 this instance provides a baseline quota of {{ userVideoQuota | bytes: 0 }} space for the videos of its users. 34 this instance provides unlimited space for the videos of its users.
29 </ng-container> 35 </ng-container>
36 </div>
30 37
31 <ng-container i18n *ngIf="userVideoQuota === -1"> 38 <div i18n *ngIf="isSignupAllowed === false">
32 this instance provides unlimited space for the videos of its users. 39 User registration is currently not allowed.
33 </ng-container> 40 </div>
41 </div>
34 </div> 42 </div>
35 43
36 <div i18n *ngIf="isSignupAllowed === false"> 44 <div class="col-md-12 col-xl-6">
37 User registration is currently not allowed. 45 <label>Features found on this instance</label>
46 <my-instance-features-table></my-instance-features-table>
38 </div> 47 </div>
39</div> \ No newline at end of file 48</div>
diff --git a/client/src/app/+my-account/my-account.component.html b/client/src/app/+my-account/my-account.component.html
index 41333c25a..3999252be 100644
--- a/client/src/app/+my-account/my-account.component.html
+++ b/client/src/app/+my-account/my-account.component.html
@@ -1,40 +1,5 @@
1<div class="row"> 1<div class="row">
2 <div class="sub-menu"> 2 <my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown>
3 <a i18n routerLink="/my-account/settings" routerLinkActive="active" class="title-page">My settings</a>
4
5 <div ngbDropdown class="my-library">
6 <span role="button" class="title-page" [ngClass]="{ active: libraryLabel !== '' }" ngbDropdownToggle>
7 <ng-container i18n>My library</ng-container>
8 <ng-container *ngIf="libraryLabel"> - {{ libraryLabel }}</ng-container>
9 </span>
10
11 <div ngbDropdownMenu>
12 <a class="dropdown-item" i18n routerLink="/my-account/video-channels">My channels</a>
13
14 <a class="dropdown-item" i18n routerLink="/my-account/videos">My videos</a>
15
16 <a class="dropdown-item" i18n routerLink="/my-account/subscriptions">My subscriptions</a>
17
18 <a class="dropdown-item" *ngIf="isVideoImportEnabled()" i18n routerLink="/my-account/video-imports">My imports</a>
19 </div>
20 </div>
21
22 <div ngbDropdown class="misc">
23 <span role="button" class="title-page" [ngClass]="{ active: miscLabel !== '' }" ngbDropdownToggle>
24 <ng-container i18n>Misc</ng-container>
25 <ng-container *ngIf="miscLabel"> - {{ miscLabel }}</ng-container>
26 </span>
27
28 <div ngbDropdownMenu>
29 <a class="dropdown-item" i18n routerLink="/my-account/blocklist/accounts">Muted accounts</a>
30
31 <a class="dropdown-item" i18n routerLink="/my-account/blocklist/servers">Muted instances</a>
32
33 <a class="dropdown-item" i18n routerLink="/my-account/ownership">Ownership changes</a>
34 </div>
35 </div>
36
37 </div>
38 3
39 <div class="margin-content"> 4 <div class="margin-content">
40 <router-outlet></router-outlet> 5 <router-outlet></router-outlet>
diff --git a/client/src/app/+my-account/my-account.component.scss b/client/src/app/+my-account/my-account.component.scss
index 6243c6dcf..4f111efdf 100644
--- a/client/src/app/+my-account/my-account.component.scss
+++ b/client/src/app/+my-account/my-account.component.scss
@@ -1,14 +1,3 @@
1.my-library, .misc { 1.row {
2 span[role=button] { 2 flex-direction: column;
3 cursor: pointer;
4 }
5
6 a {
7 display: block;
8 }
9} 3}
10
11/deep/ .dropdown-toggle::after {
12 position: relative;
13 top: 2px;
14} \ No newline at end of file
diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts
index d728caf07..d9381ebfa 100644
--- a/client/src/app/+my-account/my-account.component.ts
+++ b/client/src/app/+my-account/my-account.component.ts
@@ -1,38 +1,72 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component } from '@angular/core'
2import { ServerService } from '@app/core' 2import { ServerService } from '@app/core'
3import { NavigationStart, Router } from '@angular/router'
4import { filter } from 'rxjs/operators'
5import { I18n } from '@ngx-translate/i18n-polyfill' 3import { I18n } from '@ngx-translate/i18n-polyfill'
6import { Subscription } from 'rxjs' 4import { TopMenuDropdownParam } from '@app/shared/menu/top-menu-dropdown.component'
7 5
8@Component({ 6@Component({
9 selector: 'my-my-account', 7 selector: 'my-my-account',
10 templateUrl: './my-account.component.html', 8 templateUrl: './my-account.component.html',
11 styleUrls: [ './my-account.component.scss' ] 9 styleUrls: [ './my-account.component.scss' ]
12}) 10})
13export class MyAccountComponent implements OnInit, OnDestroy { 11export class MyAccountComponent {
14 12 menuEntries: TopMenuDropdownParam[] = []
15 libraryLabel = ''
16 miscLabel = ''
17
18 private routeSub: Subscription
19 13
20 constructor ( 14 constructor (
21 private serverService: ServerService, 15 private serverService: ServerService,
22 private router: Router,
23 private i18n: I18n 16 private i18n: I18n
24 ) {} 17 ) {
18
19 const libraryEntries: TopMenuDropdownParam = {
20 label: this.i18n('My library'),
21 children: [
22 {
23 label: this.i18n('My channels'),
24 routerLink: '/my-account/videos'
25 },
26 {
27 label: this.i18n('My videos'),
28 routerLink: '/my-account/videos'
29 },
30 {
31 label: this.i18n('My subscriptions'),
32 routerLink: '/my-account/subscriptions'
33 }
34 ]
35 }
25 36
26 ngOnInit () { 37 if (this.isVideoImportEnabled()) {
27 this.updateLabels(this.router.url) 38 libraryEntries.children.push({
39 label: 'My imports',
40 routerLink: '/my-account/video-imports'
41 })
42 }
28 43
29 this.routeSub = this.router.events 44 const miscEntries: TopMenuDropdownParam = {
30 .pipe(filter(event => event instanceof NavigationStart)) 45 label: this.i18n('Misc'),
31 .subscribe((event: NavigationStart) => this.updateLabels(event.url)) 46 children: [
32 } 47 {
48 label: this.i18n('Muted accounts'),
49 routerLink: '/my-account/blocklist/accounts'
50 },
51 {
52 label: this.i18n('Muted instances'),
53 routerLink: '/my-account/blocklist/servers'
54 },
55 {
56 label: this.i18n('Ownership changes'),
57 routerLink: '/my-account/ownership'
58 }
59 ]
60 }
33 61
34 ngOnDestroy () { 62 this.menuEntries = [
35 if (this.routeSub) this.routeSub.unsubscribe() 63 {
64 label: this.i18n('My settings'),
65 routerLink: '/my-account/settings'
66 },
67 libraryEntries,
68 miscEntries
69 ]
36 } 70 }
37 71
38 isVideoImportEnabled () { 72 isVideoImportEnabled () {
@@ -41,27 +75,4 @@ export class MyAccountComponent implements OnInit, OnDestroy {
41 return importConfig.http.enabled || importConfig.torrent.enabled 75 return importConfig.http.enabled || importConfig.torrent.enabled
42 } 76 }
43 77
44 private updateLabels (url: string) {
45 const [ path ] = url.split('?')
46
47 if (path.startsWith('/my-account/video-channels')) {
48 this.libraryLabel = this.i18n('Channels')
49 } else if (path.startsWith('/my-account/videos')) {
50 this.libraryLabel = this.i18n('Videos')
51 } else if (path.startsWith('/my-account/subscriptions')) {
52 this.libraryLabel = this.i18n('Subscriptions')
53 } else if (path.startsWith('/my-account/video-imports')) {
54 this.libraryLabel = this.i18n('Video imports')
55 } else {
56 this.libraryLabel = ''
57 }
58
59 if (path.startsWith('/my-account/blocklist/accounts')) {
60 this.miscLabel = this.i18n('Muted accounts')
61 } else if (path.startsWith('/my-account/blocklist/servers')) {
62 this.miscLabel = this.i18n('Muted instances')
63 } else {
64 this.miscLabel = ''
65 }
66 }
67} 78}
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts
index df2ec696d..8a6654aa1 100644
--- a/client/src/app/core/core.module.ts
+++ b/client/src/app/core/core.module.ts
@@ -29,7 +29,7 @@ import { CheatSheetComponent } from '@app/core/hotkeys'
29 29
30 LoadingBarHttpClientModule, 30 LoadingBarHttpClientModule,
31 LoadingBarRouterModule, 31 LoadingBarRouterModule,
32 LoadingBarModule.forRoot(), 32 LoadingBarModule,
33 33
34 HotkeyModule.forRoot({ 34 HotkeyModule.forRoot({
35 cheatSheetCloseEsc: true 35 cheatSheetCloseEsc: true
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index da8bd26db..6eccb8336 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -37,6 +37,9 @@ export class ServerService {
37 css: '' 37 css: ''
38 } 38 }
39 }, 39 },
40 email: {
41 enabled: false
42 },
40 serverVersion: 'Unknown', 43 serverVersion: 'Unknown',
41 signup: { 44 signup: {
42 allowed: false, 45 allowed: false,
diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html
index 93dbed525..9b8146624 100644
--- a/client/src/app/login/login.component.html
+++ b/client/src/app/login/login.component.html
@@ -59,7 +59,12 @@
59 </div> 59 </div>
60 60
61 <div class="modal-body"> 61 <div class="modal-body">
62 <div class="form-group"> 62
63 <div *ngIf="isEmailDisabled()" class="alert alert-danger" i18n>
64 We are sorry, you cannot recover you password because your instance administrator did not configure the PeerTube email system.
65 </div>
66
67 <div class="form-group" [hidden]="isEmailDisabled()">
63 <label i18n for="forgot-password-email">Email</label> 68 <label i18n for="forgot-password-email">Email</label>
64 <input 69 <input
65 type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required 70 type="email" id="forgot-password-email" i18n-placeholder placeholder="Email address" required
diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts
index 7553e6456..212a8ff1f 100644
--- a/client/src/app/login/login.component.ts
+++ b/client/src/app/login/login.component.ts
@@ -19,7 +19,6 @@ import { Router } from '@angular/router'
19export class LoginComponent extends FormReactive implements OnInit { 19export class LoginComponent extends FormReactive implements OnInit {
20 @ViewChild('emailInput') input: ElementRef 20 @ViewChild('emailInput') input: ElementRef
21 @ViewChild('forgotPasswordModal') forgotPasswordModal: ElementRef 21 @ViewChild('forgotPasswordModal') forgotPasswordModal: ElementRef
22 @ViewChild('forgotPasswordEmailInput') forgotPasswordEmailInput: ElementRef
23 22
24 error: string = null 23 error: string = null
25 forgotPasswordEmail = '' 24 forgotPasswordEmail = ''
@@ -45,6 +44,10 @@ export class LoginComponent extends FormReactive implements OnInit {
45 return this.serverService.getConfig().signup.allowed === true 44 return this.serverService.getConfig().signup.allowed === true
46 } 45 }
47 46
47 isEmailDisabled () {
48 return this.serverService.getConfig().email.enabled === false
49 }
50
48 ngOnInit () { 51 ngOnInit () {
49 this.buildForm({ 52 this.buildForm({
50 username: this.loginValidatorsService.LOGIN_USERNAME, 53 username: this.loginValidatorsService.LOGIN_USERNAME,
@@ -96,10 +99,6 @@ export class LoginComponent extends FormReactive implements OnInit {
96 ) 99 )
97 } 100 }
98 101
99 onForgotPasswordModalShown () {
100 this.forgotPasswordEmailInput.nativeElement.focus()
101 }
102
103 openForgotPasswordModal () { 102 openForgotPasswordModal () {
104 this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal) 103 this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal)
105 } 104 }
diff --git a/client/src/app/menu/language-chooser.component.html b/client/src/app/menu/language-chooser.component.html
index c37bf2826..c79609898 100644
--- a/client/src/app/menu/language-chooser.component.html
+++ b/client/src/app/menu/language-chooser.component.html
@@ -4,6 +4,11 @@
4 <span class="close" aria-label="Close" role="button" (click)="hide()"></span> 4 <span class="close" aria-label="Close" role="button" (click)="hide()"></span>
5 </div> 5 </div>
6 6
7
8 <a i18n class="help-to-translate" target="_blank" rel="noreferrer noopener" href="https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/translation.md">
9 Help to translate PeerTube!
10 </a>
11
7 <div class="modal-body"> 12 <div class="modal-body">
8 <a *ngFor="let lang of languages" [href]="buildLanguageLink(lang)">{{ lang.label }}</a> 13 <a *ngFor="let lang of languages" [href]="buildLanguageLink(lang)">{{ lang.label }}</a>
9 </div> 14 </div>
diff --git a/client/src/app/menu/language-chooser.component.scss b/client/src/app/menu/language-chooser.component.scss
index 944e86f46..72deb3952 100644
--- a/client/src/app/menu/language-chooser.component.scss
+++ b/client/src/app/menu/language-chooser.component.scss
@@ -1,6 +1,11 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.help-to-translate {
5 @include peertube-button-link;
6 @include orange-button;
7}
8
4.modal-body { 9.modal-body {
5 text-align: center; 10 text-align: center;
6 11
@@ -9,4 +14,4 @@
9 font-size: 16px; 14 font-size: 16px;
10 margin: 15px; 15 margin: 15px;
11 } 16 }
12} \ No newline at end of file 17}
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.html b/client/src/app/shared/menu/top-menu-dropdown.component.html
new file mode 100644
index 000000000..2d6d1c4bf
--- /dev/null
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.html
@@ -0,0 +1,18 @@
1<div class="sub-menu">
2 <ng-container *ngFor="let menuEntry of menuEntries">
3
4 <a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page">{{ menuEntry.label }}</a>
5
6 <div *ngIf="!menuEntry.routerLink" ngbDropdown class="parent-entry" #dropdown="ngbDropdown" (mouseleave)="closeDropdownIfHovered(dropdown)">
7 <span (mouseenter)="openDropdownOnHover(dropdown)" role="button" class="title-page" [ngClass]="{ active: !!suffixLabels[menuEntry.label] }" ngbDropdownToggle>
8 <ng-container i18n>{{ menuEntry.label }}</ng-container>
9 <ng-container *ngIf="!!suffixLabels[menuEntry.label]"> - {{ suffixLabels[menuEntry.label] }}</ng-container>
10 </span>
11
12 <div ngbDropdownMenu>
13 <a *ngFor="let menuChild of menuEntry.children" class="dropdown-item" [routerLink]="menuChild.routerLink">{{ menuChild.label }}</a>
14 </div>
15 </div>
16
17 </ng-container>
18</div>
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.scss b/client/src/app/shared/menu/top-menu-dropdown.component.scss
new file mode 100644
index 000000000..f3ef8f814
--- /dev/null
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.scss
@@ -0,0 +1,14 @@
1.parent-entry {
2 span[role=button] {
3 cursor: pointer;
4 }
5
6 a {
7 display: block;
8 }
9}
10
11/deep/ .dropdown-toggle::after {
12 position: relative;
13 top: 2px;
14}
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.ts b/client/src/app/shared/menu/top-menu-dropdown.component.ts
new file mode 100644
index 000000000..272b721b2
--- /dev/null
+++ b/client/src/app/shared/menu/top-menu-dropdown.component.ts
@@ -0,0 +1,75 @@
1import { Component, Input, OnDestroy, OnInit } from '@angular/core'
2import { filter, take } from 'rxjs/operators'
3import { NavigationStart, Router } from '@angular/router'
4import { Subscription } from 'rxjs'
5import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
6import { drop } from 'lodash-es'
7
8export type TopMenuDropdownParam = {
9 label: string
10 routerLink?: string
11
12 children?: {
13 label: string
14 routerLink: string
15 }[]
16}
17
18@Component({
19 selector: 'my-top-menu-dropdown',
20 templateUrl: './top-menu-dropdown.component.html',
21 styleUrls: [ './top-menu-dropdown.component.scss' ]
22})
23export class TopMenuDropdownComponent implements OnInit, OnDestroy {
24 @Input() menuEntries: TopMenuDropdownParam[] = []
25
26 suffixLabels: { [ parentLabel: string ]: string }
27
28 private openedOnHover = false
29 private routeSub: Subscription
30
31 constructor (private router: Router) {}
32
33 ngOnInit () {
34 this.updateChildLabels(window.location.pathname)
35
36 this.routeSub = this.router.events
37 .pipe(filter(event => event instanceof NavigationStart))
38 .subscribe(() => this.updateChildLabels(window.location.pathname))
39 }
40
41 ngOnDestroy () {
42 if (this.routeSub) this.routeSub.unsubscribe()
43 }
44
45 openDropdownOnHover (dropdown: NgbDropdown) {
46 this.openedOnHover = true
47 dropdown.open()
48
49 // Menu was closed
50 dropdown.openChange
51 .pipe(take(1))
52 .subscribe(e => this.openedOnHover = false)
53 }
54
55 closeDropdownIfHovered (dropdown: NgbDropdown) {
56 if (this.openedOnHover === false) return
57
58 dropdown.close()
59 this.openedOnHover = false
60 }
61
62 private updateChildLabels (path: string) {
63 this.suffixLabels = {}
64
65 for (const entry of this.menuEntries) {
66 if (!entry.children) continue
67
68 for (const child of entry.children) {
69 if (path.startsWith(child.routerLink)) {
70 this.suffixLabels[entry.label] = child.label
71 }
72 }
73 }
74 }
75}
diff --git a/client/src/app/shared/moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/moderation/user-moderation-dropdown.component.ts
index d391246e0..e3c9db923 100644
--- a/client/src/app/shared/moderation/user-moderation-dropdown.component.ts
+++ b/client/src/app/shared/moderation/user-moderation-dropdown.component.ts
@@ -277,18 +277,18 @@ export class UserModerationDropdownComponent implements OnChanges {
277 }, 277 },
278 { 278 {
279 label: this.i18n('Ban'), 279 label: this.i18n('Ban'),
280 handler: ({ user }: { user: User }) => this.openBanUserModal(user), 280 handler: ({ user }) => this.openBanUserModal(user),
281 isDisplayed: ({ user }: { user: User }) => !user.blocked 281 isDisplayed: ({ user }) => !user.blocked
282 }, 282 },
283 { 283 {
284 label: this.i18n('Unban'), 284 label: this.i18n('Unban'),
285 handler: ({ user }: { user: User }) => this.unbanUser(user), 285 handler: ({ user }) => this.unbanUser(user),
286 isDisplayed: ({ user }: { user: User }) => user.blocked 286 isDisplayed: ({ user }) => user.blocked
287 }, 287 },
288 { 288 {
289 label: this.i18n('Set Email as Verified'), 289 label: this.i18n('Set Email as Verified'),
290 handler: ({ user }: { user: User }) => this.setEmailAsVerified(user), 290 handler: ({ user }) => this.setEmailAsVerified(user),
291 isDisplayed: ({ user }: { user: User }) => this.requiresEmailVerification && !user.blocked && user.emailVerified === false 291 isDisplayed: ({ user }) => this.requiresEmailVerification && !user.blocked && user.emailVerified === false
292 } 292 }
293 ]) 293 ])
294 } 294 }
@@ -299,23 +299,23 @@ export class UserModerationDropdownComponent implements OnChanges {
299 this.userActions.push([ 299 this.userActions.push([
300 { 300 {
301 label: this.i18n('Mute this account'), 301 label: this.i18n('Mute this account'),
302 isDisplayed: ({ account }: { account: Account }) => account.mutedByUser === false, 302 isDisplayed: ({ account }) => account.mutedByUser === false,
303 handler: ({ account }: { account: Account }) => this.blockAccountByUser(account) 303 handler: ({ account }) => this.blockAccountByUser(account)
304 }, 304 },
305 { 305 {
306 label: this.i18n('Unmute this account'), 306 label: this.i18n('Unmute this account'),
307 isDisplayed: ({ account }: { account: Account }) => account.mutedByUser === true, 307 isDisplayed: ({ account }) => account.mutedByUser === true,
308 handler: ({ account }: { account: Account }) => this.unblockAccountByUser(account) 308 handler: ({ account }) => this.unblockAccountByUser(account)
309 }, 309 },
310 { 310 {
311 label: this.i18n('Mute the instance'), 311 label: this.i18n('Mute the instance'),
312 isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === false, 312 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
313 handler: ({ account }: { account: Account }) => this.blockServerByUser(account.host) 313 handler: ({ account }) => this.blockServerByUser(account.host)
314 }, 314 },
315 { 315 {
316 label: this.i18n('Unmute the instance'), 316 label: this.i18n('Unmute the instance'),
317 isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === true, 317 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
318 handler: ({ account }: { account: Account }) => this.unblockServerByUser(account.host) 318 handler: ({ account }) => this.unblockServerByUser(account.host)
319 } 319 }
320 ]) 320 ])
321 321
@@ -326,13 +326,13 @@ export class UserModerationDropdownComponent implements OnChanges {
326 instanceActions = instanceActions.concat([ 326 instanceActions = instanceActions.concat([
327 { 327 {
328 label: this.i18n('Mute this account by your instance'), 328 label: this.i18n('Mute this account by your instance'),
329 isDisplayed: ({ account }: { account: Account }) => account.mutedByInstance === false, 329 isDisplayed: ({ account }) => account.mutedByInstance === false,
330 handler: ({ account }: { account: Account }) => this.blockAccountByInstance(account) 330 handler: ({ account }) => this.blockAccountByInstance(account)
331 }, 331 },
332 { 332 {
333 label: this.i18n('Unmute this account by your instance'), 333 label: this.i18n('Unmute this account by your instance'),
334 isDisplayed: ({ account }: { account: Account }) => account.mutedByInstance === true, 334 isDisplayed: ({ account }) => account.mutedByInstance === true,
335 handler: ({ account }: { account: Account }) => this.unblockAccountByInstance(account) 335 handler: ({ account }) => this.unblockAccountByInstance(account)
336 } 336 }
337 ]) 337 ])
338 } 338 }
@@ -342,13 +342,13 @@ export class UserModerationDropdownComponent implements OnChanges {
342 instanceActions = instanceActions.concat([ 342 instanceActions = instanceActions.concat([
343 { 343 {
344 label: this.i18n('Mute the instance by your instance'), 344 label: this.i18n('Mute the instance by your instance'),
345 isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === false, 345 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
346 handler: ({ account }: { account: Account }) => this.blockServerByInstance(account.host) 346 handler: ({ account }) => this.blockServerByInstance(account.host)
347 }, 347 },
348 { 348 {
349 label: this.i18n('Unmute the instance by your instance'), 349 label: this.i18n('Unmute the instance by your instance'),
350 isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === true, 350 isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
351 handler: ({ account }: { account: Account }) => this.unblockServerByInstance(account.host) 351 handler: ({ account }) => this.unblockServerByInstance(account.host)
352 } 352 }
353 ]) 353 ])
354 } 354 }
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index a2fa27b72..9810e9485 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -61,6 +61,7 @@ import { OverviewService } from '@app/shared/overview'
61import { UserBanModalComponent } from '@app/shared/moderation' 61import { UserBanModalComponent } from '@app/shared/moderation'
62import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component' 62import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component'
63import { BlocklistService } from '@app/shared/blocklist' 63import { BlocklistService } from '@app/shared/blocklist'
64import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.component'
64 65
65@NgModule({ 66@NgModule({
66 imports: [ 67 imports: [
@@ -102,7 +103,8 @@ import { BlocklistService } from '@app/shared/blocklist'
102 RemoteSubscribeComponent, 103 RemoteSubscribeComponent,
103 InstanceFeaturesTableComponent, 104 InstanceFeaturesTableComponent,
104 UserBanModalComponent, 105 UserBanModalComponent,
105 UserModerationDropdownComponent 106 UserModerationDropdownComponent,
107 TopMenuDropdownComponent
106 ], 108 ],
107 109
108 exports: [ 110 exports: [
@@ -141,6 +143,7 @@ import { BlocklistService } from '@app/shared/blocklist'
141 InstanceFeaturesTableComponent, 143 InstanceFeaturesTableComponent,
142 UserBanModalComponent, 144 UserBanModalComponent,
143 UserModerationDropdownComponent, 145 UserModerationDropdownComponent,
146 TopMenuDropdownComponent,
144 147
145 NumberFormatterPipe, 148 NumberFormatterPipe,
146 ObjectLengthPipe, 149 ObjectLengthPipe,
diff --git a/client/src/app/signup/signup.component.html b/client/src/app/signup/signup.component.html
index 0207a166e..07d24b381 100644
--- a/client/src/app/signup/signup.component.html
+++ b/client/src/app/signup/signup.component.html
@@ -64,7 +64,7 @@
64 </form> 64 </form>
65 65
66 <div> 66 <div>
67 <label for="email" i18n>Features found on this instance</label> 67 <label i18n>Features found on this instance</label>
68 <my-instance-features-table></my-instance-features-table> 68 <my-instance-features-table></my-instance-features-table>
69 </div> 69 </div>
70 </div> 70 </div>
diff --git a/client/src/app/videos/+video-watch/modal/video-report.component.html b/client/src/app/videos/+video-watch/modal/video-report.component.html
index 8d9a49276..733c01be0 100644
--- a/client/src/app/videos/+video-watch/modal/video-report.component.html
+++ b/client/src/app/videos/+video-watch/modal/video-report.component.html
@@ -6,6 +6,11 @@
6 6
7 <div class="modal-body"> 7 <div class="modal-body">
8 8
9 <div i18n class="information">
10 Your report will be sent to moderators of {{ currentHost }}.
11 <ng-container *ngIf="isRemoteVideo()"> It will be forwarded to origin instance {{ originHost }} too.</ng-container>
12 </div>
13
9 <form novalidate [formGroup]="form" (ngSubmit)="report()"> 14 <form novalidate [formGroup]="form" (ngSubmit)="report()">
10 <div class="form-group"> 15 <div class="form-group">
11 <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }"> 16 <textarea i18n-placeholder placeholder="Reason..." formControlName="reason" [ngClass]="{ 'input-error': formErrors['reason'] }">
diff --git a/client/src/app/videos/+video-watch/modal/video-report.component.scss b/client/src/app/videos/+video-watch/modal/video-report.component.scss
index afcdb9a16..4713660a2 100644
--- a/client/src/app/videos/+video-watch/modal/video-report.component.scss
+++ b/client/src/app/videos/+video-watch/modal/video-report.component.scss
@@ -1,6 +1,10 @@
1@import 'variables'; 1@import 'variables';
2@import 'mixins'; 2@import 'mixins';
3 3
4.information {
5 margin-bottom: 20px;
6}
7
4textarea { 8textarea {
5 @include peertube-textarea(100%, 100px); 9 @include peertube-textarea(100%, 100px);
6} 10}
diff --git a/client/src/app/videos/+video-watch/modal/video-report.component.ts b/client/src/app/videos/+video-watch/modal/video-report.component.ts
index 297afb19f..023387984 100644
--- a/client/src/app/videos/+video-watch/modal/video-report.component.ts
+++ b/client/src/app/videos/+video-watch/modal/video-report.component.ts
@@ -33,6 +33,18 @@ export class VideoReportComponent extends FormReactive implements OnInit {
33 super() 33 super()
34 } 34 }
35 35
36 get currentHost () {
37 return window.location.host
38 }
39
40 get originHost () {
41 if (this.isRemoteVideo()) {
42 return this.video.account.host
43 }
44
45 return ''
46 }
47
36 ngOnInit () { 48 ngOnInit () {
37 this.buildForm({ 49 this.buildForm({
38 reason: this.videoAbuseValidatorsService.VIDEO_ABUSE_REASON 50 reason: this.videoAbuseValidatorsService.VIDEO_ABUSE_REASON
@@ -61,4 +73,8 @@ export class VideoReportComponent extends FormReactive implements OnInit {
61 err => this.notificationsService.error(this.i18n('Error'), err.message) 73 err => this.notificationsService.error(this.i18n('Error'), err.message)
62 ) 74 )
63 } 75 }
76
77 isRemoteVideo () {
78 return !this.video.isLocal
79 }
64} 80}