aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/shared')
-rw-r--r--client/src/app/shared/form-validators/abuse-validators.ts24
-rw-r--r--client/src/app/shared/form-validators/custom-config-validators.ts88
-rw-r--r--client/src/app/shared/form-validators/form-validator.model.ts2
-rw-r--r--client/src/app/shared/form-validators/host-validators.ts20
-rw-r--r--client/src/app/shared/form-validators/instance-validators.ts24
-rw-r--r--client/src/app/shared/form-validators/login-validators.ts4
-rw-r--r--client/src/app/shared/form-validators/reset-password-validators.ts2
-rw-r--r--client/src/app/shared/form-validators/user-validators.ts64
-rw-r--r--client/src/app/shared/form-validators/video-block-validators.ts4
-rw-r--r--client/src/app/shared/form-validators/video-captions-validators.ts4
-rw-r--r--client/src/app/shared/form-validators/video-channel-validators.ts22
-rw-r--r--client/src/app/shared/form-validators/video-comment-validators.ts6
-rw-r--r--client/src/app/shared/form-validators/video-ownership-change-validators.ts8
-rw-r--r--client/src/app/shared/form-validators/video-playlist-validators.ts16
-rw-r--r--client/src/app/shared/form-validators/video-validators.ts32
-rw-r--r--client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts10
-rw-r--r--client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts2
-rw-r--r--client/src/app/shared/shared-abuse-list/processed-abuse.model.ts2
-rw-r--r--client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts2
-rw-r--r--client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts4
-rw-r--r--client/src/app/shared/shared-actor-image/actor-avatar.component.ts36
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts8
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts4
-rw-r--r--client/src/app/shared/shared-forms/form-reactive.ts6
-rw-r--r--client/src/app/shared/shared-forms/form-validator.service.ts8
-rw-r--r--client/src/app/shared/shared-forms/reactive-file.component.ts2
-rw-r--r--client/src/app/shared/shared-icons/global-icon.component.ts106
-rw-r--r--client/src/app/shared/shared-instance/instance-about-accordion.component.ts2
-rw-r--r--client/src/app/shared/shared-instance/instance-follow.service.ts16
-rw-r--r--client/src/app/shared/shared-instance/instance-statistics.component.ts4
-rw-r--r--client/src/app/shared/shared-instance/instance.service.ts2
-rw-r--r--client/src/app/shared/shared-instance/shared-instance.module.ts1
-rw-r--r--client/src/app/shared/shared-main/account/account.model.ts2
-rw-r--r--client/src/app/shared/shared-main/account/actor.model.ts2
-rw-r--r--client/src/app/shared/shared-main/angular/autofocus.directive.ts2
-rw-r--r--client/src/app/shared/shared-main/angular/link.component.ts2
-rw-r--r--client/src/app/shared/shared-main/angular/peertube-template.directive.ts1
-rw-r--r--client/src/app/shared/shared-main/feeds/syndication.model.ts4
-rw-r--r--client/src/app/shared/shared-main/misc/help.component.ts12
-rw-r--r--client/src/app/shared/shared-main/misc/list-overflow.component.ts4
-rw-r--r--client/src/app/shared/shared-main/misc/simple-search-input.component.ts2
-rw-r--r--client/src/app/shared/shared-main/misc/top-menu-dropdown.component.ts2
-rw-r--r--client/src/app/shared/shared-main/users/user-notification.service.ts6
-rw-r--r--client/src/app/shared/shared-main/users/user-quota.component.ts2
-rw-r--r--client/src/app/shared/shared-main/video-channel/video-channel.model.ts5
-rw-r--r--client/src/app/shared/shared-main/video-channel/video-channel.service.ts12
-rw-r--r--client/src/app/shared/shared-main/video/redundancy.service.ts4
-rw-r--r--client/src/app/shared/shared-main/video/video-edit.model.ts12
-rw-r--r--client/src/app/shared/shared-main/video/video.model.ts2
-rw-r--r--client/src/app/shared/shared-main/video/video.service.ts18
-rw-r--r--client/src/app/shared/shared-moderation/abuse.service.ts13
-rw-r--r--client/src/app/shared/shared-moderation/account-blocklist.component.ts7
-rw-r--r--client/src/app/shared/shared-moderation/blocklist.service.ts8
-rw-r--r--client/src/app/shared/shared-moderation/server-blocklist.component.ts10
-rw-r--r--client/src/app/shared/shared-moderation/video-block.component.ts4
-rw-r--r--client/src/app/shared/shared-support-modal/support-modal.component.ts4
-rw-r--r--client/src/app/shared/shared-user-settings/user-video-settings.component.ts2
-rw-r--r--client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts16
-rw-r--r--client/src/app/shared/shared-user-subscription/subscribe-button.component.ts4
-rw-r--r--client/src/app/shared/shared-user-subscription/user-subscription.service.ts20
-rw-r--r--client/src/app/shared/shared-video-comment/video-comment.model.ts8
-rw-r--r--client/src/app/shared/shared-video-comment/video-comment.service.ts14
-rw-r--r--client/src/app/shared/shared-video-miniature/abstract-video-list.ts16
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.ts26
-rw-r--r--client/src/app/shared/shared-video-miniature/video-list-header.component.ts2
-rw-r--r--client/src/app/shared/shared-video-miniature/videos-selection.component.ts2
-rw-r--r--client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts2
-rw-r--r--client/src/app/shared/shared-video-playlist/video-playlist-element.model.ts2
-rw-r--r--client/src/app/shared/shared-video-playlist/video-playlist.model.ts2
-rw-r--r--client/src/app/shared/shared-video-playlist/video-playlist.service.ts10
70 files changed, 409 insertions, 392 deletions
diff --git a/client/src/app/shared/form-validators/abuse-validators.ts b/client/src/app/shared/form-validators/abuse-validators.ts
index 75bfacf01..8d3c411b4 100644
--- a/client/src/app/shared/form-validators/abuse-validators.ts
+++ b/client/src/app/shared/form-validators/abuse-validators.ts
@@ -2,28 +2,28 @@ import { Validators } from '@angular/forms'
2import { BuildFormValidator } from './form-validator.model' 2import { BuildFormValidator } from './form-validator.model'
3 3
4export const ABUSE_REASON_VALIDATOR: BuildFormValidator = { 4export const ABUSE_REASON_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [Validators.required, Validators.minLength(2), Validators.maxLength(3000)], 5 VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`Report reason is required.`, 7 required: $localize`Report reason is required.`,
8 'minlength': $localize`Report reason must be at least 2 characters long.`, 8 minlength: $localize`Report reason must be at least 2 characters long.`,
9 'maxlength': $localize`Report reason cannot be more than 3000 characters long.` 9 maxlength: $localize`Report reason cannot be more than 3000 characters long.`
10 } 10 }
11} 11}
12 12
13export const ABUSE_MODERATION_COMMENT_VALIDATOR: BuildFormValidator = { 13export const ABUSE_MODERATION_COMMENT_VALIDATOR: BuildFormValidator = {
14 VALIDATORS: [Validators.required, Validators.minLength(2), Validators.maxLength(3000)], 14 VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
15 MESSAGES: { 15 MESSAGES: {
16 'required': $localize`Moderation comment is required.`, 16 required: $localize`Moderation comment is required.`,
17 'minlength': $localize`Moderation comment must be at least 2 characters long.`, 17 minlength: $localize`Moderation comment must be at least 2 characters long.`,
18 'maxlength': $localize`Moderation comment cannot be more than 3000 characters long.` 18 maxlength: $localize`Moderation comment cannot be more than 3000 characters long.`
19 } 19 }
20} 20}
21 21
22export const ABUSE_MESSAGE_VALIDATOR: BuildFormValidator = { 22export const ABUSE_MESSAGE_VALIDATOR: BuildFormValidator = {
23 VALIDATORS: [Validators.required, Validators.minLength(2), Validators.maxLength(3000)], 23 VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
24 MESSAGES: { 24 MESSAGES: {
25 'required': $localize`Abuse message is required.`, 25 required: $localize`Abuse message is required.`,
26 'minlength': $localize`Abuse message must be at least 2 characters long.`, 26 minlength: $localize`Abuse message must be at least 2 characters long.`,
27 'maxlength': $localize`Abuse message cannot be more than 3000 characters long.` 27 maxlength: $localize`Abuse message cannot be more than 3000 characters long.`
28 } 28 }
29} 29}
diff --git a/client/src/app/shared/form-validators/custom-config-validators.ts b/client/src/app/shared/form-validators/custom-config-validators.ts
index 1ed5700ff..fbf423d08 100644
--- a/client/src/app/shared/form-validators/custom-config-validators.ts
+++ b/client/src/app/shared/form-validators/custom-config-validators.ts
@@ -2,120 +2,120 @@ import { Validators } from '@angular/forms'
2import { BuildFormValidator } from './form-validator.model' 2import { BuildFormValidator } from './form-validator.model'
3 3
4export const INSTANCE_NAME_VALIDATOR: BuildFormValidator = { 4export const INSTANCE_NAME_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [Validators.required], 5 VALIDATORS: [ Validators.required ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`Instance name is required.` 7 required: $localize`Instance name is required.`
8 } 8 }
9} 9}
10 10
11export const INSTANCE_SHORT_DESCRIPTION_VALIDATOR: BuildFormValidator = { 11export const INSTANCE_SHORT_DESCRIPTION_VALIDATOR: BuildFormValidator = {
12 VALIDATORS: [Validators.max(250)], 12 VALIDATORS: [ Validators.max(250) ],
13 MESSAGES: { 13 MESSAGES: {
14 'max': $localize`Short description should not be longer than 250 characters.` 14 max: $localize`Short description should not be longer than 250 characters.`
15 } 15 }
16} 16}
17 17
18export const SERVICES_TWITTER_USERNAME_VALIDATOR: BuildFormValidator = { 18export const SERVICES_TWITTER_USERNAME_VALIDATOR: BuildFormValidator = {
19 VALIDATORS: [Validators.required], 19 VALIDATORS: [ Validators.required ],
20 MESSAGES: { 20 MESSAGES: {
21 'required': $localize`Twitter username is required.` 21 required: $localize`Twitter username is required.`
22 } 22 }
23} 23}
24 24
25export const CACHE_PREVIEWS_SIZE_VALIDATOR: BuildFormValidator = { 25export const CACHE_PREVIEWS_SIZE_VALIDATOR: BuildFormValidator = {
26 VALIDATORS: [Validators.required, Validators.min(1), Validators.pattern('[0-9]+')], 26 VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
27 MESSAGES: { 27 MESSAGES: {
28 'required': $localize`Previews cache size is required.`, 28 required: $localize`Previews cache size is required.`,
29 'min': $localize`Previews cache size must be greater than 1.`, 29 min: $localize`Previews cache size must be greater than 1.`,
30 'pattern': $localize`Previews cache size must be a number.` 30 pattern: $localize`Previews cache size must be a number.`
31 } 31 }
32} 32}
33 33
34export const CACHE_CAPTIONS_SIZE_VALIDATOR: BuildFormValidator = { 34export const CACHE_CAPTIONS_SIZE_VALIDATOR: BuildFormValidator = {
35 VALIDATORS: [Validators.required, Validators.min(1), Validators.pattern('[0-9]+')], 35 VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
36 MESSAGES: { 36 MESSAGES: {
37 'required': $localize`Captions cache size is required.`, 37 required: $localize`Captions cache size is required.`,
38 'min': $localize`Captions cache size must be greater than 1.`, 38 min: $localize`Captions cache size must be greater than 1.`,
39 'pattern': $localize`Captions cache size must be a number.` 39 pattern: $localize`Captions cache size must be a number.`
40 } 40 }
41} 41}
42 42
43export const SIGNUP_LIMIT_VALIDATOR: BuildFormValidator = { 43export const SIGNUP_LIMIT_VALIDATOR: BuildFormValidator = {
44 VALIDATORS: [Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+')], 44 VALIDATORS: [ Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+') ],
45 MESSAGES: { 45 MESSAGES: {
46 'required': $localize`Signup limit is required.`, 46 required: $localize`Signup limit is required.`,
47 'min': $localize`Signup limit must be greater than 1. Use -1 to disable it.`, 47 min: $localize`Signup limit must be greater than 1. Use -1 to disable it.`,
48 'pattern': $localize`Signup limit must be a number.` 48 pattern: $localize`Signup limit must be a number.`
49 } 49 }
50} 50}
51 51
52export const SIGNUP_MINIMUM_AGE_VALIDATOR: BuildFormValidator = { 52export const SIGNUP_MINIMUM_AGE_VALIDATOR: BuildFormValidator = {
53 VALIDATORS: [Validators.required, Validators.min(1), Validators.pattern('[0-9]+')], 53 VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
54 MESSAGES: { 54 MESSAGES: {
55 'required': $localize`Signup minimum age is required.`, 55 required: $localize`Signup minimum age is required.`,
56 'min': $localize`Signup minimum age must be greater than 1.`, 56 min: $localize`Signup minimum age must be greater than 1.`,
57 'pattern': $localize`Signup minimum age must be a number.` 57 pattern: $localize`Signup minimum age must be a number.`
58 } 58 }
59} 59}
60 60
61export const ADMIN_EMAIL_VALIDATOR: BuildFormValidator = { 61export const ADMIN_EMAIL_VALIDATOR: BuildFormValidator = {
62 VALIDATORS: [Validators.required, Validators.email], 62 VALIDATORS: [ Validators.required, Validators.email ],
63 MESSAGES: { 63 MESSAGES: {
64 'required': $localize`Admin email is required.`, 64 required: $localize`Admin email is required.`,
65 'email': $localize`Admin email must be valid.` 65 email: $localize`Admin email must be valid.`
66 } 66 }
67} 67}
68 68
69export const TRANSCODING_THREADS_VALIDATOR: BuildFormValidator = { 69export const TRANSCODING_THREADS_VALIDATOR: BuildFormValidator = {
70 VALIDATORS: [Validators.required, Validators.min(0)], 70 VALIDATORS: [ Validators.required, Validators.min(0) ],
71 MESSAGES: { 71 MESSAGES: {
72 'required': $localize`Transcoding threads is required.`, 72 required: $localize`Transcoding threads is required.`,
73 'min': $localize`Transcoding threads must be greater or equal to 0.` 73 min: $localize`Transcoding threads must be greater or equal to 0.`
74 } 74 }
75} 75}
76 76
77export const MAX_LIVE_DURATION_VALIDATOR: BuildFormValidator = { 77export const MAX_LIVE_DURATION_VALIDATOR: BuildFormValidator = {
78 VALIDATORS: [Validators.required, Validators.min(-1)], 78 VALIDATORS: [ Validators.required, Validators.min(-1) ],
79 MESSAGES: { 79 MESSAGES: {
80 'required': $localize`Max live duration is required.`, 80 required: $localize`Max live duration is required.`,
81 'min': $localize`Max live duration should be greater or equal to -1.` 81 min: $localize`Max live duration should be greater or equal to -1.`
82 } 82 }
83} 83}
84 84
85export const MAX_INSTANCE_LIVES_VALIDATOR: BuildFormValidator = { 85export const MAX_INSTANCE_LIVES_VALIDATOR: BuildFormValidator = {
86 VALIDATORS: [Validators.required, Validators.min(-1)], 86 VALIDATORS: [ Validators.required, Validators.min(-1) ],
87 MESSAGES: { 87 MESSAGES: {
88 'required': $localize`Max instance lives is required.`, 88 required: $localize`Max instance lives is required.`,
89 'min': $localize`Max instance lives should be greater or equal to -1.` 89 min: $localize`Max instance lives should be greater or equal to -1.`
90 } 90 }
91} 91}
92 92
93export const MAX_USER_LIVES_VALIDATOR: BuildFormValidator = { 93export const MAX_USER_LIVES_VALIDATOR: BuildFormValidator = {
94 VALIDATORS: [Validators.required, Validators.min(-1)], 94 VALIDATORS: [ Validators.required, Validators.min(-1) ],
95 MESSAGES: { 95 MESSAGES: {
96 'required': $localize`Max user lives is required.`, 96 required: $localize`Max user lives is required.`,
97 'min': $localize`Max user lives should be greater or equal to -1.` 97 min: $localize`Max user lives should be greater or equal to -1.`
98 } 98 }
99} 99}
100 100
101export const CONCURRENCY_VALIDATOR: BuildFormValidator = { 101export const CONCURRENCY_VALIDATOR: BuildFormValidator = {
102 VALIDATORS: [Validators.required, Validators.min(1)], 102 VALIDATORS: [ Validators.required, Validators.min(1) ],
103 MESSAGES: { 103 MESSAGES: {
104 'required': $localize`Concurrency is required.`, 104 required: $localize`Concurrency is required.`,
105 'min': $localize`Concurrency should be greater or equal to 1.` 105 min: $localize`Concurrency should be greater or equal to 1.`
106 } 106 }
107} 107}
108 108
109export const INDEX_URL_VALIDATOR: BuildFormValidator = { 109export const INDEX_URL_VALIDATOR: BuildFormValidator = {
110 VALIDATORS: [Validators.pattern(/^https:\/\//)], 110 VALIDATORS: [ Validators.pattern(/^https:\/\//) ],
111 MESSAGES: { 111 MESSAGES: {
112 'pattern': $localize`Index URL should be a URL` 112 pattern: $localize`Index URL should be a URL`
113 } 113 }
114} 114}
115 115
116export const SEARCH_INDEX_URL_VALIDATOR: BuildFormValidator = { 116export const SEARCH_INDEX_URL_VALIDATOR: BuildFormValidator = {
117 VALIDATORS: [Validators.pattern(/^https?:\/\//)], 117 VALIDATORS: [ Validators.pattern(/^https?:\/\//) ],
118 MESSAGES: { 118 MESSAGES: {
119 'pattern': $localize`Search index URL should be a URL` 119 pattern: $localize`Search index URL should be a URL`
120 } 120 }
121} 121}
diff --git a/client/src/app/shared/form-validators/form-validator.model.ts b/client/src/app/shared/form-validators/form-validator.model.ts
index 07b1ea075..6f2472ccd 100644
--- a/client/src/app/shared/form-validators/form-validator.model.ts
+++ b/client/src/app/shared/form-validators/form-validator.model.ts
@@ -1,7 +1,7 @@
1import { ValidatorFn } from '@angular/forms' 1import { ValidatorFn } from '@angular/forms'
2 2
3export type BuildFormValidator = { 3export type BuildFormValidator = {
4 VALIDATORS: ValidatorFn[], 4 VALIDATORS: ValidatorFn[]
5 MESSAGES: { [ name: string ]: string } 5 MESSAGES: { [ name: string ]: string }
6} 6}
7 7
diff --git a/client/src/app/shared/form-validators/host-validators.ts b/client/src/app/shared/form-validators/host-validators.ts
index 6f410a50a..3d9c476b5 100644
--- a/client/src/app/shared/form-validators/host-validators.ts
+++ b/client/src/app/shared/form-validators/host-validators.ts
@@ -4,7 +4,7 @@ import { BuildFormValidator } from './form-validator.model'
4export function validateHost (value: string) { 4export function validateHost (value: string) {
5 // Thanks to http://stackoverflow.com/a/106223 5 // Thanks to http://stackoverflow.com/a/106223
6 const HOST_REGEXP = new RegExp( 6 const HOST_REGEXP = new RegExp(
7 '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' 7 '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$'
8 ) 8 )
9 9
10 return HOST_REGEXP.test(value) 10 return HOST_REGEXP.test(value)
@@ -32,7 +32,7 @@ const validHosts: ValidatorFn = (control: AbstractControl) => {
32 if (errors.length === 0) return null 32 if (errors.length === 0) return null
33 33
34 return { 34 return {
35 'validHosts': { 35 validHosts: {
36 reason: 'invalid', 36 reason: 'invalid',
37 value: errors.join('. ') + '.' 37 value: errors.join('. ') + '.'
38 } 38 }
@@ -55,7 +55,7 @@ const validHostsOrHandles: ValidatorFn = (control: AbstractControl) => {
55 if (errors.length === 0) return null 55 if (errors.length === 0) return null
56 56
57 return { 57 return {
58 'validHostsOrHandles': { 58 validHostsOrHandles: {
59 reason: 'invalid', 59 reason: 'invalid',
60 value: errors.join('. ') + '.' 60 value: errors.join('. ') + '.'
61 } 61 }
@@ -80,7 +80,7 @@ export const unique: ValidatorFn = (control: AbstractControl) => {
80 } 80 }
81 81
82 return { 82 return {
83 'unique': { 83 unique: {
84 reason: 'invalid' 84 reason: 'invalid'
85 } 85 }
86 } 86 }
@@ -89,17 +89,17 @@ export const unique: ValidatorFn = (control: AbstractControl) => {
89export const UNIQUE_HOSTS_VALIDATOR: BuildFormValidator = { 89export const UNIQUE_HOSTS_VALIDATOR: BuildFormValidator = {
90 VALIDATORS: [ Validators.required, validHosts, unique ], 90 VALIDATORS: [ Validators.required, validHosts, unique ],
91 MESSAGES: { 91 MESSAGES: {
92 'required': $localize`Domain is required.`, 92 required: $localize`Domain is required.`,
93 'validHosts': $localize`Hosts entered are invalid.`, 93 validHosts: $localize`Hosts entered are invalid.`,
94 'unique': $localize`Hosts entered contain duplicates.` 94 unique: $localize`Hosts entered contain duplicates.`
95 } 95 }
96} 96}
97 97
98export const UNIQUE_HOSTS_OR_HANDLE_VALIDATOR: BuildFormValidator = { 98export const UNIQUE_HOSTS_OR_HANDLE_VALIDATOR: BuildFormValidator = {
99 VALIDATORS: [ Validators.required, validHostsOrHandles, unique ], 99 VALIDATORS: [ Validators.required, validHostsOrHandles, unique ],
100 MESSAGES: { 100 MESSAGES: {
101 'required': $localize`Domain is required.`, 101 required: $localize`Domain is required.`,
102 'validHostsOrHandles': $localize`Hosts or handles are invalid.`, 102 validHostsOrHandles: $localize`Hosts or handles are invalid.`,
103 'unique': $localize`Hosts or handles contain duplicates.` 103 unique: $localize`Hosts or handles contain duplicates.`
104 } 104 }
105} 105}
diff --git a/client/src/app/shared/form-validators/instance-validators.ts b/client/src/app/shared/form-validators/instance-validators.ts
index a72e28ba0..4b1f0d048 100644
--- a/client/src/app/shared/form-validators/instance-validators.ts
+++ b/client/src/app/shared/form-validators/instance-validators.ts
@@ -2,10 +2,10 @@ import { Validators } from '@angular/forms'
2import { BuildFormValidator } from './form-validator.model' 2import { BuildFormValidator } from './form-validator.model'
3 3
4export const FROM_EMAIL_VALIDATOR: BuildFormValidator = { 4export const FROM_EMAIL_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [Validators.required, Validators.email], 5 VALIDATORS: [ Validators.required, Validators.email ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`Email is required.`, 7 required: $localize`Email is required.`,
8 'email': $localize`Email must be valid.` 8 email: $localize`Email must be valid.`
9 } 9 }
10} 10}
11 11
@@ -16,9 +16,9 @@ export const FROM_NAME_VALIDATOR: BuildFormValidator = {
16 Validators.maxLength(120) 16 Validators.maxLength(120)
17 ], 17 ],
18 MESSAGES: { 18 MESSAGES: {
19 'required': $localize`Your name is required.`, 19 required: $localize`Your name is required.`,
20 'minlength': $localize`Your name must be at least 1 character long.`, 20 minlength: $localize`Your name must be at least 1 character long.`,
21 'maxlength': $localize`Your name cannot be more than 120 characters long.` 21 maxlength: $localize`Your name cannot be more than 120 characters long.`
22 } 22 }
23} 23}
24 24
@@ -29,9 +29,9 @@ export const SUBJECT_VALIDATOR: BuildFormValidator = {
29 Validators.maxLength(120) 29 Validators.maxLength(120)
30 ], 30 ],
31 MESSAGES: { 31 MESSAGES: {
32 'required': $localize`A subject is required.`, 32 required: $localize`A subject is required.`,
33 'minlength': $localize`The subject must be at least 1 character long.`, 33 minlength: $localize`The subject must be at least 1 character long.`,
34 'maxlength': $localize`The subject cannot be more than 120 characters long.` 34 maxlength: $localize`The subject cannot be more than 120 characters long.`
35 } 35 }
36} 36}
37 37
@@ -42,8 +42,8 @@ export const BODY_VALIDATOR: BuildFormValidator = {
42 Validators.maxLength(5000) 42 Validators.maxLength(5000)
43 ], 43 ],
44 MESSAGES: { 44 MESSAGES: {
45 'required': $localize`A message is required.`, 45 required: $localize`A message is required.`,
46 'minlength': $localize`The message must be at least 3 characters long.`, 46 minlength: $localize`The message must be at least 3 characters long.`,
47 'maxlength': $localize`The message cannot be more than 5000 characters long.` 47 maxlength: $localize`The message cannot be more than 5000 characters long.`
48 } 48 }
49} 49}
diff --git a/client/src/app/shared/form-validators/login-validators.ts b/client/src/app/shared/form-validators/login-validators.ts
index 1ceae1be3..5b911ac47 100644
--- a/client/src/app/shared/form-validators/login-validators.ts
+++ b/client/src/app/shared/form-validators/login-validators.ts
@@ -6,7 +6,7 @@ export const LOGIN_USERNAME_VALIDATOR: BuildFormValidator = {
6 Validators.required 6 Validators.required
7 ], 7 ],
8 MESSAGES: { 8 MESSAGES: {
9 'required': $localize`Username is required.` 9 required: $localize`Username is required.`
10 } 10 }
11} 11}
12 12
@@ -15,6 +15,6 @@ export const LOGIN_PASSWORD_VALIDATOR: BuildFormValidator = {
15 Validators.required 15 Validators.required
16 ], 16 ],
17 MESSAGES: { 17 MESSAGES: {
18 'required': $localize`Password is required.` 18 required: $localize`Password is required.`
19 } 19 }
20} 20}
diff --git a/client/src/app/shared/form-validators/reset-password-validators.ts b/client/src/app/shared/form-validators/reset-password-validators.ts
index b87f2eab9..70617a562 100644
--- a/client/src/app/shared/form-validators/reset-password-validators.ts
+++ b/client/src/app/shared/form-validators/reset-password-validators.ts
@@ -6,6 +6,6 @@ export const RESET_PASSWORD_CONFIRM_VALIDATOR: BuildFormValidator = {
6 Validators.required 6 Validators.required
7 ], 7 ],
8 MESSAGES: { 8 MESSAGES: {
9 'required': $localize`Confirmation of the password is required.` 9 required: $localize`Confirmation of the password is required.`
10 } 10 }
11} 11}
diff --git a/client/src/app/shared/form-validators/user-validators.ts b/client/src/app/shared/form-validators/user-validators.ts
index 976c97b87..6d0dea64e 100644
--- a/client/src/app/shared/form-validators/user-validators.ts
+++ b/client/src/app/shared/form-validators/user-validators.ts
@@ -11,10 +11,10 @@ export const USER_USERNAME_VALIDATOR: BuildFormValidator = {
11 Validators.pattern(new RegExp(`^${USER_USERNAME_REGEX_CHARACTERS}*$`)) 11 Validators.pattern(new RegExp(`^${USER_USERNAME_REGEX_CHARACTERS}*$`))
12 ], 12 ],
13 MESSAGES: { 13 MESSAGES: {
14 'required': $localize`Username is required.`, 14 required: $localize`Username is required.`,
15 'minlength': $localize`Username must be at least 1 character long.`, 15 minlength: $localize`Username must be at least 1 character long.`,
16 'maxlength': $localize`Username cannot be more than 50 characters long.`, 16 maxlength: $localize`Username cannot be more than 50 characters long.`,
17 'pattern': $localize`Username should be lowercase alphanumeric; dots and underscores are allowed.` 17 pattern: $localize`Username should be lowercase alphanumeric; dots and underscores are allowed.`
18 } 18 }
19} 19}
20 20
@@ -26,18 +26,18 @@ export const USER_CHANNEL_NAME_VALIDATOR: BuildFormValidator = {
26 Validators.pattern(/^[a-z0-9][a-z0-9._]*$/) 26 Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
27 ], 27 ],
28 MESSAGES: { 28 MESSAGES: {
29 'required': $localize`Channel name is required.`, 29 required: $localize`Channel name is required.`,
30 'minlength': $localize`Channel name must be at least 1 character long.`, 30 minlength: $localize`Channel name must be at least 1 character long.`,
31 'maxlength': $localize`Channel name cannot be more than 50 characters long.`, 31 maxlength: $localize`Channel name cannot be more than 50 characters long.`,
32 'pattern': $localize`Channel name should be lowercase, and can contain only alphanumeric characters, dots and underscores.` 32 pattern: $localize`Channel name should be lowercase, and can contain only alphanumeric characters, dots and underscores.`
33 } 33 }
34} 34}
35 35
36export const USER_EMAIL_VALIDATOR: BuildFormValidator = { 36export const USER_EMAIL_VALIDATOR: BuildFormValidator = {
37 VALIDATORS: [ Validators.required, Validators.email ], 37 VALIDATORS: [ Validators.required, Validators.email ],
38 MESSAGES: { 38 MESSAGES: {
39 'required': $localize`Email is required.`, 39 required: $localize`Email is required.`,
40 'email': $localize`Email must be valid.` 40 email: $localize`Email must be valid.`
41 } 41 }
42} 42}
43 43
@@ -47,8 +47,8 @@ export const USER_HANDLE_VALIDATOR: BuildFormValidator = {
47 Validators.pattern(/@.+/) 47 Validators.pattern(/@.+/)
48 ], 48 ],
49 MESSAGES: { 49 MESSAGES: {
50 'required': $localize`Handle is required.`, 50 required: $localize`Handle is required.`,
51 'pattern': $localize`Handle must be valid (eg. chocobozzz@example.com).` 51 pattern: $localize`Handle must be valid (eg. chocobozzz@example.com).`
52 } 52 }
53} 53}
54 54
@@ -57,7 +57,7 @@ export const USER_EXISTING_PASSWORD_VALIDATOR: BuildFormValidator = {
57 Validators.required 57 Validators.required
58 ], 58 ],
59 MESSAGES: { 59 MESSAGES: {
60 'required': $localize`Password is required.` 60 required: $localize`Password is required.`
61 } 61 }
62} 62}
63 63
@@ -68,9 +68,9 @@ export const USER_PASSWORD_VALIDATOR: BuildFormValidator = {
68 Validators.maxLength(255) 68 Validators.maxLength(255)
69 ], 69 ],
70 MESSAGES: { 70 MESSAGES: {
71 'required': $localize`Password is required.`, 71 required: $localize`Password is required.`,
72 'minlength': $localize`Password must be at least 6 characters long.`, 72 minlength: $localize`Password must be at least 6 characters long.`,
73 'maxlength': $localize`Password cannot be more than 255 characters long.` 73 maxlength: $localize`Password cannot be more than 255 characters long.`
74 } 74 }
75} 75}
76 76
@@ -80,37 +80,37 @@ export const USER_PASSWORD_OPTIONAL_VALIDATOR: BuildFormValidator = {
80 Validators.maxLength(255) 80 Validators.maxLength(255)
81 ], 81 ],
82 MESSAGES: { 82 MESSAGES: {
83 'minlength': $localize`Password must be at least 6 characters long.`, 83 minlength: $localize`Password must be at least 6 characters long.`,
84 'maxlength': $localize`Password cannot be more than 255 characters long.` 84 maxlength: $localize`Password cannot be more than 255 characters long.`
85 } 85 }
86} 86}
87 87
88export const USER_CONFIRM_PASSWORD_VALIDATOR: BuildFormValidator = { 88export const USER_CONFIRM_PASSWORD_VALIDATOR: BuildFormValidator = {
89 VALIDATORS: [], 89 VALIDATORS: [],
90 MESSAGES: { 90 MESSAGES: {
91 'matchPassword': $localize`The new password and the confirmed password do not correspond.` 91 matchPassword: $localize`The new password and the confirmed password do not correspond.`
92 } 92 }
93} 93}
94 94
95export const USER_VIDEO_QUOTA_VALIDATOR: BuildFormValidator = { 95export const USER_VIDEO_QUOTA_VALIDATOR: BuildFormValidator = {
96 VALIDATORS: [ Validators.required, Validators.min(-1) ], 96 VALIDATORS: [ Validators.required, Validators.min(-1) ],
97 MESSAGES: { 97 MESSAGES: {
98 'required': $localize`Video quota is required.`, 98 required: $localize`Video quota is required.`,
99 'min': $localize`Quota must be greater than -1.` 99 min: $localize`Quota must be greater than -1.`
100 } 100 }
101} 101}
102export const USER_VIDEO_QUOTA_DAILY_VALIDATOR: BuildFormValidator = { 102export const USER_VIDEO_QUOTA_DAILY_VALIDATOR: BuildFormValidator = {
103 VALIDATORS: [ Validators.required, Validators.min(-1) ], 103 VALIDATORS: [ Validators.required, Validators.min(-1) ],
104 MESSAGES: { 104 MESSAGES: {
105 'required': $localize`Daily upload limit is required.`, 105 required: $localize`Daily upload limit is required.`,
106 'min': $localize`Daily upload limit must be greater than -1.` 106 min: $localize`Daily upload limit must be greater than -1.`
107 } 107 }
108} 108}
109 109
110export const USER_ROLE_VALIDATOR: BuildFormValidator = { 110export const USER_ROLE_VALIDATOR: BuildFormValidator = {
111 VALIDATORS: [ Validators.required ], 111 VALIDATORS: [ Validators.required ],
112 MESSAGES: { 112 MESSAGES: {
113 'required': $localize`User role is required.` 113 required: $localize`User role is required.`
114 } 114 }
115} 115}
116 116
@@ -122,15 +122,15 @@ export const USER_DESCRIPTION_VALIDATOR: BuildFormValidator = {
122 Validators.maxLength(1000) 122 Validators.maxLength(1000)
123 ], 123 ],
124 MESSAGES: { 124 MESSAGES: {
125 'minlength': $localize`Description must be at least 3 characters long.`, 125 minlength: $localize`Description must be at least 3 characters long.`,
126 'maxlength': $localize`Description cannot be more than 1000 characters long.` 126 maxlength: $localize`Description cannot be more than 1000 characters long.`
127 } 127 }
128} 128}
129 129
130export const USER_TERMS_VALIDATOR: BuildFormValidator = { 130export const USER_TERMS_VALIDATOR: BuildFormValidator = {
131 VALIDATORS: [ Validators.requiredTrue ], 131 VALIDATORS: [ Validators.requiredTrue ],
132 MESSAGES: { 132 MESSAGES: {
133 'required': $localize`You must agree with the instance terms in order to register on it.` 133 required: $localize`You must agree with the instance terms in order to register on it.`
134 } 134 }
135} 135}
136 136
@@ -140,8 +140,8 @@ export const USER_BAN_REASON_VALIDATOR: BuildFormValidator = {
140 Validators.maxLength(250) 140 Validators.maxLength(250)
141 ], 141 ],
142 MESSAGES: { 142 MESSAGES: {
143 'minlength': $localize`Ban reason must be at least 3 characters long.`, 143 minlength: $localize`Ban reason must be at least 3 characters long.`,
144 'maxlength': $localize`Ban reason cannot be more than 250 characters long.` 144 maxlength: $localize`Ban reason cannot be more than 250 characters long.`
145 } 145 }
146} 146}
147 147
@@ -152,9 +152,9 @@ function buildDisplayNameValidator (required: boolean) {
152 Validators.maxLength(120) 152 Validators.maxLength(120)
153 ], 153 ],
154 MESSAGES: { 154 MESSAGES: {
155 'required': $localize`Display name is required.`, 155 required: $localize`Display name is required.`,
156 'minlength': $localize`Display name must be at least 1 character long.`, 156 minlength: $localize`Display name must be at least 1 character long.`,
157 'maxlength': $localize`Display name cannot be more than 50 characters long.` 157 maxlength: $localize`Display name cannot be more than 50 characters long.`
158 } 158 }
159 } 159 }
160 160
diff --git a/client/src/app/shared/form-validators/video-block-validators.ts b/client/src/app/shared/form-validators/video-block-validators.ts
index d3974aefe..cd2791b76 100644
--- a/client/src/app/shared/form-validators/video-block-validators.ts
+++ b/client/src/app/shared/form-validators/video-block-validators.ts
@@ -4,7 +4,7 @@ import { BuildFormValidator } from './form-validator.model'
4export const VIDEO_BLOCK_REASON_VALIDATOR: BuildFormValidator = { 4export const VIDEO_BLOCK_REASON_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ], 5 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ],
6 MESSAGES: { 6 MESSAGES: {
7 'minlength': $localize`Block reason must be at least 2 characters long.`, 7 minlength: $localize`Block reason must be at least 2 characters long.`,
8 'maxlength': $localize`Block reason cannot be more than 300 characters long.` 8 maxlength: $localize`Block reason cannot be more than 300 characters long.`
9 } 9 }
10} 10}
diff --git a/client/src/app/shared/form-validators/video-captions-validators.ts b/client/src/app/shared/form-validators/video-captions-validators.ts
index 9742d2925..a16216422 100644
--- a/client/src/app/shared/form-validators/video-captions-validators.ts
+++ b/client/src/app/shared/form-validators/video-captions-validators.ts
@@ -4,13 +4,13 @@ import { BuildFormValidator } from './form-validator.model'
4export const VIDEO_CAPTION_LANGUAGE_VALIDATOR: BuildFormValidator = { 4export const VIDEO_CAPTION_LANGUAGE_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [ Validators.required ], 5 VALIDATORS: [ Validators.required ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`Video caption language is required.` 7 required: $localize`Video caption language is required.`
8 } 8 }
9} 9}
10 10
11export const VIDEO_CAPTION_FILE_VALIDATOR: BuildFormValidator = { 11export const VIDEO_CAPTION_FILE_VALIDATOR: BuildFormValidator = {
12 VALIDATORS: [ Validators.required ], 12 VALIDATORS: [ Validators.required ],
13 MESSAGES: { 13 MESSAGES: {
14 'required': $localize`Video caption file is required.` 14 required: $localize`Video caption file is required.`
15 } 15 }
16} 16}
diff --git a/client/src/app/shared/form-validators/video-channel-validators.ts b/client/src/app/shared/form-validators/video-channel-validators.ts
index ba502ed01..48f5b1a2c 100644
--- a/client/src/app/shared/form-validators/video-channel-validators.ts
+++ b/client/src/app/shared/form-validators/video-channel-validators.ts
@@ -7,10 +7,10 @@ export const VIDEO_CHANNEL_NAME_VALIDATOR: BuildFormValidator = {
7 VALIDATORS: USER_USERNAME_VALIDATOR.VALIDATORS, 7 VALIDATORS: USER_USERNAME_VALIDATOR.VALIDATORS,
8 8
9 MESSAGES: { 9 MESSAGES: {
10 'required': $localize`Name is required.`, 10 required: $localize`Name is required.`,
11 'minlength': $localize`Name must be at least 1 character long.`, 11 minlength: $localize`Name must be at least 1 character long.`,
12 'maxlength': $localize`Name cannot be more than 50 characters long.`, 12 maxlength: $localize`Name cannot be more than 50 characters long.`,
13 'pattern': $localize`Name should be lowercase alphanumeric; dots and underscores are allowed.` 13 pattern: $localize`Name should be lowercase alphanumeric; dots and underscores are allowed.`
14 } 14 }
15} 15}
16 16
@@ -21,9 +21,9 @@ export const VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR: BuildFormValidator = {
21 Validators.maxLength(50) 21 Validators.maxLength(50)
22 ], 22 ],
23 MESSAGES: { 23 MESSAGES: {
24 'required': $localize`Display name is required.`, 24 required: $localize`Display name is required.`,
25 'minlength': $localize`Display name must be at least 1 character long.`, 25 minlength: $localize`Display name must be at least 1 character long.`,
26 'maxlength': $localize`Display name cannot be more than 50 characters long.` 26 maxlength: $localize`Display name cannot be more than 50 characters long.`
27 } 27 }
28} 28}
29 29
@@ -33,8 +33,8 @@ export const VIDEO_CHANNEL_DESCRIPTION_VALIDATOR: BuildFormValidator = {
33 Validators.maxLength(1000) 33 Validators.maxLength(1000)
34 ], 34 ],
35 MESSAGES: { 35 MESSAGES: {
36 'minlength': $localize`Description must be at least 3 characters long.`, 36 minlength: $localize`Description must be at least 3 characters long.`,
37 'maxlength': $localize`Description cannot be more than 1000 characters long.` 37 maxlength: $localize`Description cannot be more than 1000 characters long.`
38 } 38 }
39} 39}
40 40
@@ -44,7 +44,7 @@ export const VIDEO_CHANNEL_SUPPORT_VALIDATOR: BuildFormValidator = {
44 Validators.maxLength(1000) 44 Validators.maxLength(1000)
45 ], 45 ],
46 MESSAGES: { 46 MESSAGES: {
47 'minlength': $localize`Support text must be at least 3 characters long.`, 47 minlength: $localize`Support text must be at least 3 characters long.`,
48 'maxlength': $localize`Support text cannot be more than 1000 characters long` 48 maxlength: $localize`Support text cannot be more than 1000 characters long`
49 } 49 }
50} 50}
diff --git a/client/src/app/shared/form-validators/video-comment-validators.ts b/client/src/app/shared/form-validators/video-comment-validators.ts
index c56564d34..9e8f95e7c 100644
--- a/client/src/app/shared/form-validators/video-comment-validators.ts
+++ b/client/src/app/shared/form-validators/video-comment-validators.ts
@@ -4,8 +4,8 @@ import { BuildFormValidator } from './form-validator.model'
4export const VIDEO_COMMENT_TEXT_VALIDATOR: BuildFormValidator = { 4export const VIDEO_COMMENT_TEXT_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(3000) ], 5 VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(3000) ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`Comment is required.`, 7 required: $localize`Comment is required.`,
8 'minlength': $localize`Comment must be at least 2 characters long.`, 8 minlength: $localize`Comment must be at least 2 characters long.`,
9 'maxlength': $localize`Comment cannot be more than 3000 characters long.` 9 maxlength: $localize`Comment cannot be more than 3000 characters long.`
10 } 10 }
11} 11}
diff --git a/client/src/app/shared/form-validators/video-ownership-change-validators.ts b/client/src/app/shared/form-validators/video-ownership-change-validators.ts
index e1a2df8a6..3e7823c49 100644
--- a/client/src/app/shared/form-validators/video-ownership-change-validators.ts
+++ b/client/src/app/shared/form-validators/video-ownership-change-validators.ts
@@ -4,21 +4,21 @@ import { BuildFormValidator } from './form-validator.model'
4export const OWNERSHIP_CHANGE_CHANNEL_VALIDATOR: BuildFormValidator = { 4export const OWNERSHIP_CHANGE_CHANNEL_VALIDATOR: BuildFormValidator = {
5 VALIDATORS: [ Validators.required ], 5 VALIDATORS: [ Validators.required ],
6 MESSAGES: { 6 MESSAGES: {
7 'required': $localize`The channel is required.` 7 required: $localize`The channel is required.`
8 } 8 }
9} 9}
10 10
11export const OWNERSHIP_CHANGE_USERNAME_VALIDATOR: BuildFormValidator = { 11export const OWNERSHIP_CHANGE_USERNAME_VALIDATOR: BuildFormValidator = {
12 VALIDATORS: [ Validators.required, localAccountValidator ], 12 VALIDATORS: [ Validators.required, localAccountValidator ],
13 MESSAGES: { 13 MESSAGES: {
14 'required': $localize`The username is required.`, 14 required: $localize`The username is required.`,
15 'localAccountOnly': $localize`You can only transfer ownership to a local account` 15 localAccountOnly: $localize`You can only transfer ownership to a local account`
16 } 16 }
17} 17}
18 18
19function localAccountValidator (control: AbstractControl): ValidationErrors { 19function localAccountValidator (control: AbstractControl): ValidationErrors {
20 if (control.value.includes('@')) { 20 if (control.value.includes('@')) {
21 return { 'localAccountOnly': true } 21 return { localAccountOnly: true }
22 } 22 }
23 23
24 return null 24 return null
diff --git a/client/src/app/shared/form-validators/video-playlist-validators.ts b/client/src/app/shared/form-validators/video-playlist-validators.ts
index 7e3d29458..63af637a3 100644
--- a/client/src/app/shared/form-validators/video-playlist-validators.ts
+++ b/client/src/app/shared/form-validators/video-playlist-validators.ts
@@ -9,9 +9,9 @@ export const VIDEO_PLAYLIST_DISPLAY_NAME_VALIDATOR: BuildFormValidator = {
9 Validators.maxLength(120) 9 Validators.maxLength(120)
10 ], 10 ],
11 MESSAGES: { 11 MESSAGES: {
12 'required': $localize`Display name is required.`, 12 required: $localize`Display name is required.`,
13 'minlength': $localize`Display name must be at least 1 character long.`, 13 minlength: $localize`Display name must be at least 1 character long.`,
14 'maxlength': $localize`Display name cannot be more than 120 characters long.` 14 maxlength: $localize`Display name cannot be more than 120 characters long.`
15 } 15 }
16} 16}
17 17
@@ -20,7 +20,7 @@ export const VIDEO_PLAYLIST_PRIVACY_VALIDATOR: BuildFormValidator = {
20 Validators.required 20 Validators.required
21 ], 21 ],
22 MESSAGES: { 22 MESSAGES: {
23 'required': $localize`Privacy is required.` 23 required: $localize`Privacy is required.`
24 } 24 }
25} 25}
26 26
@@ -30,21 +30,21 @@ export const VIDEO_PLAYLIST_DESCRIPTION_VALIDATOR: BuildFormValidator = {
30 Validators.maxLength(1000) 30 Validators.maxLength(1000)
31 ], 31 ],
32 MESSAGES: { 32 MESSAGES: {
33 'minlength': $localize`Description must be at least 3 characters long.`, 33 minlength: $localize`Description must be at least 3 characters long.`,
34 'maxlength': $localize`Description cannot be more than 1000 characters long.` 34 maxlength: $localize`Description cannot be more than 1000 characters long.`
35 } 35 }
36} 36}
37 37
38export const VIDEO_PLAYLIST_CHANNEL_ID_VALIDATOR: BuildFormValidator = { 38export const VIDEO_PLAYLIST_CHANNEL_ID_VALIDATOR: BuildFormValidator = {
39 VALIDATORS: [], 39 VALIDATORS: [],
40 MESSAGES: { 40 MESSAGES: {
41 'required': $localize`The channel is required when the playlist is public.` 41 required: $localize`The channel is required when the playlist is public.`
42 } 42 }
43} 43}
44 44
45export function setPlaylistChannelValidator (channelControl: AbstractControl, privacy: VideoPlaylistPrivacy) { 45export function setPlaylistChannelValidator (channelControl: AbstractControl, privacy: VideoPlaylistPrivacy) {
46 if (privacy.toString() === VideoPlaylistPrivacy.PUBLIC.toString()) { 46 if (privacy.toString() === VideoPlaylistPrivacy.PUBLIC.toString()) {
47 channelControl.setValidators([Validators.required]) 47 channelControl.setValidators([ Validators.required ])
48 } else { 48 } else {
49 channelControl.setValidators(null) 49 channelControl.setValidators(null)
50 } 50 }
diff --git a/client/src/app/shared/form-validators/video-validators.ts b/client/src/app/shared/form-validators/video-validators.ts
index 1382a7747..f96189aa2 100644
--- a/client/src/app/shared/form-validators/video-validators.ts
+++ b/client/src/app/shared/form-validators/video-validators.ts
@@ -12,17 +12,17 @@ export const trimValidator: ValidatorFn = (control: FormControl) => {
12export const VIDEO_NAME_VALIDATOR: BuildFormValidator = { 12export const VIDEO_NAME_VALIDATOR: BuildFormValidator = {
13 VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(120) ], 13 VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(120) ],
14 MESSAGES: { 14 MESSAGES: {
15 'required': $localize`Video name is required.`, 15 required: $localize`Video name is required.`,
16 'minlength': $localize`Video name must be at least 3 characters long.`, 16 minlength: $localize`Video name must be at least 3 characters long.`,
17 'maxlength': $localize`Video name cannot be more than 120 characters long.`, 17 maxlength: $localize`Video name cannot be more than 120 characters long.`,
18 'spaces': $localize`Video name has leading or trailing whitespace.` 18 spaces: $localize`Video name has leading or trailing whitespace.`
19 } 19 }
20} 20}
21 21
22export const VIDEO_PRIVACY_VALIDATOR: BuildFormValidator = { 22export const VIDEO_PRIVACY_VALIDATOR: BuildFormValidator = {
23 VALIDATORS: [ Validators.required ], 23 VALIDATORS: [ Validators.required ],
24 MESSAGES: { 24 MESSAGES: {
25 'required': $localize`Video privacy is required.` 25 required: $localize`Video privacy is required.`
26 } 26 }
27} 27}
28 28
@@ -49,46 +49,46 @@ export const VIDEO_IMAGE_VALIDATOR: BuildFormValidator = {
49export const VIDEO_CHANNEL_VALIDATOR: BuildFormValidator = { 49export const VIDEO_CHANNEL_VALIDATOR: BuildFormValidator = {
50 VALIDATORS: [ Validators.required ], 50 VALIDATORS: [ Validators.required ],
51 MESSAGES: { 51 MESSAGES: {
52 'required': $localize`Video channel is required.` 52 required: $localize`Video channel is required.`
53 } 53 }
54} 54}
55 55
56export const VIDEO_DESCRIPTION_VALIDATOR: BuildFormValidator = { 56export const VIDEO_DESCRIPTION_VALIDATOR: BuildFormValidator = {
57 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(10000) ], 57 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(10000) ],
58 MESSAGES: { 58 MESSAGES: {
59 'minlength': $localize`Video description must be at least 3 characters long.`, 59 minlength: $localize`Video description must be at least 3 characters long.`,
60 'maxlength': $localize`Video description cannot be more than 10000 characters long.` 60 maxlength: $localize`Video description cannot be more than 10000 characters long.`
61 } 61 }
62} 62}
63 63
64export const VIDEO_TAG_VALIDATOR: BuildFormValidator = { 64export const VIDEO_TAG_VALIDATOR: BuildFormValidator = {
65 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(30) ], 65 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(30) ],
66 MESSAGES: { 66 MESSAGES: {
67 'minlength': $localize`A tag should be more than 2 characters long.`, 67 minlength: $localize`A tag should be more than 2 characters long.`,
68 'maxlength': $localize`A tag should be less than 30 characters long.` 68 maxlength: $localize`A tag should be less than 30 characters long.`
69 } 69 }
70} 70}
71 71
72export const VIDEO_TAGS_ARRAY_VALIDATOR: BuildFormValidator = { 72export const VIDEO_TAGS_ARRAY_VALIDATOR: BuildFormValidator = {
73 VALIDATORS: [ Validators.maxLength(5), arrayTagLengthValidator() ], 73 VALIDATORS: [ Validators.maxLength(5), arrayTagLengthValidator() ],
74 MESSAGES: { 74 MESSAGES: {
75 'maxlength': $localize`A maximum of 5 tags can be used on a video.`, 75 maxlength: $localize`A maximum of 5 tags can be used on a video.`,
76 'arrayTagLength': $localize`A tag should be more than 1 and less than 30 characters long.` 76 arrayTagLength: $localize`A tag should be more than 1 and less than 30 characters long.`
77 } 77 }
78} 78}
79 79
80export const VIDEO_SUPPORT_VALIDATOR: BuildFormValidator = { 80export const VIDEO_SUPPORT_VALIDATOR: BuildFormValidator = {
81 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(1000) ], 81 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(1000) ],
82 MESSAGES: { 82 MESSAGES: {
83 'minlength': $localize`Video support must be at least 3 characters long.`, 83 minlength: $localize`Video support must be at least 3 characters long.`,
84 'maxlength': $localize`Video support cannot be more than 1000 characters long.` 84 maxlength: $localize`Video support cannot be more than 1000 characters long.`
85 } 85 }
86} 86}
87 87
88export const VIDEO_SCHEDULE_PUBLICATION_AT_VALIDATOR: BuildFormValidator = { 88export const VIDEO_SCHEDULE_PUBLICATION_AT_VALIDATOR: BuildFormValidator = {
89 VALIDATORS: [ ], 89 VALIDATORS: [ ],
90 MESSAGES: { 90 MESSAGES: {
91 'required': $localize`A date is required to schedule video update.` 91 required: $localize`A date is required to schedule video update.`
92 } 92 }
93} 93}
94 94
@@ -105,6 +105,6 @@ function arrayTagLengthValidator (min = 2, max = 30): ValidatorFn {
105 return null 105 return null
106 } 106 }
107 107
108 return { 'arrayTagLength': true } 108 return { arrayTagLength: true }
109 } 109 }
110} 110}
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
index e3bf9e1fb..33e9fd8de 100644
--- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
+++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
@@ -39,23 +39,23 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
39 39
40 inputFilters: AdvancedInputFilter[] = [ 40 inputFilters: AdvancedInputFilter[] = [
41 { 41 {
42 queryParams: { 'search': 'state:pending' }, 42 queryParams: { search: 'state:pending' },
43 label: $localize`Unsolved reports` 43 label: $localize`Unsolved reports`
44 }, 44 },
45 { 45 {
46 queryParams: { 'search': 'state:accepted' }, 46 queryParams: { search: 'state:accepted' },
47 label: $localize`Accepted reports` 47 label: $localize`Accepted reports`
48 }, 48 },
49 { 49 {
50 queryParams: { 'search': 'state:rejected' }, 50 queryParams: { search: 'state:rejected' },
51 label: $localize`Refused reports` 51 label: $localize`Refused reports`
52 }, 52 },
53 { 53 {
54 queryParams: { 'search': 'videoIs:blacklisted' }, 54 queryParams: { search: 'videoIs:blacklisted' },
55 label: $localize`Reports with blocked videos` 55 label: $localize`Reports with blocked videos`
56 }, 56 },
57 { 57 {
58 queryParams: { 'search': 'videoIs:deleted' }, 58 queryParams: { search: 'videoIs:deleted' },
59 label: $localize`Reports with deleted videos` 59 label: $localize`Reports with deleted videos`
60 } 60 }
61 ] 61 ]
diff --git a/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts b/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
index 06f1555ea..ccb0c5262 100644
--- a/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
+++ b/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
@@ -50,7 +50,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
50 } 50 }
51 51
52 async banUser () { 52 async banUser () {
53 const moderationComment: string = this.form.value[ 'moderationComment' ] 53 const moderationComment: string = this.form.value['moderationComment']
54 54
55 this.abuseService.updateAbuse(this.abuseToComment, { moderationComment }) 55 this.abuseService.updateAbuse(this.abuseToComment, { moderationComment })
56 .subscribe({ 56 .subscribe({
diff --git a/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts b/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts
index fce1a8db3..194d52a33 100644
--- a/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts
+++ b/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts
@@ -5,7 +5,7 @@ import { Account } from '@app/shared/shared-main'
5// Don't use an abuse model because we need external services to compute some properties 5// Don't use an abuse model because we need external services to compute some properties
6// And this model is only used in this component 6// And this model is only used in this component
7export type ProcessedAbuse = AdminAbuse & { 7export type ProcessedAbuse = AdminAbuse & {
8 moderationCommentHtml?: string, 8 moderationCommentHtml?: string
9 reasonHtml?: string 9 reasonHtml?: string
10 embedHtml?: SafeHtml 10 embedHtml?: SafeHtml
11 updatedAt?: Date 11 updatedAt?: Date
diff --git a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts
index dc9b72ddb..2c0e45e20 100644
--- a/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts
+++ b/client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.ts
@@ -51,7 +51,7 @@ export class ActorAvatarEditComponent implements OnInit {
51 onAvatarChange (input: HTMLInputElement) { 51 onAvatarChange (input: HTMLInputElement) {
52 this.avatarfileInput = new ElementRef(input) 52 this.avatarfileInput = new ElementRef(input)
53 53
54 const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ] 54 const avatarfile = this.avatarfileInput.nativeElement.files[0]
55 if (avatarfile.size > this.maxAvatarSize) { 55 if (avatarfile.size > this.maxAvatarSize) {
56 this.notifier.error('Error', $localize`This image is too large.`) 56 this.notifier.error('Error', $localize`This image is too large.`)
57 return 57 return
diff --git a/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts
index c3f10c055..cba2c5db3 100644
--- a/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts
+++ b/client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.ts
@@ -40,14 +40,14 @@ export class ActorBannerEditComponent implements OnInit {
40 this.maxBannerSize = config.banner.file.size.max 40 this.maxBannerSize = config.banner.file.size.max
41 this.bannerExtensions = config.banner.file.extensions.join(', ') 41 this.bannerExtensions = config.banner.file.extensions.join(', ')
42 42
43 // tslint:disable:max-line-length 43 /* eslint-disable max-len */
44 this.bannerFormat = $localize`ratio 6/1, recommended size: 1920x317, max size: ${getBytes(this.maxBannerSize)}, extensions: ${this.bannerExtensions}` 44 this.bannerFormat = $localize`ratio 6/1, recommended size: 1920x317, max size: ${getBytes(this.maxBannerSize)}, extensions: ${this.bannerExtensions}`
45 } 45 }
46 46
47 onBannerChange (input: HTMLInputElement) { 47 onBannerChange (input: HTMLInputElement) {
48 this.bannerfileInput = new ElementRef(input) 48 this.bannerfileInput = new ElementRef(input)
49 49
50 const bannerfile = this.bannerfileInput.nativeElement.files[ 0 ] 50 const bannerfile = this.bannerfileInput.nativeElement.files[0]
51 if (bannerfile.size > this.maxBannerSize) { 51 if (bannerfile.size > this.maxBannerSize) {
52 this.notifier.error('Error', $localize`This image is too large.`) 52 this.notifier.error('Error', $localize`This image is too large.`)
53 return 53 return
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts
index b06c2bae6..a4adfd1b7 100644
--- a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts
+++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts
@@ -17,6 +17,8 @@ export type ActorAvatarSize = '18' | '25' | '32' | '34' | '36' | '40' | '100' |
17 templateUrl: './actor-avatar.component.html' 17 templateUrl: './actor-avatar.component.html'
18}) 18})
19export class ActorAvatarComponent { 19export class ActorAvatarComponent {
20 private _title: string
21
20 @Input() account: ActorInput 22 @Input() account: ActorInput
21 @Input() channel: ActorInput 23 @Input() channel: ActorInput
22 24
@@ -33,8 +35,6 @@ export class ActorAvatarComponent {
33 this._title = value 35 this._title = value
34 } 36 }
35 37
36 private _title: string
37
38 get title () { 38 get title () {
39 if (this._title) return this._title 39 if (this._title) return this._title
40 if (this.account) return $localize`${this.account.name} (account page)` 40 if (this.account) return $localize`${this.account.name} (account page)`
@@ -50,22 +50,6 @@ export class ActorAvatarComponent {
50 return '' 50 return ''
51 } 51 }
52 52
53 getClass (type: 'avatar' | 'initial') {
54 const base = [ 'avatar' ]
55
56 if (this.size) base.push(`avatar-${this.size}`)
57
58 if (this.channel) base.push('channel')
59 else base.push('account')
60
61 if (type === 'initial' && this.initial) {
62 base.push('initial')
63 base.push(this.getColorTheme())
64 }
65
66 return base
67 }
68
69 get defaultAvatarUrl () { 53 get defaultAvatarUrl () {
70 if (this.channel) return VideoChannel.GET_DEFAULT_AVATAR_URL() 54 if (this.channel) return VideoChannel.GET_DEFAULT_AVATAR_URL()
71 55
@@ -86,6 +70,22 @@ export class ActorAvatarComponent {
86 return name.slice(0, 1) 70 return name.slice(0, 1)
87 } 71 }
88 72
73 getClass (type: 'avatar' | 'initial') {
74 const base = [ 'avatar' ]
75
76 if (this.size) base.push(`avatar-${this.size}`)
77
78 if (this.channel) base.push('channel')
79 else base.push('account')
80
81 if (type === 'initial' && this.initial) {
82 base.push('initial')
83 base.push(this.getColorTheme())
84 }
85
86 return base
87 }
88
89 hasActor () { 89 hasActor () {
90 return !!this.account || !!this.channel 90 return !!this.account || !!this.channel
91 } 91 }
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
index 8c1357d7a..35b413b60 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
@@ -39,9 +39,13 @@ export class ChannelMiniatureMarkupComponent implements CustomMarkupComponent, O
39 ngOnInit () { 39 ngOnInit () {
40 this.findInBulk.getChannel(this.name) 40 this.findInBulk.getChannel(this.name)
41 .pipe( 41 .pipe(
42 tap(channel => this.channel = channel), 42 tap(channel => {
43 this.channel = channel
44 }),
43 switchMap(() => from(this.markdown.textMarkdownToHTML(this.channel.description))), 45 switchMap(() => from(this.markdown.textMarkdownToHTML(this.channel.description))),
44 tap(html => this.descriptionHTML = html), 46 tap(html => {
47 this.descriptionHTML = html
48 }),
45 switchMap(() => this.loadVideosObservable()), 49 switchMap(() => this.loadVideosObservable()),
46 finalize(() => this.loaded.emit(true)) 50 finalize(() => this.loaded.emit(true))
47 ).subscribe({ 51 ).subscribe({
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
index 56b43d85e..7315126e0 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
@@ -1,10 +1,10 @@
1import { finalize } from 'rxjs/operators' 1import { finalize } from 'rxjs/operators'
2import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' 2import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
3import { AuthService, Notifier } from '@app/core' 3import { AuthService, Notifier } from '@app/core'
4import { Video, VideoService } from '../../shared-main' 4import { FindInBulkService } from '@app/shared/shared-search'
5import { Video } from '../../shared-main'
5import { MiniatureDisplayOptions } from '../../shared-video-miniature' 6import { MiniatureDisplayOptions } from '../../shared-video-miniature'
6import { CustomMarkupComponent } from './shared' 7import { CustomMarkupComponent } from './shared'
7import { FindInBulkService } from '@app/shared/shared-search'
8 8
9/* 9/*
10 * Markup component that creates a video miniature only 10 * Markup component that creates a video miniature only
diff --git a/client/src/app/shared/shared-forms/form-reactive.ts b/client/src/app/shared/shared-forms/form-reactive.ts
index adf6cb894..f2ce82360 100644
--- a/client/src/app/shared/shared-forms/form-reactive.ts
+++ b/client/src/app/shared/shared-forms/form-reactive.ts
@@ -51,7 +51,7 @@ export abstract class FormReactive {
51 } 51 }
52 52
53 // clear previous error message (if any) 53 // clear previous error message (if any)
54 formErrors[ field ] = '' 54 formErrors[field] = ''
55 const control = form.get(field) 55 const control = form.get(field)
56 56
57 if (control.dirty) this.formChanged = true 57 if (control.dirty) this.formChanged = true
@@ -59,9 +59,9 @@ export abstract class FormReactive {
59 // Don't care if dirty on force check 59 // Don't care if dirty on force check
60 const isDirty = control.dirty || forceCheck === true 60 const isDirty = control.dirty || forceCheck === true
61 if (control && isDirty && control.enabled && !control.valid) { 61 if (control && isDirty && control.enabled && !control.valid) {
62 const messages = validationMessages[ field ] 62 const messages = validationMessages[field]
63 for (const key of Object.keys(control.errors)) { 63 for (const key of Object.keys(control.errors)) {
64 formErrors[ field ] += messages[ key ] + ' ' 64 formErrors[field] += messages[key] + ' '
65 } 65 }
66 } 66 }
67 } 67 }
diff --git a/client/src/app/shared/shared-forms/form-validator.service.ts b/client/src/app/shared/shared-forms/form-validator.service.ts
index 41c8b76bd..c0664de5f 100644
--- a/client/src/app/shared/shared-forms/form-validator.service.ts
+++ b/client/src/app/shared/shared-forms/form-validator.service.ts
@@ -28,11 +28,11 @@ export class FormValidatorService {
28 continue 28 continue
29 } 29 }
30 30
31 if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string } 31 if (field?.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
32 32
33 const defaultValue = defaultValues[name] || '' 33 const defaultValue = defaultValues[name] || ''
34 34
35 if (field && field.VALIDATORS) group[name] = [ defaultValue, field.VALIDATORS ] 35 if (field?.VALIDATORS) group[name] = [ defaultValue, field.VALIDATORS ]
36 else group[name] = [ defaultValue ] 36 else group[name] = [ defaultValue ]
37 } 37 }
38 38
@@ -62,11 +62,11 @@ export class FormValidatorService {
62 continue 62 continue
63 } 63 }
64 64
65 if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string } 65 if (field?.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
66 66
67 const defaultValue = defaultValues[name] || '' 67 const defaultValue = defaultValues[name] || ''
68 68
69 if (field && field.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS as ValidatorFn[])) 69 if (field?.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS as ValidatorFn[]))
70 else form.addControl(name, new FormControl(defaultValue)) 70 else form.addControl(name, new FormControl(defaultValue))
71 } 71 }
72 } 72 }
diff --git a/client/src/app/shared/shared-forms/reactive-file.component.ts b/client/src/app/shared/shared-forms/reactive-file.component.ts
index fac3dfb3a..9d27ad07a 100644
--- a/client/src/app/shared/shared-forms/reactive-file.component.ts
+++ b/client/src/app/shared/shared-forms/reactive-file.component.ts
@@ -43,7 +43,7 @@ export class ReactiveFileComponent implements OnInit, ControlValueAccessor {
43 } 43 }
44 44
45 fileChange (event: any) { 45 fileChange (event: any) {
46 if (event.target.files && event.target.files.length) { 46 if (event.target.files?.length) {
47 const [ file ] = event.target.files 47 const [ file ] = event.target.files
48 48
49 if (file.size > this.maxFileSize) { 49 if (file.size > this.maxFileSize) {
diff --git a/client/src/app/shared/shared-icons/global-icon.component.ts b/client/src/app/shared/shared-icons/global-icon.component.ts
index a47f07fc3..cb5f31c8e 100644
--- a/client/src/app/shared/shared-icons/global-icon.component.ts
+++ b/client/src/app/shared/shared-icons/global-icon.component.ts
@@ -3,77 +3,77 @@ import { HooksService } from '@app/core/plugins/hooks.service'
3 3
4const icons = { 4const icons = {
5 // misc icons 5 // misc icons
6 'npm': require('!!raw-loader?!../../../assets/images/misc/npm.svg').default, 6 npm: require('!!raw-loader?!../../../assets/images/misc/npm.svg').default,
7 'markdown': require('!!raw-loader?!../../../assets/images/misc/markdown.svg').default, 7 markdown: require('!!raw-loader?!../../../assets/images/misc/markdown.svg').default,
8 'language': require('!!raw-loader?!../../../assets/images/misc/language.svg').default, 8 language: require('!!raw-loader?!../../../assets/images/misc/language.svg').default,
9 'video-lang': require('!!raw-loader?!../../../assets/images/misc/video-lang.svg').default, 9 'video-lang': require('!!raw-loader?!../../../assets/images/misc/video-lang.svg').default,
10 'support': require('!!raw-loader?!../../../assets/images/misc/support.svg').default, 10 support: require('!!raw-loader?!../../../assets/images/misc/support.svg').default,
11 'peertube-x': require('!!raw-loader?!../../../assets/images/misc/peertube-x.svg').default, 11 'peertube-x': require('!!raw-loader?!../../../assets/images/misc/peertube-x.svg').default,
12 'robot': require('!!raw-loader?!../../../assets/images/misc/miscellaneous-services.svg').default, // material ui 12 robot: require('!!raw-loader?!../../../assets/images/misc/miscellaneous-services.svg').default, // material ui
13 'videos': require('!!raw-loader?!../../../assets/images/misc/video-library.svg').default, // material ui 13 videos: require('!!raw-loader?!../../../assets/images/misc/video-library.svg').default, // material ui
14 'history': require('!!raw-loader?!../../../assets/images/misc/history.svg').default, // material ui 14 history: require('!!raw-loader?!../../../assets/images/misc/history.svg').default, // material ui
15 'subscriptions': require('!!raw-loader?!../../../assets/images/misc/subscriptions.svg').default, // material ui 15 subscriptions: require('!!raw-loader?!../../../assets/images/misc/subscriptions.svg').default, // material ui
16 'playlist-add': require('!!raw-loader?!../../../assets/images/misc/playlist-add.svg').default, // material ui 16 'playlist-add': require('!!raw-loader?!../../../assets/images/misc/playlist-add.svg').default, // material ui
17 'follower': require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui 17 follower: require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui
18 'following': require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui 18 following: require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui
19 'flame': require('!!raw-loader?!../../../assets/images/misc/flame.svg').default, 19 flame: require('!!raw-loader?!../../../assets/images/misc/flame.svg').default,
20 'local': require('!!raw-loader?!../../../assets/images/misc/local.svg').default, 20 local: require('!!raw-loader?!../../../assets/images/misc/local.svg').default,
21 21
22 // feather icons 22 // feather icons
23 'flag': require('!!raw-loader?!../../../assets/images/feather/flag.svg').default, 23 flag: require('!!raw-loader?!../../../assets/images/feather/flag.svg').default,
24 'playlists': require('!!raw-loader?!../../../assets/images/feather/list.svg').default, 24 playlists: require('!!raw-loader?!../../../assets/images/feather/list.svg').default,
25 'syndication': require('!!raw-loader?!../../../assets/images/feather/syndication.svg').default, 25 syndication: require('!!raw-loader?!../../../assets/images/feather/syndication.svg').default,
26 'help': require('!!raw-loader?!../../../assets/images/feather/help.svg').default, 26 help: require('!!raw-loader?!../../../assets/images/feather/help.svg').default,
27 'alert': require('!!raw-loader?!../../../assets/images/feather/alert.svg').default, 27 alert: require('!!raw-loader?!../../../assets/images/feather/alert.svg').default,
28 'globe': require('!!raw-loader?!../../../assets/images/feather/globe.svg').default, 28 globe: require('!!raw-loader?!../../../assets/images/feather/globe.svg').default,
29 'home': require('!!raw-loader?!../../../assets/images/feather/home.svg').default, 29 home: require('!!raw-loader?!../../../assets/images/feather/home.svg').default,
30 'recently-added': require('!!raw-loader?!../../../assets/images/feather/recently-added.svg').default, 30 'recently-added': require('!!raw-loader?!../../../assets/images/feather/recently-added.svg').default,
31 'trending': require('!!raw-loader?!../../../assets/images/feather/trending.svg').default, 31 trending: require('!!raw-loader?!../../../assets/images/feather/trending.svg').default,
32 'search': require('!!raw-loader?!../../../assets/images/feather/search.svg').default, 32 search: require('!!raw-loader?!../../../assets/images/feather/search.svg').default,
33 'upload': require('!!raw-loader?!../../../assets/images/feather/upload.svg').default, 33 upload: require('!!raw-loader?!../../../assets/images/feather/upload.svg').default,
34 'dislike': require('!!raw-loader?!../../../assets/images/feather/dislike.svg').default, 34 dislike: require('!!raw-loader?!../../../assets/images/feather/dislike.svg').default,
35 'like': require('!!raw-loader?!../../../assets/images/feather/like.svg').default, 35 like: require('!!raw-loader?!../../../assets/images/feather/like.svg').default,
36 'no': require('!!raw-loader?!../../../assets/images/feather/no.svg').default, 36 no: require('!!raw-loader?!../../../assets/images/feather/no.svg').default,
37 'cloud-download': require('!!raw-loader?!../../../assets/images/feather/cloud-download.svg').default, 37 'cloud-download': require('!!raw-loader?!../../../assets/images/feather/cloud-download.svg').default,
38 'clock': require('!!raw-loader?!../../../assets/images/feather/clock.svg').default, 38 clock: require('!!raw-loader?!../../../assets/images/feather/clock.svg').default,
39 'cog': require('!!raw-loader?!../../../assets/images/feather/cog.svg').default, 39 cog: require('!!raw-loader?!../../../assets/images/feather/cog.svg').default,
40 'delete': require('!!raw-loader?!../../../assets/images/feather/delete.svg').default, 40 delete: require('!!raw-loader?!../../../assets/images/feather/delete.svg').default,
41 'bell': require('!!raw-loader?!../../../assets/images/feather/bell.svg').default, 41 bell: require('!!raw-loader?!../../../assets/images/feather/bell.svg').default,
42 'sign-out': require('!!raw-loader?!../../../assets/images/feather/log-out.svg').default, 42 'sign-out': require('!!raw-loader?!../../../assets/images/feather/log-out.svg').default,
43 'sign-in': require('!!raw-loader?!../../../assets/images/feather/log-in.svg').default, 43 'sign-in': require('!!raw-loader?!../../../assets/images/feather/log-in.svg').default,
44 'download': require('!!raw-loader?!../../../assets/images/feather/download.svg').default, 44 download: require('!!raw-loader?!../../../assets/images/feather/download.svg').default,
45 'ownership-change': require('!!raw-loader?!../../../assets/images/feather/share.svg').default, 45 'ownership-change': require('!!raw-loader?!../../../assets/images/feather/share.svg').default,
46 'share': require('!!raw-loader?!../../../assets/images/feather/share-2.svg').default, 46 share: require('!!raw-loader?!../../../assets/images/feather/share-2.svg').default,
47 'channel': require('!!raw-loader?!../../../assets/images/feather/tv.svg').default, 47 channel: require('!!raw-loader?!../../../assets/images/feather/tv.svg').default,
48 'user': require('!!raw-loader?!../../../assets/images/feather/user.svg').default, 48 user: require('!!raw-loader?!../../../assets/images/feather/user.svg').default,
49 'user-x': require('!!raw-loader?!../../../assets/images/feather/user-x.svg').default, 49 'user-x': require('!!raw-loader?!../../../assets/images/feather/user-x.svg').default,
50 'users': require('!!raw-loader?!../../../assets/images/feather/users.svg').default, 50 users: require('!!raw-loader?!../../../assets/images/feather/users.svg').default,
51 'user-add': require('!!raw-loader?!../../../assets/images/feather/user-plus.svg').default, 51 'user-add': require('!!raw-loader?!../../../assets/images/feather/user-plus.svg').default,
52 'add': require('!!raw-loader?!../../../assets/images/feather/plus-circle.svg').default, 52 add: require('!!raw-loader?!../../../assets/images/feather/plus-circle.svg').default,
53 'cloud-error': require('!!raw-loader?!../../../assets/images/feather/cloud-off.svg').default, 53 'cloud-error': require('!!raw-loader?!../../../assets/images/feather/cloud-off.svg').default,
54 'undo': require('!!raw-loader?!../../../assets/images/feather/corner-up-left.svg').default, 54 undo: require('!!raw-loader?!../../../assets/images/feather/corner-up-left.svg').default,
55 'circle-tick': require('!!raw-loader?!../../../assets/images/feather/check-circle.svg').default, 55 'circle-tick': require('!!raw-loader?!../../../assets/images/feather/check-circle.svg').default,
56 'more-horizontal': require('!!raw-loader?!../../../assets/images/feather/more-horizontal.svg').default, 56 'more-horizontal': require('!!raw-loader?!../../../assets/images/feather/more-horizontal.svg').default,
57 'more-vertical': require('!!raw-loader?!../../../assets/images/feather/more-vertical.svg').default, 57 'more-vertical': require('!!raw-loader?!../../../assets/images/feather/more-vertical.svg').default,
58 'play': require('!!raw-loader?!../../../assets/images/feather/play.svg').default, 58 play: require('!!raw-loader?!../../../assets/images/feather/play.svg').default,
59 'p2p': require('!!raw-loader?!../../../assets/images/feather/airplay.svg').default, 59 p2p: require('!!raw-loader?!../../../assets/images/feather/airplay.svg').default,
60 'fullscreen': require('!!raw-loader?!../../../assets/images/feather/maximize.svg').default, 60 fullscreen: require('!!raw-loader?!../../../assets/images/feather/maximize.svg').default,
61 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/feather/minimize.svg').default, 61 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/feather/minimize.svg').default,
62 'film': require('!!raw-loader?!../../../assets/images/feather/film.svg').default, 62 film: require('!!raw-loader?!../../../assets/images/feather/film.svg').default,
63 'edit': require('!!raw-loader?!../../../assets/images/feather/edit-2.svg').default, 63 edit: require('!!raw-loader?!../../../assets/images/feather/edit-2.svg').default,
64 'sensitive': require('!!raw-loader?!../../../assets/images/feather/eye.svg').default, 64 sensitive: require('!!raw-loader?!../../../assets/images/feather/eye.svg').default,
65 'unsensitive': require('!!raw-loader?!../../../assets/images/feather/eye-off.svg').default, 65 unsensitive: require('!!raw-loader?!../../../assets/images/feather/eye-off.svg').default,
66 'refresh': require('!!raw-loader?!../../../assets/images/feather/refresh-cw.svg').default, 66 refresh: require('!!raw-loader?!../../../assets/images/feather/refresh-cw.svg').default,
67 'command': require('!!raw-loader?!../../../assets/images/feather/command.svg').default, 67 command: require('!!raw-loader?!../../../assets/images/feather/command.svg').default,
68 'go': require('!!raw-loader?!../../../assets/images/feather/arrow-up-right.svg').default, 68 go: require('!!raw-loader?!../../../assets/images/feather/arrow-up-right.svg').default,
69 'cross': require('!!raw-loader?!../../../assets/images/feather/x.svg').default, 69 cross: require('!!raw-loader?!../../../assets/images/feather/x.svg').default,
70 'tick': require('!!raw-loader?!../../../assets/images/feather/check.svg').default, 70 tick: require('!!raw-loader?!../../../assets/images/feather/check.svg').default,
71 'columns': require('!!raw-loader?!../../../assets/images/feather/columns.svg').default, 71 columns: require('!!raw-loader?!../../../assets/images/feather/columns.svg').default,
72 'live': require('!!raw-loader?!../../../assets/images/feather/live.svg').default, 72 live: require('!!raw-loader?!../../../assets/images/feather/live.svg').default,
73 'repeat': require('!!raw-loader?!../../../assets/images/feather/repeat.svg').default, 73 repeat: require('!!raw-loader?!../../../assets/images/feather/repeat.svg').default,
74 'message-circle': require('!!raw-loader?!../../../assets/images/feather/message-circle.svg').default, 74 'message-circle': require('!!raw-loader?!../../../assets/images/feather/message-circle.svg').default,
75 'codesandbox': require('!!raw-loader?!../../../assets/images/feather/codesandbox.svg').default, 75 codesandbox: require('!!raw-loader?!../../../assets/images/feather/codesandbox.svg').default,
76 'award': require('!!raw-loader?!../../../assets/images/feather/award.svg').default 76 award: require('!!raw-loader?!../../../assets/images/feather/award.svg').default
77} 77}
78 78
79export type GlobalIconName = keyof typeof icons 79export type GlobalIconName = keyof typeof icons
diff --git a/client/src/app/shared/shared-instance/instance-about-accordion.component.ts b/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
index 855c06aa1..1eb7b49b6 100644
--- a/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
+++ b/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
@@ -7,7 +7,7 @@ import { About } from '@shared/models/server'
7@Component({ 7@Component({
8 selector: 'my-instance-about-accordion', 8 selector: 'my-instance-about-accordion',
9 templateUrl: './instance-about-accordion.component.html', 9 templateUrl: './instance-about-accordion.component.html',
10 styleUrls: ['./instance-about-accordion.component.scss'] 10 styleUrls: [ './instance-about-accordion.component.scss' ]
11}) 11})
12export class InstanceAboutAccordionComponent implements OnInit { 12export class InstanceAboutAccordionComponent implements OnInit {
13 @ViewChild('accordion', { static: true }) accordion: NgbAccordion 13 @ViewChild('accordion', { static: true }) accordion: NgbAccordion
diff --git a/client/src/app/shared/shared-instance/instance-follow.service.ts b/client/src/app/shared/shared-instance/instance-follow.service.ts
index af44020cf..a6799d3e1 100644
--- a/client/src/app/shared/shared-instance/instance-follow.service.ts
+++ b/client/src/app/shared/shared-instance/instance-follow.service.ts
@@ -19,10 +19,10 @@ export class InstanceFollowService {
19 } 19 }
20 20
21 getFollowing (options: { 21 getFollowing (options: {
22 pagination: RestPagination, 22 pagination: RestPagination
23 sort: SortMeta, 23 sort: SortMeta
24 search?: string, 24 search?: string
25 actorType?: ActivityPubActorType, 25 actorType?: ActivityPubActorType
26 state?: FollowState 26 state?: FollowState
27 }): Observable<ResultList<ActorFollow>> { 27 }): Observable<ResultList<ActorFollow>> {
28 const { pagination, sort, search, state, actorType } = options 28 const { pagination, sort, search, state, actorType } = options
@@ -42,10 +42,10 @@ export class InstanceFollowService {
42 } 42 }
43 43
44 getFollowers (options: { 44 getFollowers (options: {
45 pagination: RestPagination, 45 pagination: RestPagination
46 sort: SortMeta, 46 sort: SortMeta
47 search?: string, 47 search?: string
48 actorType?: ActivityPubActorType, 48 actorType?: ActivityPubActorType
49 state?: FollowState 49 state?: FollowState
50 }): Observable<ResultList<ActorFollow>> { 50 }): Observable<ResultList<ActorFollow>> {
51 const { pagination, sort, search, state, actorType } = options 51 const { pagination, sort, search, state, actorType } = options
diff --git a/client/src/app/shared/shared-instance/instance-statistics.component.ts b/client/src/app/shared/shared-instance/instance-statistics.component.ts
index 40aa8a4c0..0618efe69 100644
--- a/client/src/app/shared/shared-instance/instance-statistics.component.ts
+++ b/client/src/app/shared/shared-instance/instance-statistics.component.ts
@@ -17,6 +17,8 @@ export class InstanceStatisticsComponent implements OnInit {
17 17
18 ngOnInit () { 18 ngOnInit () {
19 this.serverService.getServerStats() 19 this.serverService.getServerStats()
20 .subscribe(res => this.serverStats = res) 20 .subscribe(res => {
21 this.serverStats = res
22 })
21 } 23 }
22} 24}
diff --git a/client/src/app/shared/shared-instance/instance.service.ts b/client/src/app/shared/shared-instance/instance.service.ts
index 70e022178..0241f56ef 100644
--- a/client/src/app/shared/shared-instance/instance.service.ts
+++ b/client/src/app/shared/shared-instance/instance.service.ts
@@ -51,7 +51,7 @@ export class InstanceService {
51 } 51 }
52 52
53 for (const key of Object.keys(html)) { 53 for (const key of Object.keys(html)) {
54 html[ key ] = await this.markdownService.textMarkdownToHTML(about.instance[ key ]) 54 html[key] = await this.markdownService.textMarkdownToHTML(about.instance[key])
55 } 55 }
56 56
57 return html 57 return html
diff --git a/client/src/app/shared/shared-instance/shared-instance.module.ts b/client/src/app/shared/shared-instance/shared-instance.module.ts
index 5efb95a7d..13c681ab8 100644
--- a/client/src/app/shared/shared-instance/shared-instance.module.ts
+++ b/client/src/app/shared/shared-instance/shared-instance.module.ts
@@ -1,7 +1,6 @@
1 1
2import { NgModule } from '@angular/core' 2import { NgModule } from '@angular/core'
3import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap' 3import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'
4import { SharedCustomMarkupModule } from '../shared-custom-markup'
5import { SharedMainModule } from '../shared-main/shared-main.module' 4import { SharedMainModule } from '../shared-main/shared-main.module'
6import { FeatureBooleanComponent } from './feature-boolean.component' 5import { FeatureBooleanComponent } from './feature-boolean.component'
7import { InstanceAboutAccordionComponent } from './instance-about-accordion.component' 6import { InstanceAboutAccordionComponent } from './instance-about-accordion.component'
diff --git a/client/src/app/shared/shared-main/account/account.model.ts b/client/src/app/shared/shared-main/account/account.model.ts
index 7b5611f35..92606e7fa 100644
--- a/client/src/app/shared/shared-main/account/account.model.ts
+++ b/client/src/app/shared/shared-main/account/account.model.ts
@@ -1,4 +1,4 @@
1import { Account as ServerAccount, Actor as ServerActor, ActorImage } from '@shared/models' 1import { Account as ServerAccount, ActorImage } from '@shared/models'
2import { Actor } from './actor.model' 2import { Actor } from './actor.model'
3 3
4export class Account extends Actor implements ServerAccount { 4export class Account extends Actor implements ServerAccount {
diff --git a/client/src/app/shared/shared-main/account/actor.model.ts b/client/src/app/shared/shared-main/account/actor.model.ts
index 2fccc472a..082f44fb9 100644
--- a/client/src/app/shared/shared-main/account/actor.model.ts
+++ b/client/src/app/shared/shared-main/account/actor.model.ts
@@ -20,7 +20,7 @@ export abstract class Actor implements ServerActor {
20 static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) { 20 static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) {
21 if (actor?.avatar?.url) return actor.avatar.url 21 if (actor?.avatar?.url) return actor.avatar.url
22 22
23 if (actor && actor.avatar) { 23 if (actor?.avatar) {
24 const absoluteAPIUrl = getAbsoluteAPIUrl() 24 const absoluteAPIUrl = getAbsoluteAPIUrl()
25 25
26 return absoluteAPIUrl + actor.avatar.path 26 return absoluteAPIUrl + actor.avatar.path
diff --git a/client/src/app/shared/shared-main/angular/autofocus.directive.ts b/client/src/app/shared/shared-main/angular/autofocus.directive.ts
index 5f087d79d..2da492ea1 100644
--- a/client/src/app/shared/shared-main/angular/autofocus.directive.ts
+++ b/client/src/app/shared/shared-main/angular/autofocus.directive.ts
@@ -1,7 +1,7 @@
1import { AfterViewInit, Directive, ElementRef } from '@angular/core' 1import { AfterViewInit, Directive, ElementRef } from '@angular/core'
2 2
3@Directive({ 3@Directive({
4 selector: '[autofocus]' 4 selector: '[myAutofocus]'
5}) 5})
6export class AutofocusDirective implements AfterViewInit { 6export class AutofocusDirective implements AfterViewInit {
7 constructor (private host: ElementRef) { } 7 constructor (private host: ElementRef) { }
diff --git a/client/src/app/shared/shared-main/angular/link.component.ts b/client/src/app/shared/shared-main/angular/link.component.ts
index 597a16871..ecbd9151c 100644
--- a/client/src/app/shared/shared-main/angular/link.component.ts
+++ b/client/src/app/shared/shared-main/angular/link.component.ts
@@ -1,4 +1,4 @@
1import { Component, Input, ViewEncapsulation } from '@angular/core' 1import { Component, Input } from '@angular/core'
2 2
3@Component({ 3@Component({
4 selector: 'my-link', 4 selector: 'my-link',
diff --git a/client/src/app/shared/shared-main/angular/peertube-template.directive.ts b/client/src/app/shared/shared-main/angular/peertube-template.directive.ts
index e04c25d9a..dc0cde12d 100644
--- a/client/src/app/shared/shared-main/angular/peertube-template.directive.ts
+++ b/client/src/app/shared/shared-main/angular/peertube-template.directive.ts
@@ -1,6 +1,7 @@
1import { Directive, Input, TemplateRef } from '@angular/core' 1import { Directive, Input, TemplateRef } from '@angular/core'
2 2
3@Directive({ 3@Directive({
4 // eslint-disable-next-line @angular-eslint/directive-selector
4 selector: '[ptTemplate]' 5 selector: '[ptTemplate]'
5}) 6})
6export class PeerTubeTemplateDirective <T extends string> { 7export class PeerTubeTemplateDirective <T extends string> {
diff --git a/client/src/app/shared/shared-main/feeds/syndication.model.ts b/client/src/app/shared/shared-main/feeds/syndication.model.ts
index 2466ae7c6..cd6fbdb48 100644
--- a/client/src/app/shared/shared-main/feeds/syndication.model.ts
+++ b/client/src/app/shared/shared-main/feeds/syndication.model.ts
@@ -1,7 +1,7 @@
1import { FeedFormat } from '@shared/models' 1import { FeedFormat } from '@shared/models'
2 2
3export interface Syndication { 3export interface Syndication {
4 format: FeedFormat, 4 format: FeedFormat
5 label: string, 5 label: string
6 url: string 6 url: string
7} 7}
diff --git a/client/src/app/shared/shared-main/misc/help.component.ts b/client/src/app/shared/shared-main/misc/help.component.ts
index 76e255d99..37e2abd97 100644
--- a/client/src/app/shared/shared-main/misc/help.component.ts
+++ b/client/src/app/shared/shared-main/misc/help.component.ts
@@ -71,18 +71,18 @@ export class HelpComponent implements OnInit, OnChanges, AfterContentInit {
71 } 71 }
72 72
73 private formatMarkdownSupport (rules: string[]) { 73 private formatMarkdownSupport (rules: string[]) {
74 // tslint:disable:max-line-length 74 /* eslint-disable max-len */
75 return $localize`<a href="https://en.wikipedia.org/wiki/Markdown#Example" target="_blank" rel="noopener noreferrer">Markdown</a> compatible that supports:` + 75 return $localize`<a href="https://en.wikipedia.org/wiki/Markdown#Example" target="_blank" rel="noopener noreferrer">Markdown</a> compatible that supports:` +
76 this.createMarkdownList(rules) 76 this.createMarkdownList(rules)
77 } 77 }
78 78
79 private createMarkdownList (rules: string[]) { 79 private createMarkdownList (rules: string[]) {
80 const rulesToText = { 80 const rulesToText = {
81 'emphasis': $localize`Emphasis`, 81 emphasis: $localize`Emphasis`,
82 'link': $localize`Links`, 82 link: $localize`Links`,
83 'newline': $localize`New lines`, 83 newline: $localize`New lines`,
84 'list': $localize`Lists`, 84 list: $localize`Lists`,
85 'image': $localize`Images` 85 image: $localize`Images`
86 } 86 }
87 87
88 const bullets = rules.map(r => rulesToText[r]) 88 const bullets = rules.map(r => rulesToText[r])
diff --git a/client/src/app/shared/shared-main/misc/list-overflow.component.ts b/client/src/app/shared/shared-main/misc/list-overflow.component.ts
index 144e0f156..fbc481093 100644
--- a/client/src/app/shared/shared-main/misc/list-overflow.component.ts
+++ b/client/src/app/shared/shared-main/misc/list-overflow.component.ts
@@ -22,7 +22,7 @@ export interface ListOverflowItem {
22} 22}
23 23
24@Component({ 24@Component({
25 selector: 'list-overflow', 25 selector: 'my-list-overflow',
26 templateUrl: './list-overflow.component.html', 26 templateUrl: './list-overflow.component.html',
27 styleUrls: [ './list-overflow.component.scss' ], 27 styleUrls: [ './list-overflow.component.scss' ],
28 changeDetection: ChangeDetectionStrategy.OnPush 28 changeDetection: ChangeDetectionStrategy.OnPush
@@ -65,7 +65,7 @@ export class ListOverflowComponent<T extends ListOverflowItem> implements AfterV
65 let showItemsUntilIndexExcluded: number 65 let showItemsUntilIndexExcluded: number
66 let accWidth = 0 66 let accWidth = 0
67 67
68 for (const [index, el] of this.itemsRendered.toArray().entries()) { 68 for (const [ index, el ] of this.itemsRendered.toArray().entries()) {
69 accWidth += el.nativeElement.getBoundingClientRect().width 69 accWidth += el.nativeElement.getBoundingClientRect().width
70 if (showItemsUntilIndexExcluded === undefined) { 70 if (showItemsUntilIndexExcluded === undefined) {
71 showItemsUntilIndexExcluded = (parentWidth < accWidth) ? index : undefined 71 showItemsUntilIndexExcluded = (parentWidth < accWidth) ? index : undefined
diff --git a/client/src/app/shared/shared-main/misc/simple-search-input.component.ts b/client/src/app/shared/shared-main/misc/simple-search-input.component.ts
index 224d71134..292ec4c82 100644
--- a/client/src/app/shared/shared-main/misc/simple-search-input.component.ts
+++ b/client/src/app/shared/shared-main/misc/simple-search-input.component.ts
@@ -4,7 +4,7 @@ import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild }
4import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
5 5
6@Component({ 6@Component({
7 selector: 'simple-search-input', 7 selector: 'my-simple-search-input',
8 templateUrl: './simple-search-input.component.html', 8 templateUrl: './simple-search-input.component.html',
9 styleUrls: [ './simple-search-input.component.scss' ] 9 styleUrls: [ './simple-search-input.component.scss' ]
10}) 10})
diff --git a/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.ts b/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.ts
index 2cafb6c55..e7e34ce1e 100644
--- a/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.ts
+++ b/client/src/app/shared/shared-main/misc/top-menu-dropdown.component.ts
@@ -66,7 +66,7 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
66 .subscribe(() => this.updateChildLabels(window.location.pathname)) 66 .subscribe(() => this.updateChildLabels(window.location.pathname))
67 67
68 this.hasIcons = this.menuEntries.some( 68 this.hasIcons = this.menuEntries.some(
69 e => e.children && e.children.some(c => !!c.iconName) 69 e => e.children?.some(c => !!c.iconName)
70 ) 70 )
71 } 71 }
72 72
diff --git a/client/src/app/shared/shared-main/users/user-notification.service.ts b/client/src/app/shared/shared-main/users/user-notification.service.ts
index 9014b48a8..09fee87a3 100644
--- a/client/src/app/shared/shared-main/users/user-notification.service.ts
+++ b/client/src/app/shared/shared-main/users/user-notification.service.ts
@@ -1,11 +1,11 @@
1import { SortMeta } from 'primeng/api'
1import { catchError, map, tap } from 'rxjs/operators' 2import { catchError, map, tap } from 'rxjs/operators'
2import { HttpClient, HttpParams } from '@angular/common/http' 3import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 4import { Injectable } from '@angular/core'
4import { ComponentPaginationLight, RestExtractor, RestService, User, PeerTubeSocket, AuthService } from '@app/core' 5import { AuthService, ComponentPaginationLight, PeerTubeSocket, RestExtractor, RestService } from '@app/core'
5import { ResultList, UserNotification as UserNotificationServer, UserNotificationSetting } from '@shared/models' 6import { ResultList, UserNotification as UserNotificationServer, UserNotificationSetting } from '@shared/models'
6import { environment } from '../../../../environments/environment' 7import { environment } from '../../../../environments/environment'
7import { UserNotification } from './user-notification.model' 8import { UserNotification } from './user-notification.model'
8import { SortMeta } from 'primeng/api'
9 9
10@Injectable() 10@Injectable()
11export class UserNotificationService { 11export class UserNotificationService {
@@ -23,7 +23,7 @@ export class UserNotificationService {
23 listMyNotifications (parameters: { 23 listMyNotifications (parameters: {
24 pagination: ComponentPaginationLight 24 pagination: ComponentPaginationLight
25 ignoreLoadingBar?: boolean 25 ignoreLoadingBar?: boolean
26 unread?: boolean, 26 unread?: boolean
27 sort?: SortMeta 27 sort?: SortMeta
28 }) { 28 }) {
29 const { pagination, ignoreLoadingBar, unread, sort } = parameters 29 const { pagination, ignoreLoadingBar, unread, sort } = parameters
diff --git a/client/src/app/shared/shared-main/users/user-quota.component.ts b/client/src/app/shared/shared-main/users/user-quota.component.ts
index b38619186..5a95f1209 100644
--- a/client/src/app/shared/shared-main/users/user-quota.component.ts
+++ b/client/src/app/shared/shared-main/users/user-quota.component.ts
@@ -6,7 +6,7 @@ import { BytesPipe } from '../angular'
6@Component({ 6@Component({
7 selector: 'my-user-quota', 7 selector: 'my-user-quota',
8 templateUrl: './user-quota.component.html', 8 templateUrl: './user-quota.component.html',
9 styleUrls: ['./user-quota.component.scss'] 9 styleUrls: [ './user-quota.component.scss' ]
10}) 10})
11 11
12export class UserQuotaComponent implements OnInit { 12export class UserQuotaComponent implements OnInit {
diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts
index a9dcf2fa2..66d4cac68 100644
--- a/client/src/app/shared/shared-main/video-channel/video-channel.model.ts
+++ b/client/src/app/shared/shared-main/video-channel/video-channel.model.ts
@@ -1,6 +1,5 @@
1import { getAbsoluteAPIUrl } from '@app/helpers' 1import { getAbsoluteAPIUrl } from '@app/helpers'
2import { Account as ServerAccount, ActorImage, VideoChannel as ServerVideoChannel, ViewsPerDate } from '@shared/models' 2import { Account as ServerAccount, ActorImage, VideoChannel as ServerVideoChannel, ViewsPerDate } from '@shared/models'
3import { Account } from '../account/account.model'
4import { Actor } from '../account/actor.model' 3import { Actor } from '../account/actor.model'
5 4
6export class VideoChannel extends Actor implements ServerVideoChannel { 5export class VideoChannel extends Actor implements ServerVideoChannel {
@@ -25,14 +24,14 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
25 24
26 viewsPerDay?: ViewsPerDate[] 25 viewsPerDay?: ViewsPerDate[]
27 26
28 static GET_ACTOR_AVATAR_URL (actor: object) { 27 static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) {
29 return Actor.GET_ACTOR_AVATAR_URL(actor) 28 return Actor.GET_ACTOR_AVATAR_URL(actor)
30 } 29 }
31 30
32 static GET_ACTOR_BANNER_URL (channel: ServerVideoChannel) { 31 static GET_ACTOR_BANNER_URL (channel: ServerVideoChannel) {
33 if (channel?.banner?.url) return channel.banner.url 32 if (channel?.banner?.url) return channel.banner.url
34 33
35 if (channel && channel.banner) { 34 if (channel?.banner) {
36 const absoluteAPIUrl = getAbsoluteAPIUrl() 35 const absoluteAPIUrl = getAbsoluteAPIUrl()
37 36
38 return absoluteAPIUrl + channel.banner.path 37 return absoluteAPIUrl + channel.banner.path
diff --git a/client/src/app/shared/shared-main/video-channel/video-channel.service.ts b/client/src/app/shared/shared-main/video-channel/video-channel.service.ts
index a89f1065a..7560a35a8 100644
--- a/client/src/app/shared/shared-main/video-channel/video-channel.service.ts
+++ b/client/src/app/shared/shared-main/video-channel/video-channel.service.ts
@@ -15,6 +15,12 @@ export class VideoChannelService {
15 15
16 videoChannelLoaded = new ReplaySubject<VideoChannel>(1) 16 videoChannelLoaded = new ReplaySubject<VideoChannel>(1)
17 17
18 constructor (
19 private authHttp: HttpClient,
20 private restService: RestService,
21 private restExtractor: RestExtractor
22 ) { }
23
18 static extractVideoChannels (result: ResultList<VideoChannelServer>) { 24 static extractVideoChannels (result: ResultList<VideoChannelServer>) {
19 const videoChannels: VideoChannel[] = [] 25 const videoChannels: VideoChannel[] = []
20 26
@@ -25,12 +31,6 @@ export class VideoChannelService {
25 return { data: videoChannels, total: result.total } 31 return { data: videoChannels, total: result.total }
26 } 32 }
27 33
28 constructor (
29 private authHttp: HttpClient,
30 private restService: RestService,
31 private restExtractor: RestExtractor
32 ) { }
33
34 getVideoChannel (videoChannelName: string) { 34 getVideoChannel (videoChannelName: string) {
35 return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelName) 35 return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelName)
36 .pipe( 36 .pipe(
diff --git a/client/src/app/shared/shared-main/video/redundancy.service.ts b/client/src/app/shared/shared-main/video/redundancy.service.ts
index 6e839e655..966d7fafd 100644
--- a/client/src/app/shared/shared-main/video/redundancy.service.ts
+++ b/client/src/app/shared/shared-main/video/redundancy.service.ts
@@ -30,8 +30,8 @@ export class RedundancyService {
30 } 30 }
31 31
32 listVideoRedundancies (options: { 32 listVideoRedundancies (options: {
33 pagination: RestPagination, 33 pagination: RestPagination
34 sort: SortMeta, 34 sort: SortMeta
35 target?: VideoRedundanciesTarget 35 target?: VideoRedundanciesTarget
36 }): Observable<ResultList<VideoRedundancy>> { 36 }): Observable<ResultList<VideoRedundancy>> {
37 const { pagination, sort, target } = options 37 const { pagination, sort, target } = options
diff --git a/client/src/app/shared/shared-main/video/video-edit.model.ts b/client/src/app/shared/shared-main/video/video-edit.model.ts
index 757b686c0..ea0456942 100644
--- a/client/src/app/shared/shared-main/video/video-edit.model.ts
+++ b/client/src/app/shared/shared-main/video/video-edit.model.ts
@@ -29,11 +29,11 @@ export class VideoEdit implements VideoUpdate {
29 29
30 constructor ( 30 constructor (
31 video?: Video & { 31 video?: Video & {
32 tags: string[], 32 tags: string[]
33 commentsEnabled: boolean, 33 commentsEnabled: boolean
34 downloadEnabled: boolean, 34 downloadEnabled: boolean
35 support: string, 35 support: string
36 thumbnailUrl: string, 36 thumbnailUrl: string
37 previewUrl: string 37 previewUrl: string
38 }) { 38 }) {
39 if (video) { 39 if (video) {
@@ -64,7 +64,7 @@ export class VideoEdit implements VideoUpdate {
64 64
65 patch (values: { [ id: string ]: any }) { 65 patch (values: { [ id: string ]: any }) {
66 Object.keys(values).forEach((key) => { 66 Object.keys(values).forEach((key) => {
67 this[ key ] = values[ key ] 67 this[key] = values[key]
68 }) 68 })
69 69
70 // If schedule publication, the video is private and will be changed to public privacy 70 // If schedule publication, the video is private and will be changed to public privacy
diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts
index b7720c8d2..7471a933b 100644
--- a/client/src/app/shared/shared-main/video/video.model.ts
+++ b/client/src/app/shared/shared-main/video/video.model.ts
@@ -100,7 +100,7 @@ export class Video implements VideoServerModel {
100 return '/videos/update/' + video.uuid 100 return '/videos/update/' + video.uuid
101 } 101 }
102 102
103 constructor (hash: VideoServerModel, translations = {}) { 103 constructor (hash: VideoServerModel, translations: { [ id: string ]: string } = {}) {
104 const absoluteAPIUrl = getAbsoluteAPIUrl() 104 const absoluteAPIUrl = getAbsoluteAPIUrl()
105 105
106 this.createdAt = new Date(hash.createdAt.toString()) 106 this.createdAt = new Date(hash.createdAt.toString())
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts
index 4a97719fa..60cc9d160 100644
--- a/client/src/app/shared/shared-main/video/video.service.ts
+++ b/client/src/app/shared/shared-main/video/video.service.ts
@@ -30,10 +30,10 @@ import { Video } from './video.model'
30 30
31export interface VideosProvider { 31export interface VideosProvider {
32 getVideos (parameters: { 32 getVideos (parameters: {
33 videoPagination: ComponentPaginationLight, 33 videoPagination: ComponentPaginationLight
34 sort: VideoSortField, 34 sort: VideoSortField
35 filter?: VideoFilter, 35 filter?: VideoFilter
36 categoryOneOf?: number[], 36 categoryOneOf?: number[]
37 languageOneOf?: string[] 37 languageOneOf?: string[]
38 nsfwPolicy: NSFWPolicyType 38 nsfwPolicy: NSFWPolicyType
39 }): Observable<ResultList<Video>> 39 }): Observable<ResultList<Video>>
@@ -145,8 +145,8 @@ export class VideoService implements VideosProvider {
145 } 145 }
146 146
147 getAccountVideos (parameters: { 147 getAccountVideos (parameters: {
148 account: Pick<Account, 'nameWithHost'>, 148 account: Pick<Account, 'nameWithHost'>
149 videoPagination: ComponentPaginationLight, 149 videoPagination: ComponentPaginationLight
150 sort: VideoSortField 150 sort: VideoSortField
151 nsfwPolicy?: NSFWPolicyType 151 nsfwPolicy?: NSFWPolicyType
152 videoFilter?: VideoFilter 152 videoFilter?: VideoFilter
@@ -180,9 +180,9 @@ export class VideoService implements VideosProvider {
180 } 180 }
181 181
182 getVideoChannelVideos (parameters: { 182 getVideoChannelVideos (parameters: {
183 videoChannel: Pick<VideoChannel, 'nameWithHost'>, 183 videoChannel: Pick<VideoChannel, 'nameWithHost'>
184 videoPagination: ComponentPaginationLight, 184 videoPagination: ComponentPaginationLight
185 sort: VideoSortField, 185 sort: VideoSortField
186 nsfwPolicy?: NSFWPolicyType 186 nsfwPolicy?: NSFWPolicyType
187 videoFilter?: VideoFilter 187 videoFilter?: VideoFilter
188 }): Observable<ResultList<Video>> { 188 }): Observable<ResultList<Video>> {
diff --git a/client/src/app/shared/shared-moderation/abuse.service.ts b/client/src/app/shared/shared-moderation/abuse.service.ts
index bf98d4b36..f45b5c8e8 100644
--- a/client/src/app/shared/shared-moderation/abuse.service.ts
+++ b/client/src/app/shared/shared-moderation/abuse.service.ts
@@ -30,8 +30,8 @@ export class AbuseService {
30 ) { } 30 ) { }
31 31
32 getAdminAbuses (options: { 32 getAdminAbuses (options: {
33 pagination: RestPagination, 33 pagination: RestPagination
34 sort: SortMeta, 34 sort: SortMeta
35 search?: string 35 search?: string
36 }): Observable<ResultList<AdminAbuse>> { 36 }): Observable<ResultList<AdminAbuse>> {
37 const { pagination, sort, search } = options 37 const { pagination, sort, search } = options
@@ -51,8 +51,8 @@ export class AbuseService {
51 } 51 }
52 52
53 getUserAbuses (options: { 53 getUserAbuses (options: {
54 pagination: RestPagination, 54 pagination: RestPagination
55 sort: SortMeta, 55 sort: SortMeta
56 search?: string 56 search?: string
57 }): Observable<ResultList<UserAbuse>> { 57 }): Observable<ResultList<UserAbuse>> {
58 const { pagination, sort, search } = options 58 const { pagination, sort, search } = options
@@ -74,7 +74,7 @@ export class AbuseService {
74 reportVideo (parameters: AbuseCreate) { 74 reportVideo (parameters: AbuseCreate) {
75 const url = AbuseService.BASE_ABUSE_URL 75 const url = AbuseService.BASE_ABUSE_URL
76 76
77 const body = omit(parameters, ['id']) 77 const body = omit(parameters, [ 'id' ])
78 78
79 return this.authHttp.post(url, body) 79 return this.authHttp.post(url, body)
80 .pipe( 80 .pipe(
@@ -147,11 +147,13 @@ export class AbuseService {
147 { 147 {
148 id: 'spamOrMisleading', 148 id: 'spamOrMisleading',
149 label: $localize`Spam, ad or false news`, 149 label: $localize`Spam, ad or false news`,
150 // eslint-disable-next-line max-len
150 help: $localize`Contains marketing, spam, purposefully deceitful news, or otherwise misleading thumbnail/text/tags. Please provide reputable sources to report hoaxes.` 151 help: $localize`Contains marketing, spam, purposefully deceitful news, or otherwise misleading thumbnail/text/tags. Please provide reputable sources to report hoaxes.`
151 }, 152 },
152 { 153 {
153 id: 'privacy', 154 id: 'privacy',
154 label: $localize`Privacy breach or doxxing`, 155 label: $localize`Privacy breach or doxxing`,
156 // eslint-disable-next-line max-len
155 help: $localize`Contains personal information that could be used to track, identify, contact or impersonate someone (e.g. name, address, phone number, email, or credit card details).` 157 help: $localize`Contains personal information that could be used to track, identify, contact or impersonate someone (e.g. name, address, phone number, email, or credit card details).`
156 }, 158 },
157 { 159 {
@@ -162,6 +164,7 @@ export class AbuseService {
162 { 164 {
163 id: 'serverRules', 165 id: 'serverRules',
164 label: $localize`Breaks server rules`, 166 label: $localize`Breaks server rules`,
167 // eslint-disable-next-line max-len
165 description: $localize`Anything not included in the above that breaks the terms of service, code of conduct, or general rules in place on the server.` 168 description: $localize`Anything not included in the above that breaks the terms of service, code of conduct, or general rules in place on the server.`
166 } 169 }
167 ] 170 ]
diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.ts b/client/src/app/shared/shared-moderation/account-blocklist.component.ts
index 36f2a591b..9ed00bc12 100644
--- a/client/src/app/shared/shared-moderation/account-blocklist.component.ts
+++ b/client/src/app/shared/shared-moderation/account-blocklist.component.ts
@@ -1,14 +1,13 @@
1import { SortMeta } from 'primeng/api' 1import { SortMeta } from 'primeng/api'
2import { Directive, OnInit } from '@angular/core' 2import { Directive, OnInit } from '@angular/core'
3import { Notifier, RestPagination, RestTable } from '@app/core' 3import { Notifier, RestPagination, RestTable } from '@app/core'
4import { Account } from '@app/shared/shared-main'
5import { AccountBlock } from './account-block.model' 4import { AccountBlock } from './account-block.model'
6import { BlocklistComponentType, BlocklistService } from './blocklist.service' 5import { BlocklistComponentType, BlocklistService } from './blocklist.service'
7 6
8@Directive() 7@Directive()
9// tslint:disable-next-line: directive-class-suffix 8// eslint-disable-next-line @angular-eslint/directive-class-suffix
10export class GenericAccountBlocklistComponent extends RestTable implements OnInit { 9export class GenericAccountBlocklistComponent extends RestTable implements OnInit {
11 // @ts-ignore: "Abstract methods can only appear within an abstract class" 10 // @ts-expect-error: "Abstract methods can only appear within an abstract class"
12 abstract mode: BlocklistComponentType 11 abstract mode: BlocklistComponentType
13 12
14 blockedAccounts: AccountBlock[] = [] 13 blockedAccounts: AccountBlock[] = []
@@ -23,7 +22,7 @@ export class GenericAccountBlocklistComponent extends RestTable implements OnIni
23 super() 22 super()
24 } 23 }
25 24
26 // @ts-ignore: "Abstract methods can only appear within an abstract class" 25 // @ts-expect-error: "Abstract methods can only appear within an abstract class"
27 abstract getIdentifier (): string 26 abstract getIdentifier (): string
28 27
29 ngOnInit () { 28 ngOnInit () {
diff --git a/client/src/app/shared/shared-moderation/blocklist.service.ts b/client/src/app/shared/shared-moderation/blocklist.service.ts
index de677a77b..db2a8c584 100644
--- a/client/src/app/shared/shared-moderation/blocklist.service.ts
+++ b/client/src/app/shared/shared-moderation/blocklist.service.ts
@@ -21,7 +21,7 @@ export class BlocklistService {
21 private restService: RestService 21 private restService: RestService
22 ) { } 22 ) { }
23 23
24 /*********************** User -> Account blocklist ***********************/ 24 /** ********************* User -> Account blocklist ***********************/
25 25
26 getUserAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { 26 getUserAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
27 const { pagination, sort, search } = options 27 const { pagination, sort, search } = options
@@ -53,7 +53,7 @@ export class BlocklistService {
53 .pipe(catchError(err => this.restExtractor.handleError(err))) 53 .pipe(catchError(err => this.restExtractor.handleError(err)))
54 } 54 }
55 55
56 /*********************** User -> Server blocklist ***********************/ 56 /** ********************* User -> Server blocklist ***********************/
57 57
58 getUserServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { 58 getUserServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
59 const { pagination, sort, search } = options 59 const { pagination, sort, search } = options
@@ -84,7 +84,7 @@ export class BlocklistService {
84 .pipe(catchError(err => this.restExtractor.handleError(err))) 84 .pipe(catchError(err => this.restExtractor.handleError(err)))
85 } 85 }
86 86
87 /*********************** Instance -> Account blocklist ***********************/ 87 /** ********************* Instance -> Account blocklist ***********************/
88 88
89 getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { 89 getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
90 const { pagination, sort, search } = options 90 const { pagination, sort, search } = options
@@ -116,7 +116,7 @@ export class BlocklistService {
116 .pipe(catchError(err => this.restExtractor.handleError(err))) 116 .pipe(catchError(err => this.restExtractor.handleError(err)))
117 } 117 }
118 118
119 /*********************** Instance -> Server blocklist ***********************/ 119 /** ********************* Instance -> Server blocklist ***********************/
120 120
121 getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { 121 getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
122 const { pagination, sort, search } = options 122 const { pagination, sort, search } = options
diff --git a/client/src/app/shared/shared-moderation/server-blocklist.component.ts b/client/src/app/shared/shared-moderation/server-blocklist.component.ts
index da09b1d0e..1ba7a1b4d 100644
--- a/client/src/app/shared/shared-moderation/server-blocklist.component.ts
+++ b/client/src/app/shared/shared-moderation/server-blocklist.component.ts
@@ -6,11 +6,11 @@ import { ServerBlock } from '@shared/models'
6import { BlocklistComponentType, BlocklistService } from './blocklist.service' 6import { BlocklistComponentType, BlocklistService } from './blocklist.service'
7 7
8@Directive() 8@Directive()
9// tslint:disable-next-line: directive-class-suffix 9// eslint-disable-next-line @angular-eslint/directive-class-suffix
10export class GenericServerBlocklistComponent extends RestTable implements OnInit { 10export class GenericServerBlocklistComponent extends RestTable implements OnInit {
11 @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent 11 @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent
12 12
13 // @ts-ignore: "Abstract methods can only appear within an abstract class" 13 // @ts-expect-error: "Abstract methods can only appear within an abstract class"
14 public abstract mode: BlocklistComponentType 14 public abstract mode: BlocklistComponentType
15 15
16 blockedServers: ServerBlock[] = [] 16 blockedServers: ServerBlock[] = []
@@ -25,7 +25,7 @@ export class GenericServerBlocklistComponent extends RestTable implements OnInit
25 super() 25 super()
26 } 26 }
27 27
28 // @ts-ignore: "Abstract methods can only appear within an abstract class" 28 // @ts-expect-error: "Abstract methods can only appear within an abstract class"
29 public abstract getIdentifier (): string 29 public abstract getIdentifier (): string
30 30
31 ngOnInit () { 31 ngOnInit () {
@@ -34,8 +34,8 @@ export class GenericServerBlocklistComponent extends RestTable implements OnInit
34 34
35 unblockServer (serverBlock: ServerBlock) { 35 unblockServer (serverBlock: ServerBlock) {
36 const operation = (host: string) => this.mode === BlocklistComponentType.Account 36 const operation = (host: string) => this.mode === BlocklistComponentType.Account
37 ? this.blocklistService.unblockServerByUser(host) 37 ? this.blocklistService.unblockServerByUser(host)
38 : this.blocklistService.unblockServerByInstance(host) 38 : this.blocklistService.unblockServerByInstance(host)
39 const host = serverBlock.blockedServer.host 39 const host = serverBlock.blockedServer.host
40 40
41 operation(host).subscribe( 41 operation(host).subscribe(
diff --git a/client/src/app/shared/shared-moderation/video-block.component.ts b/client/src/app/shared/shared-moderation/video-block.component.ts
index bc6952620..f6c29dcfa 100644
--- a/client/src/app/shared/shared-moderation/video-block.component.ts
+++ b/client/src/app/shared/shared-moderation/video-block.component.ts
@@ -51,8 +51,8 @@ export class VideoBlockComponent extends FormReactive implements OnInit {
51 } 51 }
52 52
53 block () { 53 block () {
54 const reason = this.form.value[ 'reason' ] || undefined 54 const reason = this.form.value['reason'] || undefined
55 const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined 55 const unfederate = this.video.isLocal ? this.form.value['unfederate'] : undefined
56 56
57 this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate) 57 this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate)
58 .subscribe({ 58 .subscribe({
diff --git a/client/src/app/shared/shared-support-modal/support-modal.component.ts b/client/src/app/shared/shared-support-modal/support-modal.component.ts
index a0b9fada6..08e997f7b 100644
--- a/client/src/app/shared/shared-support-modal/support-modal.component.ts
+++ b/client/src/app/shared/shared-support-modal/support-modal.component.ts
@@ -28,7 +28,9 @@ export class SupportModalComponent {
28 const support = this.video?.support || this.videoChannel.support 28 const support = this.video?.support || this.videoChannel.support
29 29
30 this.markdownService.enhancedMarkdownToHTML(support) 30 this.markdownService.enhancedMarkdownToHTML(support)
31 .then(r => this.htmlSupport = r) 31 .then(r => {
32 this.htmlSupport = r
33 })
32 34
33 this.displayName = this.video 35 this.displayName = this.video
34 ? this.video.channel.displayName 36 ? this.video.channel.displayName
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
index 4aac60c2b..5d6e11c04 100644
--- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
+++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
@@ -80,7 +80,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
80 } 80 }
81 81
82 updateDetails (onlyKeys?: string[]) { 82 updateDetails (onlyKeys?: string[]) {
83 const nsfwPolicy = this.form.value[ 'nsfwPolicy' ] 83 const nsfwPolicy = this.form.value['nsfwPolicy']
84 const webTorrentEnabled = this.form.value['webTorrentEnabled'] 84 const webTorrentEnabled = this.form.value['webTorrentEnabled']
85 const autoPlayVideo = this.form.value['autoPlayVideo'] 85 const autoPlayVideo = this.form.value['autoPlayVideo']
86 const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] 86 const autoPlayNextVideo = this.form.value['autoPlayNextVideo']
diff --git a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
index 666199523..a951134eb 100644
--- a/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
+++ b/client/src/app/shared/shared-user-subscription/remote-subscribe.component.ts
@@ -6,7 +6,7 @@ import { USER_HANDLE_VALIDATOR } from '../form-validators/user-validators'
6@Component({ 6@Component({
7 selector: 'my-remote-subscribe', 7 selector: 'my-remote-subscribe',
8 templateUrl: './remote-subscribe.component.html', 8 templateUrl: './remote-subscribe.component.html',
9 styleUrls: ['./remote-subscribe.component.scss'] 9 styleUrls: [ './remote-subscribe.component.scss' ]
10}) 10})
11export class RemoteSubscribeComponent extends FormReactive implements OnInit { 11export class RemoteSubscribeComponent extends FormReactive implements OnInit {
12 @Input() uri: string 12 @Input() uri: string
@@ -42,17 +42,21 @@ export class RemoteSubscribeComponent extends FormReactive implements OnInit {
42 // Should not have CORS error because https://tools.ietf.org/html/rfc7033#section-5 42 // Should not have CORS error because https://tools.ietf.org/html/rfc7033#section-5
43 fetch(`${protocol}//${hostname}/.well-known/webfinger?resource=acct:${username}@${hostname}`) 43 fetch(`${protocol}//${hostname}/.well-known/webfinger?resource=acct:${username}@${hostname}`)
44 .then(response => response.json()) 44 .then(response => response.json())
45 .then(data => new Promise((res, rej) => { 45 .then(data => {
46 if (!data || Array.isArray(data.links) === false) return rej() 46 if (!data || Array.isArray(data.links) === false) {
47 throw new Error('Not links in webfinger response')
48 }
47 49
48 const link: { template: string } = data.links.find((link: any) => { 50 const link: { template: string } = data.links.find((link: any) => {
49 return link && typeof link.template === 'string' && link.rel === 'http://ostatus.org/schema/1.0/subscribe' 51 return link && typeof link.template === 'string' && link.rel === 'http://ostatus.org/schema/1.0/subscribe'
50 }) 52 })
51 53
52 if (link && link.template.includes('{uri}')) { 54 if (link?.template.includes('{uri}')) {
53 res(link.template.replace('{uri}', encodeURIComponent(this.uri))) 55 return link.template.replace('{uri}', encodeURIComponent(this.uri))
54 } 56 }
55 })) 57
58 throw new Error('No subscribe template in webfinger response')
59 })
56 .then(window.open) 60 .then(window.open)
57 .catch(err => { 61 .catch(err => {
58 console.error(err) 62 console.error(err)
diff --git a/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts b/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
index 796493bd9..180bc0565 100644
--- a/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
+++ b/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
@@ -137,7 +137,7 @@ export class SubscribeButtonComponent implements OnInit, OnChanges {
137 this.notifier.success( 137 this.notifier.success(
138 this.account 138 this.account
139 ? $localize`Unsubscribed from all channels of ${this.account.nameWithHost}` 139 ? $localize`Unsubscribed from all channels of ${this.account.nameWithHost}`
140 : $localize`Unsubscribed from ${this.videoChannels[ 0 ].nameWithHost}`, 140 : $localize`Unsubscribed from ${this.videoChannels[0].nameWithHost}`,
141 141
142 $localize`Unsubscribed` 142 $localize`Unsubscribed`
143 ) 143 )
@@ -157,7 +157,7 @@ export class SubscribeButtonComponent implements OnInit, OnChanges {
157 157
158 subscribeStatus (subscribed: boolean) { 158 subscribeStatus (subscribed: boolean) {
159 const accumulator: string[] = [] 159 const accumulator: string[] = []
160 for (const [key, value] of this.subscribed.entries()) { 160 for (const [ key, value ] of this.subscribed.entries()) {
161 if (value === subscribed) accumulator.push(key) 161 if (value === subscribed) accumulator.push(key)
162 } 162 }
163 163
diff --git a/client/src/app/shared/shared-user-subscription/user-subscription.service.ts b/client/src/app/shared/shared-user-subscription/user-subscription.service.ts
index bb44660d2..e4fc09b36 100644
--- a/client/src/app/shared/shared-user-subscription/user-subscription.service.ts
+++ b/client/src/app/shared/shared-user-subscription/user-subscription.service.ts
@@ -46,8 +46,8 @@ export class UserSubscriptionService {
46 } 46 }
47 47
48 getUserSubscriptionVideos (parameters: { 48 getUserSubscriptionVideos (parameters: {
49 videoPagination: ComponentPaginationLight, 49 videoPagination: ComponentPaginationLight
50 sort: VideoSortField, 50 sort: VideoSortField
51 skipCount?: boolean 51 skipCount?: boolean
52 }): Observable<ResultList<Video>> { 52 }): Observable<ResultList<Video>> {
53 const { videoPagination, sort, skipCount } = parameters 53 const { videoPagination, sort, skipCount } = parameters
@@ -131,16 +131,16 @@ export class UserSubscriptionService {
131 131
132 listenToSubscriptionCacheChange (nameWithHost: string) { 132 listenToSubscriptionCacheChange (nameWithHost: string) {
133 if (nameWithHost in this.myAccountSubscriptionCacheObservable) { 133 if (nameWithHost in this.myAccountSubscriptionCacheObservable) {
134 return this.myAccountSubscriptionCacheObservable[ nameWithHost ] 134 return this.myAccountSubscriptionCacheObservable[nameWithHost]
135 } 135 }
136 136
137 const obs = this.existsObservable 137 const obs = this.existsObservable
138 .pipe( 138 .pipe(
139 filter(existsResult => existsResult[ nameWithHost ] !== undefined), 139 filter(existsResult => existsResult[nameWithHost] !== undefined),
140 map(existsResult => existsResult[ nameWithHost ]) 140 map(existsResult => existsResult[nameWithHost])
141 ) 141 )
142 142
143 this.myAccountSubscriptionCacheObservable[ nameWithHost ] = obs 143 this.myAccountSubscriptionCacheObservable[nameWithHost] = obs
144 return obs 144 return obs
145 } 145 }
146 146
@@ -150,16 +150,16 @@ export class UserSubscriptionService {
150 if (nameWithHost in this.myAccountSubscriptionCache) { 150 if (nameWithHost in this.myAccountSubscriptionCache) {
151 logger('Found cache for %d.', nameWithHost) 151 logger('Found cache for %d.', nameWithHost)
152 152
153 return of(this.myAccountSubscriptionCache[ nameWithHost ]) 153 return of(this.myAccountSubscriptionCache[nameWithHost])
154 } 154 }
155 155
156 this.existsSubject.next(nameWithHost) 156 this.existsSubject.next(nameWithHost)
157 157
158 logger('Fetching from network for %d.', nameWithHost) 158 logger('Fetching from network for %d.', nameWithHost)
159 return this.existsObservable.pipe( 159 return this.existsObservable.pipe(
160 filter(existsResult => existsResult[ nameWithHost ] !== undefined), 160 filter(existsResult => existsResult[nameWithHost] !== undefined),
161 map(existsResult => existsResult[ nameWithHost ]), 161 map(existsResult => existsResult[nameWithHost]),
162 tap(result => this.myAccountSubscriptionCache[ nameWithHost ] = result) 162 tap(result => this.myAccountSubscriptionCache[nameWithHost] = result)
163 ) 163 )
164 } 164 }
165 165
diff --git a/client/src/app/shared/shared-video-comment/video-comment.model.ts b/client/src/app/shared/shared-video-comment/video-comment.model.ts
index ba0f57e8f..adab4cfbd 100644
--- a/client/src/app/shared/shared-video-comment/video-comment.model.ts
+++ b/client/src/app/shared/shared-video-comment/video-comment.model.ts
@@ -1,6 +1,10 @@
1import { getAbsoluteAPIUrl } from '@app/helpers' 1import { getAbsoluteAPIUrl } from '@app/helpers'
2import { Account, Actor, Video } from '@app/shared/shared-main' 2import { Actor, Video } from '@app/shared/shared-main'
3import { Account as AccountInterface, VideoComment as VideoCommentServerModel, VideoCommentAdmin as VideoCommentAdminServerModel } from '@shared/models' 3import {
4 Account as AccountInterface,
5 VideoComment as VideoCommentServerModel,
6 VideoCommentAdmin as VideoCommentAdminServerModel
7} from '@shared/models'
4 8
5export class VideoComment implements VideoCommentServerModel { 9export class VideoComment implements VideoCommentServerModel {
6 id: number 10 id: number
diff --git a/client/src/app/shared/shared-video-comment/video-comment.service.ts b/client/src/app/shared/shared-video-comment/video-comment.service.ts
index 4f1452116..5550c96e4 100644
--- a/client/src/app/shared/shared-video-comment/video-comment.service.ts
+++ b/client/src/app/shared/shared-video-comment/video-comment.service.ts
@@ -37,8 +37,8 @@ export class VideoCommentService {
37 37
38 return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) 38 return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment)
39 .pipe( 39 .pipe(
40 map(data => this.extractVideoComment(data.comment)), 40 map(data => this.extractVideoComment(data.comment)),
41 catchError(err => this.restExtractor.handleError(err)) 41 catchError(err => this.restExtractor.handleError(err))
42 ) 42 )
43 } 43 }
44 44
@@ -54,8 +54,8 @@ export class VideoCommentService {
54 } 54 }
55 55
56 getAdminVideoComments (options: { 56 getAdminVideoComments (options: {
57 pagination: RestPagination, 57 pagination: RestPagination
58 sort: SortMeta, 58 sort: SortMeta
59 search?: string 59 search?: string
60 }): Observable<ResultList<VideoCommentAdmin>> { 60 }): Observable<ResultList<VideoCommentAdmin>> {
61 const { pagination, sort, search } = options 61 const { pagination, sort, search } = options
@@ -75,8 +75,8 @@ export class VideoCommentService {
75 } 75 }
76 76
77 getVideoCommentThreads (parameters: { 77 getVideoCommentThreads (parameters: {
78 videoId: number | string, 78 videoId: number | string
79 componentPagination: ComponentPaginationLight, 79 componentPagination: ComponentPaginationLight
80 sort: string 80 sort: string
81 }): Observable<ThreadsResultList<VideoComment>> { 81 }): Observable<ThreadsResultList<VideoComment>> {
82 const { videoId, componentPagination, sort } = parameters 82 const { videoId, componentPagination, sort } = parameters
@@ -95,7 +95,7 @@ export class VideoCommentService {
95 } 95 }
96 96
97 getVideoThreadComments (parameters: { 97 getVideoThreadComments (parameters: {
98 videoId: number | string, 98 videoId: number | string
99 threadId: number 99 threadId: number
100 }): Observable<VideoCommentThreadTree> { 100 }): Observable<VideoCommentThreadTree> {
101 const { videoId, threadId } = parameters 101 const { videoId, threadId } = parameters
diff --git a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
index d8b2ee17d..f12ae2ee5 100644
--- a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
+++ b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
@@ -42,7 +42,7 @@ enum GroupDate {
42} 42}
43 43
44@Directive() 44@Directive()
45// tslint:disable-next-line: directive-class-suffix 45// eslint-disable-next-line @angular-eslint/directive-class-suffix
46export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterContentInit, DisableForReuseHook { 46export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterContentInit, DisableForReuseHook {
47 @ViewChild('videoListHeader', { static: true, read: ViewContainerRef }) videoListHeader: ViewContainerRef 47 @ViewChild('videoListHeader', { static: true, read: ViewContainerRef }) videoListHeader: ViewContainerRef
48 48
@@ -174,7 +174,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
174 ngAfterContentInit () { 174 ngAfterContentInit () {
175 if (this.videoListHeader) { 175 if (this.videoListHeader) {
176 // some components don't use the header: they use their own template, like my-history.component.html 176 // some components don't use the header: they use their own template, like my-history.component.html
177 this.setHeader.apply(this, [ this.HeaderComponent, this.headerComponentInjector ]) 177 this.setHeader(this.HeaderComponent, this.headerComponentInjector)
178 } 178 }
179 } 179 }
180 180
@@ -278,7 +278,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
278 278
279 if (currentGroupedDate !== period.value) { 279 if (currentGroupedDate !== period.value) {
280 currentGroupedDate = period.value 280 currentGroupedDate = period.value
281 this.groupedDates[ video.id ] = currentGroupedDate 281 this.groupedDates[video.id] = currentGroupedDate
282 } 282 }
283 283
284 break 284 break
@@ -302,13 +302,13 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
302 i: Injector = this.headerComponentInjector 302 i: Injector = this.headerComponentInjector
303 ) { 303 ) {
304 const injector = i || Injector.create({ 304 const injector = i || Injector.create({
305 providers: [{ 305 providers: [ {
306 provide: 'data', 306 provide: 'data',
307 useValue: { 307 useValue: {
308 titlePage: this.titlePage, 308 titlePage: this.titlePage,
309 titleTooltip: this.titleTooltip 309 titleTooltip: this.titleTooltip
310 } 310 }
311 }] 311 } ]
312 }) 312 })
313 const viewContainerRef = this.videoListHeader 313 const viewContainerRef = this.videoListHeader
314 viewContainerRef.clear() 314 viewContainerRef.clear()
@@ -331,9 +331,9 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
331 protected loadPageRouteParams (_queryParams: Params) { /* empty */ } 331 protected loadPageRouteParams (_queryParams: Params) { /* empty */ }
332 332
333 protected loadRouteParams (queryParams: Params) { 333 protected loadRouteParams (queryParams: Params) {
334 this.sort = queryParams[ 'sort' ] as VideoSortField || this.defaultSort 334 this.sort = queryParams['sort'] as VideoSortField || this.defaultSort
335 this.categoryOneOf = queryParams[ 'categoryOneOf' ] 335 this.categoryOneOf = queryParams['categoryOneOf']
336 this.angularState = queryParams[ 'a-state' ] 336 this.angularState = queryParams['a-state']
337 337
338 this.loadPageRouteParams(queryParams) 338 this.loadPageRouteParams(queryParams)
339 } 339 }
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.ts b/client/src/app/shared/shared-video-miniature/video-download.component.ts
index 28fefb9dd..5328f5170 100644
--- a/client/src/app/shared/shared-video-miniature/video-download.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-download.component.ts
@@ -210,10 +210,10 @@ export class VideoDownloadComponent {
210 210
211 private getMetadataFormat (format: any) { 211 private getMetadataFormat (format: any) {
212 const keyToTranslateFunction = { 212 const keyToTranslateFunction = {
213 'encoder': (value: string) => ({ label: $localize`Encoder`, value }), 213 encoder: (value: string) => ({ label: $localize`Encoder`, value }),
214 'format_long_name': (value: string) => ({ label: $localize`Format name`, value }), 214 format_long_name: (value: string) => ({ label: $localize`Format name`, value }),
215 'size': (value: number) => ({ label: $localize`Size`, value: this.bytesPipe.transform(value, 2) }), 215 size: (value: number) => ({ label: $localize`Size`, value: this.bytesPipe.transform(value, 2) }),
216 'bit_rate': (value: number) => ({ 216 bit_rate: (value: number) => ({
217 label: $localize`Bitrate`, 217 label: $localize`Bitrate`,
218 value: `${this.numbersPipe.transform(value)}bps` 218 value: `${this.numbersPipe.transform(value)}bps`
219 }) 219 })
@@ -234,9 +234,9 @@ export class VideoDownloadComponent {
234 if (!stream) return undefined 234 if (!stream) return undefined
235 235
236 let keyToTranslateFunction = { 236 let keyToTranslateFunction = {
237 'codec_long_name': (value: string) => ({ label: $localize`Codec`, value }), 237 codec_long_name: (value: string) => ({ label: $localize`Codec`, value }),
238 'profile': (value: string) => ({ label: $localize`Profile`, value }), 238 profile: (value: string) => ({ label: $localize`Profile`, value }),
239 'bit_rate': (value: number) => ({ 239 bit_rate: (value: number) => ({
240 label: $localize`Bitrate`, 240 label: $localize`Bitrate`,
241 value: `${this.numbersPipe.transform(value)}bps` 241 value: `${this.numbersPipe.transform(value)}bps`
242 }) 242 })
@@ -244,15 +244,15 @@ export class VideoDownloadComponent {
244 244
245 if (type === 'video') { 245 if (type === 'video') {
246 keyToTranslateFunction = Object.assign(keyToTranslateFunction, { 246 keyToTranslateFunction = Object.assign(keyToTranslateFunction, {
247 'width': (value: number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }), 247 width: (value: number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }),
248 'display_aspect_ratio': (value: string) => ({ label: $localize`Aspect ratio`, value }), 248 display_aspect_ratio: (value: string) => ({ label: $localize`Aspect ratio`, value }),
249 'avg_frame_rate': (value: string) => ({ label: $localize`Average frame rate`, value }), 249 avg_frame_rate: (value: string) => ({ label: $localize`Average frame rate`, value }),
250 'pix_fmt': (value: string) => ({ label: $localize`Pixel format`, value }) 250 pix_fmt: (value: string) => ({ label: $localize`Pixel format`, value })
251 }) 251 })
252 } else { 252 } else {
253 keyToTranslateFunction = Object.assign(keyToTranslateFunction, { 253 keyToTranslateFunction = Object.assign(keyToTranslateFunction, {
254 'sample_rate': (value: number) => ({ label: $localize`Sample rate`, value }), 254 sample_rate: (value: number) => ({ label: $localize`Sample rate`, value }),
255 'channel_layout': (value: number) => ({ label: $localize`Channel Layout`, value }) 255 channel_layout: (value: number) => ({ label: $localize`Channel Layout`, value })
256 }) 256 })
257 } 257 }
258 258
diff --git a/client/src/app/shared/shared-video-miniature/video-list-header.component.ts b/client/src/app/shared/shared-video-miniature/video-list-header.component.ts
index 08a961be1..fed696672 100644
--- a/client/src/app/shared/shared-video-miniature/video-list-header.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-list-header.component.ts
@@ -11,7 +11,7 @@ export abstract class GenericHeaderComponent {
11 11
12@Component({ 12@Component({
13 selector: 'my-video-list-header', 13 selector: 'my-video-list-header',
14 // tslint:disable-next-line:use-component-view-encapsulation 14 // eslint-disable-next-line @angular-eslint/use-component-view-encapsulation
15 encapsulation: ViewEncapsulation.None, 15 encapsulation: ViewEncapsulation.None,
16 templateUrl: './video-list-header.component.html' 16 templateUrl: './video-list-header.component.html'
17}) 17})
diff --git a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts
index d64ee9b98..456b36926 100644
--- a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts
+++ b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts
@@ -108,7 +108,7 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni
108 } 108 }
109 109
110 isInSelectionMode () { 110 isInSelectionMode () {
111 return Object.keys(this._selection).some(k => this._selection[ k ] === true) 111 return Object.keys(this._selection).some(k => this._selection[k] === true)
112 } 112 }
113 113
114 generateSyndicationList () { 114 generateSyndicationList () {
diff --git a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
index df3aeddb7..553930595 100644
--- a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
+++ b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
@@ -191,7 +191,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
191 } 191 }
192 192
193 createPlaylist () { 193 createPlaylist () {
194 const displayName = this.form.value[ 'displayName' ] 194 const displayName = this.form.value['displayName']
195 195
196 const videoPlaylistCreate: VideoPlaylistCreate = { 196 const videoPlaylistCreate: VideoPlaylistCreate = {
197 displayName, 197 displayName,
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element.model.ts b/client/src/app/shared/shared-video-playlist/video-playlist-element.model.ts
index f25f10ede..b661378bd 100644
--- a/client/src/app/shared/shared-video-playlist/video-playlist-element.model.ts
+++ b/client/src/app/shared/shared-video-playlist/video-playlist-element.model.ts
@@ -11,7 +11,7 @@ export class VideoPlaylistElement implements ServerVideoPlaylistElement {
11 11
12 video?: Video 12 video?: Video
13 13
14 constructor (hash: ServerVideoPlaylistElement, translations: {}) { 14 constructor (hash: ServerVideoPlaylistElement, translations: { [ id: string ]: string } = {}) {
15 this.id = hash.id 15 this.id = hash.id
16 this.position = hash.position 16 this.position = hash.position
17 this.startTimestamp = hash.startTimestamp 17 this.startTimestamp = hash.startTimestamp
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts
index fcc2ce705..6b38d9ca3 100644
--- a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts
+++ b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts
@@ -48,7 +48,7 @@ export class VideoPlaylist implements ServerVideoPlaylist {
48 return buildPlaylistWatchPath({ shortUUID: playlist.shortUUID || playlist.uuid }) 48 return buildPlaylistWatchPath({ shortUUID: playlist.shortUUID || playlist.uuid })
49 } 49 }
50 50
51 constructor (hash: ServerVideoPlaylist, translations: {}) { 51 constructor (hash: ServerVideoPlaylist, translations: { [ id: string ]: string }) {
52 const absoluteAPIUrl = getAbsoluteAPIUrl() 52 const absoluteAPIUrl = getAbsoluteAPIUrl()
53 53
54 this.id = hash.id 54 this.id = hash.id
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.service.ts b/client/src/app/shared/shared-video-playlist/video-playlist.service.ts
index a3f1393ff..0a01af593 100644
--- a/client/src/app/shared/shared-video-playlist/video-playlist.service.ts
+++ b/client/src/app/shared/shared-video-playlist/video-playlist.service.ts
@@ -279,18 +279,18 @@ export class VideoPlaylistService {
279 } 279 }
280 280
281 listenToVideoPlaylistChange (videoId: number) { 281 listenToVideoPlaylistChange (videoId: number) {
282 if (this.videoExistsObservableCache[ videoId ]) { 282 if (this.videoExistsObservableCache[videoId]) {
283 return this.videoExistsObservableCache[ videoId ] 283 return this.videoExistsObservableCache[videoId]
284 } 284 }
285 285
286 const obs = this.videoExistsInPlaylistObservable 286 const obs = this.videoExistsInPlaylistObservable
287 .pipe( 287 .pipe(
288 map(existsResult => existsResult[ videoId ]), 288 map(existsResult => existsResult[videoId]),
289 filter(r => !!r), 289 filter(r => !!r),
290 tap(result => this.videoExistsCache[ videoId ] = result) 290 tap(result => this.videoExistsCache[videoId] = result)
291 ) 291 )
292 292
293 this.videoExistsObservableCache[ videoId ] = obs 293 this.videoExistsObservableCache[videoId] = obs
294 return obs 294 return obs
295 } 295 }
296 296