aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-02-10 09:05:29 +0100
committerChocobozzz <me@florianbigard.com>2021-02-10 11:36:40 +0100
commit21e493d4d8acb7a650eff3a30cd7e086b3cb8a28 (patch)
treef3a451d6a59925907c62b0c36db99745a43b67db
parentead64cdf8d917fa0d6a20271e42378f38e5f2407 (diff)
downloadPeerTube-21e493d4d8acb7a650eff3a30cd7e086b3cb8a28.tar.gz
PeerTube-21e493d4d8acb7a650eff3a30cd7e086b3cb8a28.tar.zst
PeerTube-21e493d4d8acb7a650eff3a30cd7e086b3cb8a28.zip
Add ability to set a custom quota
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html32
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts3
-rw-r--r--client/src/app/+admin/config/shared/config.service.ts47
-rw-r--r--client/src/app/+admin/users/user-edit/user-create.component.ts4
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.component.html36
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.component.scss14
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.ts21
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.ts3
-rw-r--r--client/src/app/+videos/+video-edit/shared/video-edit.component.ts5
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-send.ts3
-rw-r--r--client/src/app/+videos/+video-edit/video-update.component.ts3
-rw-r--r--client/src/app/helpers/utils.ts4
-rw-r--r--client/src/app/shared/form-validators/form-validator.model.ts2
-rw-r--r--client/src/app/shared/shared-forms/select/select-channel.component.ts25
-rw-r--r--client/src/app/shared/shared-forms/select/select-checkbox.component.ts2
-rw-r--r--client/src/app/shared/shared-forms/select/select-custom-value.component.html6
-rw-r--r--client/src/app/shared/shared-forms/select/select-custom-value.component.ts4
-rw-r--r--client/src/app/shared/shared-forms/select/select-options.component.ts9
-rw-r--r--client/src/app/shared/shared-forms/select/select-shared.component.scss7
-rw-r--r--client/src/app/shared/shared-user-settings/user-video-settings.component.ts3
-rw-r--r--client/src/types/select-options-item.model.ts13
21 files changed, 141 insertions, 105 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
index 844620ca2..637203b96 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
@@ -402,25 +402,29 @@
402 <ng-container formGroupName="user"> 402 <ng-container formGroupName="user">
403 <div class="form-group"> 403 <div class="form-group">
404 <label i18n for="userVideoQuota">Default video quota per user</label> 404 <label i18n for="userVideoQuota">Default video quota per user</label>
405 <div class="peertube-select-container"> 405
406 <select id="userVideoQuota" formControlName="videoQuota" class="form-control"> 406 <my-select-custom-value
407 <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value" [disabled]="videoQuotaOption.disabled"> 407 id="userVideoQuota"
408 {{ videoQuotaOption.label }} 408 [items]="videoQuotaOptions"
409 </option> 409 formControlName="videoQuota"
410 </select> 410 i18n-inputSuffix inputSuffix="bytes" inputType="number"
411 </div> 411 [clearable]="false"
412 ></my-select-custom-value>
413
412 <div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div> 414 <div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div>
413 </div> 415 </div>
414 416
415 <div class="form-group"> 417 <div class="form-group">
416 <label i18n for="userVideoQuotaDaily">Default daily upload limit per user</label> 418 <label i18n for="userVideoQuotaDaily">Default daily upload limit per user</label>
417 <div class="peertube-select-container"> 419
418 <select id="userVideoQuotaDaily" formControlName="videoQuotaDaily" class="form-control"> 420 <my-select-custom-value
419 <option *ngFor="let videoQuotaDailyOption of videoQuotaDailyOptions" [value]="videoQuotaDailyOption.value" [disabled]="videoQuotaDailyOption.disabled"> 421 id="userVideoQuotaDaily"
420 {{ videoQuotaDailyOption.label }} 422 [items]="videoQuotaDailyOptions"
421 </option> 423 formControlName="videoQuotaDaily"
422 </select> 424 i18n-inputSuffix inputSuffix="bytes" inputType="number"
423 </div> 425 [clearable]="false"
426 ></my-select-custom-value>
427
424 <div *ngIf="formErrors.user.videoQuotaDaily" class="form-error">{{ formErrors.user.videoQuotaDaily }}</div> 428 <div *ngIf="formErrors.user.videoQuotaDaily" class="form-error">{{ formErrors.user.videoQuotaDaily }}</div>
425 </div> 429 </div>
426 </ng-container> 430 </ng-container>
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index a9f72d7db..56be97e84 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -19,9 +19,10 @@ import {
19 TRANSCODING_THREADS_VALIDATOR 19 TRANSCODING_THREADS_VALIDATOR
20} from '@app/shared/form-validators/custom-config-validators' 20} from '@app/shared/form-validators/custom-config-validators'
21import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators' 21import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
22import { FormReactive, FormValidatorService, SelectOptionsItem } from '@app/shared/shared-forms' 22import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
23import { NgbNav } from '@ng-bootstrap/ng-bootstrap' 23import { NgbNav } from '@ng-bootstrap/ng-bootstrap'
24import { CustomConfig, ServerConfig } from '@shared/models' 24import { CustomConfig, ServerConfig } from '@shared/models'
25import { SelectOptionsItem } from 'src/types/select-options-item.model'
25 26
26@Component({ 27@Component({
27 selector: 'my-edit-custom-config', 28 selector: 'my-edit-custom-config',
diff --git a/client/src/app/+admin/config/shared/config.service.ts b/client/src/app/+admin/config/shared/config.service.ts
index 5f98aa545..d29b752f7 100644
--- a/client/src/app/+admin/config/shared/config.service.ts
+++ b/client/src/app/+admin/config/shared/config.service.ts
@@ -3,43 +3,46 @@ import { HttpClient } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { RestExtractor } from '@app/core' 4import { RestExtractor } from '@app/core'
5import { CustomConfig } from '@shared/models' 5import { CustomConfig } from '@shared/models'
6import { SelectOptionsItem } from '../../../../types/select-options-item.model'
6import { environment } from '../../../../environments/environment' 7import { environment } from '../../../../environments/environment'
7 8
8@Injectable() 9@Injectable()
9export class ConfigService { 10export class ConfigService {
10 private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/config' 11 private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/config'
11 12
12 videoQuotaOptions: { value: number, label: string, disabled?: boolean }[] = [] 13 videoQuotaOptions: SelectOptionsItem[] = []
13 videoQuotaDailyOptions: { value: number, label: string, disabled?: boolean }[] = [] 14 videoQuotaDailyOptions: SelectOptionsItem[] = []
14 15
15 constructor ( 16 constructor (
16 private authHttp: HttpClient, 17 private authHttp: HttpClient,
17 private restExtractor: RestExtractor 18 private restExtractor: RestExtractor
18 ) { 19 ) {
19 this.videoQuotaOptions = [ 20 this.videoQuotaOptions = [
20 { value: undefined, label: 'Default quota', disabled: true }, 21 { id: -1, label: $localize`Unlimited` },
21 { value: -1, label: $localize`Unlimited` }, 22 { id: 0, label: $localize`None - no upload possible` },
22 { value: undefined, label: '─────', disabled: true }, 23 { id: 100 * 1024 * 1024, label: $localize`100MB` },
23 { value: 0, label: $localize`None - no upload possible` }, 24 { id: 500 * 1024 * 1024, label: $localize`500MB` },
24 { value: 100 * 1024 * 1024, label: $localize`100MB` }, 25 { id: 1024 * 1024 * 1024, label: $localize`1GB` },
25 { value: 500 * 1024 * 1024, label: $localize`500MB` }, 26 { id: 5 * 1024 * 1024 * 1024, label: $localize`5GB` },
26 { value: 1024 * 1024 * 1024, label: $localize`1GB` }, 27 { id: 20 * 1024 * 1024 * 1024, label: $localize`20GB` },
27 { value: 5 * 1024 * 1024 * 1024, label: $localize`5GB` }, 28 { id: 50 * 1024 * 1024 * 1024, label: $localize`50GB` },
28 { value: 20 * 1024 * 1024 * 1024, label: $localize`20GB` }, 29 { id: 100 * 1024 * 1024 * 1024, label: $localize`100GB` },
29 { value: 50 * 1024 * 1024 * 1024, label: $localize`50GB` } 30 { id: 200 * 1024 * 1024 * 1024, label: $localize`200GB` },
31 { id: 500 * 1024 * 1024 * 1024, label: $localize`500GB` }
30 ] 32 ]
31 33
32 this.videoQuotaDailyOptions = [ 34 this.videoQuotaDailyOptions = [
33 { value: undefined, label: 'Default daily upload limit', disabled: true }, 35 { id: -1, label: $localize`Unlimited` },
34 { value: -1, label: $localize`Unlimited` }, 36 { id: 0, label: $localize`None - no upload possible` },
35 { value: undefined, label: '─────', disabled: true }, 37 { id: 10 * 1024 * 1024, label: $localize`10MB` },
36 { value: 0, label: $localize`None - no upload possible` }, 38 { id: 50 * 1024 * 1024, label: $localize`50MB` },
37 { value: 10 * 1024 * 1024, label: $localize`10MB` }, 39 { id: 100 * 1024 * 1024, label: $localize`100MB` },
38 { value: 50 * 1024 * 1024, label: $localize`50MB` }, 40 { id: 500 * 1024 * 1024, label: $localize`500MB` },
39 { value: 100 * 1024 * 1024, label: $localize`100MB` }, 41 { id: 2 * 1024 * 1024 * 1024, label: $localize`2GB` },
40 { value: 500 * 1024 * 1024, label: $localize`500MB` }, 42 { id: 5 * 1024 * 1024 * 1024, label: $localize`5GB` },
41 { value: 2 * 1024 * 1024 * 1024, label: $localize`2GB` }, 43 { id: 10 * 1024 * 1024 * 1024, label: $localize`10GB` },
42 { value: 5 * 1024 * 1024 * 1024, label: $localize`5GB` } 44 { id: 20 * 1024 * 1024 * 1024, label: $localize`20GB` },
45 { id: 50 * 1024 * 1024 * 1024, label: $localize`50GB` }
43 ] 46 ]
44 } 47 }
45 48
diff --git a/client/src/app/+admin/users/user-edit/user-create.component.ts b/client/src/app/+admin/users/user-edit/user-create.component.ts
index d0aac1cb9..da333240c 100644
--- a/client/src/app/+admin/users/user-edit/user-create.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-create.component.ts
@@ -45,8 +45,8 @@ export class UserCreateComponent extends UserEdit implements OnInit {
45 45
46 const defaultValues = { 46 const defaultValues = {
47 role: UserRole.USER.toString(), 47 role: UserRole.USER.toString(),
48 videoQuota: '-1', 48 videoQuota: -1,
49 videoQuotaDaily: '-1' 49 videoQuotaDaily: -1
50 } 50 }
51 51
52 this.buildForm({ 52 this.buildForm({
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.html b/client/src/app/+admin/users/user-edit/user-edit.component.html
index fb34d6b22..243c6556a 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.component.html
+++ b/client/src/app/+admin/users/user-edit/user-edit.component.html
@@ -149,28 +149,38 @@
149 149
150 <div class="form-group"> 150 <div class="form-group">
151 <label i18n for="videoQuota">Video quota</label> 151 <label i18n for="videoQuota">Video quota</label>
152 <div class="peertube-select-container"> 152
153 <select id="videoQuota" formControlName="videoQuota" class="form-control"> 153 <my-select-custom-value
154 <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value" [disabled]="videoQuotaOption.disabled"> 154 id="videoQuota"
155 {{ videoQuotaOption.label }} 155 [items]="videoQuotaOptions"
156 </option> 156 formControlName="videoQuota"
157 </select> 157 i18n-inputSuffix inputSuffix="bytes" inputType="number"
158 </div> 158 [clearable]="false"
159 ></my-select-custom-value>
159 160
160 <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()"> 161 <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
161 Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br /> 162 Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br />
162 At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}. 163 At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}.
163 </div> 164 </div>
165
166 <div *ngIf="formErrors.videoQuota" class="form-error">
167 {{ formErrors.videoQuota }}
168 </div>
164 </div> 169 </div>
165 170
166 <div class="form-group"> 171 <div class="form-group">
167 <label i18n for="videoQuotaDaily">Daily video quota</label> 172 <label i18n for="videoQuotaDaily">Daily video quota</label>
168 <div class="peertube-select-container"> 173
169 <select id="videoQuotaDaily" formControlName="videoQuotaDaily" class="form-control"> 174 <my-select-custom-value
170 <option *ngFor="let videoQuotaDailyOption of videoQuotaDailyOptions" [value]="videoQuotaDailyOption.value" [disabled]="videoQuotaDailyOption.disabled"> 175 id="videoQuotaDaily"
171 {{ videoQuotaDailyOption.label }} 176 [items]="videoQuotaDailyOptions"
172 </option> 177 formControlName="videoQuotaDaily"
173 </select> 178 i18n-inputSuffix inputSuffix="bytes" inputType="number"
179 [clearable]="false"
180 ></my-select-custom-value>
181
182 <div *ngIf="formErrors.videoQuotaDaily" class="form-error">
183 {{ formErrors.videoQuotaDaily }}
174 </div> 184 </div>
175 </div> 185 </div>
176 186
diff --git a/client/src/app/+admin/users/user-edit/user-edit.component.scss b/client/src/app/+admin/users/user-edit/user-edit.component.scss
index 3b7715062..aa87b8d6d 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.component.scss
+++ b/client/src/app/+admin/users/user-edit/user-edit.component.scss
@@ -1,6 +1,8 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4$form-base-input-width: 340px;
5
4label { 6label {
5 font-weight: $font-regular; 7 font-weight: $font-regular;
6 font-size: 100%; 8 font-size: 100%;
@@ -15,18 +17,24 @@ label {
15} 17}
16 18
17input:not([type=submit]) { 19input:not([type=submit]) {
18 @include peertube-input-text(340px); 20 @include peertube-input-text($form-base-input-width);
19 display: block; 21 display: block;
20} 22}
21 23
22my-input-toggle-hidden { 24my-input-toggle-hidden {
23 @include responsive-width(340px); 25 @include responsive-width($form-base-input-width);
24 26
25 display: block; 27 display: block;
26} 28}
27 29
28.peertube-select-container { 30.peertube-select-container {
29 @include peertube-select-container(340px); 31 @include peertube-select-container($form-base-input-width);
32}
33
34my-select-custom-value {
35 @include responsive-width($form-base-input-width);
36
37 display: block;
30} 38}
31 39
32input[type=submit], button { 40input[type=submit], button {
diff --git a/client/src/app/+admin/users/user-edit/user-edit.ts b/client/src/app/+admin/users/user-edit/user-edit.ts
index faa2f5ad8..2fc3c5d3b 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.ts
+++ b/client/src/app/+admin/users/user-edit/user-edit.ts
@@ -4,12 +4,13 @@ import { AuthService, ScreenService, ServerService, User } from '@app/core'
4import { FormReactive } from '@app/shared/shared-forms' 4import { FormReactive } from '@app/shared/shared-forms'
5import { USER_ROLE_LABELS } from '@shared/core-utils/users' 5import { USER_ROLE_LABELS } from '@shared/core-utils/users'
6import { ServerConfig, UserAdminFlag, UserRole, VideoResolution } from '@shared/models' 6import { ServerConfig, UserAdminFlag, UserRole, VideoResolution } from '@shared/models'
7import { SelectOptionsItem } from '../../../../types/select-options-item.model'
7 8
8@Directive() 9@Directive()
9// tslint:disable-next-line: directive-class-suffix 10// tslint:disable-next-line: directive-class-suffix
10export abstract class UserEdit extends FormReactive implements OnInit { 11export abstract class UserEdit extends FormReactive implements OnInit {
11 videoQuotaOptions: { value: string, label: string, disabled?: boolean }[] = [] 12 videoQuotaOptions: SelectOptionsItem[] = []
12 videoQuotaDailyOptions: { value: string, label: string, disabled?: boolean }[] = [] 13 videoQuotaDailyOptions: SelectOptionsItem[] = []
13 username: string 14 username: string
14 user: User 15 user: User
15 16
@@ -97,19 +98,7 @@ export abstract class UserEdit extends FormReactive implements OnInit {
97 } 98 }
98 99
99 protected buildQuotaOptions () { 100 protected buildQuotaOptions () {
100 // These are used by a HTML select, so convert key into strings 101 this.videoQuotaOptions = this.configService.videoQuotaOptions
101 this.videoQuotaOptions = this.configService 102 this.videoQuotaDailyOptions = this.configService.videoQuotaDailyOptions
102 .videoQuotaOptions.map(q => ({
103 value: q.value?.toString(),
104 label: q.label,
105 disabled: q.disabled
106 }))
107
108 this.videoQuotaDailyOptions = this.configService
109 .videoQuotaDailyOptions.map(q => ({
110 value: q.value?.toString(),
111 label: q.label,
112 disabled: q.disabled
113 }))
114 } 103 }
115} 104}
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.ts
index 40ba23e75..71db0592a 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.ts
@@ -1,6 +1,7 @@
1import { FormReactive, SelectChannelItem } from '@app/shared/shared-forms' 1import { FormReactive } from '@app/shared/shared-forms'
2import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models' 2import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models'
3import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' 3import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model'
4import { SelectChannelItem } from '../../../types/select-options-item.model'
4 5
5export abstract class MyVideoPlaylistEdit extends FormReactive { 6export abstract class MyVideoPlaylistEdit extends FormReactive {
6 // Declare it here to avoid errors in create template 7 // Declare it here to avoid errors in create template
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.ts b/client/src/app/+videos/+video-edit/shared/video-edit.component.ts
index 80b5dce46..f51f52160 100644
--- a/client/src/app/+videos/+video-edit/shared/video-edit.component.ts
+++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.ts
@@ -1,5 +1,6 @@
1import { forkJoin } from 'rxjs' 1import { forkJoin } from 'rxjs'
2import { map } from 'rxjs/operators' 2import { map } from 'rxjs/operators'
3import { SelectChannelItem } from 'src/types/select-options-item.model'
3import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' 4import { Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
4import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms' 5import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
5import { HooksService, PluginService, ServerService } from '@app/core' 6import { HooksService, PluginService, ServerService } from '@app/core'
@@ -17,10 +18,10 @@ import {
17 VIDEO_SUPPORT_VALIDATOR, 18 VIDEO_SUPPORT_VALIDATOR,
18 VIDEO_TAGS_ARRAY_VALIDATOR 19 VIDEO_TAGS_ARRAY_VALIDATOR
19} from '@app/shared/form-validators/video-validators' 20} from '@app/shared/form-validators/video-validators'
20import { FormReactiveValidationMessages, FormValidatorService, SelectChannelItem } from '@app/shared/shared-forms' 21import { FormReactiveValidationMessages, FormValidatorService } from '@app/shared/shared-forms'
21import { InstanceService } from '@app/shared/shared-instance' 22import { InstanceService } from '@app/shared/shared-instance'
22import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main' 23import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
23import { ServerConfig, VideoConstant, LiveVideo, VideoPrivacy } from '@shared/models' 24import { LiveVideo, ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
24import { RegisterClientFormFieldOptions, RegisterClientVideoFieldOptions } from '@shared/models/plugins/register-client-form-field.model' 25import { RegisterClientFormFieldOptions, RegisterClientVideoFieldOptions } from '@shared/models/plugins/register-client-form-field.model'
25import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' 26import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
26import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' 27import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-send.ts b/client/src/app/+videos/+video-edit/video-add-components/video-send.ts
index 812936d7a..9a22024e5 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-send.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-send.ts
@@ -1,8 +1,9 @@
1import { catchError, switchMap, tap } from 'rxjs/operators' 1import { catchError, switchMap, tap } from 'rxjs/operators'
2import { SelectChannelItem } from 'src/types/select-options-item.model'
2import { Directive, EventEmitter, OnInit } from '@angular/core' 3import { Directive, EventEmitter, OnInit } from '@angular/core'
3import { AuthService, CanComponentDeactivateResult, Notifier, ServerService } from '@app/core' 4import { AuthService, CanComponentDeactivateResult, Notifier, ServerService } from '@app/core'
4import { populateAsyncUserVideoChannels } from '@app/helpers' 5import { populateAsyncUserVideoChannels } from '@app/helpers'
5import { FormReactive, SelectChannelItem } from '@app/shared/shared-forms' 6import { FormReactive } from '@app/shared/shared-forms'
6import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' 7import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
7import { LoadingBarService } from '@ngx-loading-bar/core' 8import { LoadingBarService } from '@ngx-loading-bar/core'
8import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' 9import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
diff --git a/client/src/app/+videos/+video-edit/video-update.component.ts b/client/src/app/+videos/+video-edit/video-update.component.ts
index 654901798..2973c6840 100644
--- a/client/src/app/+videos/+video-edit/video-update.component.ts
+++ b/client/src/app/+videos/+video-edit/video-update.component.ts
@@ -1,9 +1,10 @@
1import { of } from 'rxjs' 1import { of } from 'rxjs'
2import { map, switchMap } from 'rxjs/operators' 2import { map, switchMap } from 'rxjs/operators'
3import { SelectChannelItem } from 'src/types/select-options-item.model'
3import { Component, HostListener, OnInit } from '@angular/core' 4import { Component, HostListener, OnInit } from '@angular/core'
4import { ActivatedRoute, Router } from '@angular/router' 5import { ActivatedRoute, Router } from '@angular/router'
5import { Notifier } from '@app/core' 6import { Notifier } from '@app/core'
6import { FormReactive, FormValidatorService, SelectChannelItem } from '@app/shared/shared-forms' 7import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
7import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main' 8import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
8import { LiveVideoService } from '@app/shared/shared-video-live' 9import { LiveVideoService } from '@app/shared/shared-video-live'
9import { LoadingBarService } from '@ngx-loading-bar/core' 10import { LoadingBarService } from '@ngx-loading-bar/core'
diff --git a/client/src/app/helpers/utils.ts b/client/src/app/helpers/utils.ts
index b4e26d792..6d7e76b11 100644
--- a/client/src/app/helpers/utils.ts
+++ b/client/src/app/helpers/utils.ts
@@ -1,10 +1,10 @@
1import { SelectChannelItem } from 'src/types/select-options-item.model'
1import { DatePipe } from '@angular/common' 2import { DatePipe } from '@angular/common'
2import { HttpErrorResponse } from '@angular/common/http' 3import { HttpErrorResponse } from '@angular/common/http'
3import { Notifier } from '@app/core' 4import { Notifier } from '@app/core'
4import { SelectChannelItem } from '@app/shared/shared-forms' 5import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
5import { environment } from '../../environments/environment' 6import { environment } from '../../environments/environment'
6import { AuthService } from '../core/auth' 7import { AuthService } from '../core/auth'
7import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
8 8
9// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript 9// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
10function getParameterByName (name: string, url: string) { 10function getParameterByName (name: string, url: string) {
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 248a3b1d3..07b1ea075 100644
--- a/client/src/app/shared/form-validators/form-validator.model.ts
+++ b/client/src/app/shared/form-validators/form-validator.model.ts
@@ -10,5 +10,5 @@ export type BuildFormArgument = {
10} 10}
11 11
12export type BuildFormDefaultValues = { 12export type BuildFormDefaultValues = {
13 [ name: string ]: string | string[] | BuildFormDefaultValues 13 [ name: string ]: number | string | string[] | BuildFormDefaultValues
14} 14}
diff --git a/client/src/app/shared/shared-forms/select/select-channel.component.ts b/client/src/app/shared/shared-forms/select/select-channel.component.ts
index 1d91d59bc..40a7c53bb 100644
--- a/client/src/app/shared/shared-forms/select/select-channel.component.ts
+++ b/client/src/app/shared/shared-forms/select/select-channel.component.ts
@@ -1,13 +1,7 @@
1import { Component, forwardRef, Input } from '@angular/core' 1import { Component, forwardRef, Input, OnChanges } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { VideoChannel } from '@app/shared/shared-main' 3import { VideoChannel } from '@app/shared/shared-main'
4 4import { SelectChannelItem } from '../../../../types/select-options-item.model'
5export type SelectChannelItem = {
6 id: number
7 label: string
8 support: string
9 avatarPath?: string
10}
11 5
12@Component({ 6@Component({
13 selector: 'my-select-channel', 7 selector: 'my-select-channel',
@@ -21,9 +15,10 @@ export type SelectChannelItem = {
21 } 15 }
22 ] 16 ]
23}) 17})
24export class SelectChannelComponent implements ControlValueAccessor { 18export class SelectChannelComponent implements ControlValueAccessor, OnChanges {
25 @Input() items: SelectChannelItem[] = [] 19 @Input() items: SelectChannelItem[] = []
26 20
21 channels: SelectChannelItem[] = []
27 selectedId: number 22 selectedId: number
28 23
29 // ng-select options 24 // ng-select options
@@ -32,10 +27,14 @@ export class SelectChannelComponent implements ControlValueAccessor {
32 clearable = false 27 clearable = false
33 searchable = false 28 searchable = false
34 29
35 get channels () { 30 ngOnChanges () {
36 return this.items.map(c => Object.assign(c, { 31 this.channels = this.items.map(c => {
37 avatarPath: c.avatarPath ? c.avatarPath : VideoChannel.GET_DEFAULT_AVATAR_URL() 32 const avatarPath = c.avatarPath
38 })) 33 ? c.avatarPath
34 : VideoChannel.GET_DEFAULT_AVATAR_URL()
35
36 return Object.assign({}, c, { avatarPath })
37 })
39 } 38 }
40 39
41 propagateChange = (_: any) => { /* empty */ } 40 propagateChange = (_: any) => { /* empty */ }
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.ts b/client/src/app/shared/shared-forms/select/select-checkbox.component.ts
index eb0c49034..c2523f15c 100644
--- a/client/src/app/shared/shared-forms/select/select-checkbox.component.ts
+++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.ts
@@ -1,6 +1,6 @@
1import { Component, forwardRef, Input, OnInit } from '@angular/core' 1import { Component, forwardRef, Input, OnInit } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { SelectOptionsItem } from './select-options.component' 3import { SelectOptionsItem } from '../../../../types/select-options-item.model'
4 4
5export type ItemSelectCheckboxValue = { id?: string | number, group?: string } | string 5export type ItemSelectCheckboxValue = { id?: string | number, group?: string } | string
6 6
diff --git a/client/src/app/shared/shared-forms/select/select-custom-value.component.html b/client/src/app/shared/shared-forms/select/select-custom-value.component.html
index 5fdf432ff..9dc8c2ec2 100644
--- a/client/src/app/shared/shared-forms/select/select-custom-value.component.html
+++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.html
@@ -10,5 +10,9 @@
10 (ngModelChange)="onModelChange()" 10 (ngModelChange)="onModelChange()"
11 ></my-select-options> 11 ></my-select-options>
12 12
13 <input *ngIf="isCustomValue()" [(ngModel)]="customValue" (ngModelChange)="onModelChange()" type="text" class="form-control" /> 13 <ng-container *ngIf="isCustomValue()">
14 <input [(ngModel)]="customValue" (ngModelChange)="onModelChange()" [type]="inputType" class="form-control" />
15
16 <span *ngIf="inputSuffix" class="input-suffix">{{ inputSuffix }}</span>
17 </ng-container>
14</div> 18</div>
diff --git a/client/src/app/shared/shared-forms/select/select-custom-value.component.ts b/client/src/app/shared/shared-forms/select/select-custom-value.component.ts
index a8e5ad0d3..bc6b863c7 100644
--- a/client/src/app/shared/shared-forms/select/select-custom-value.component.ts
+++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.ts
@@ -1,6 +1,6 @@
1import { Component, forwardRef, Input, OnChanges } from '@angular/core' 1import { Component, forwardRef, Input, OnChanges } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { SelectOptionsItem } from './select-options.component' 3import { SelectOptionsItem } from '../../../../types/select-options-item.model'
4 4
5@Component({ 5@Component({
6 selector: 'my-select-custom-value', 6 selector: 'my-select-custom-value',
@@ -20,6 +20,8 @@ export class SelectCustomValueComponent implements ControlValueAccessor, OnChang
20 @Input() searchable = false 20 @Input() searchable = false
21 @Input() groupBy: string 21 @Input() groupBy: string
22 @Input() labelForId: string 22 @Input() labelForId: string
23 @Input() inputSuffix: string
24 @Input() inputType = 'text'
23 25
24 customValue: number | string = '' 26 customValue: number | string = ''
25 selectedId: number | string 27 selectedId: number | string
diff --git a/client/src/app/shared/shared-forms/select/select-options.component.ts b/client/src/app/shared/shared-forms/select/select-options.component.ts
index 51a3f515d..2890670e5 100644
--- a/client/src/app/shared/shared-forms/select/select-options.component.ts
+++ b/client/src/app/shared/shared-forms/select/select-options.component.ts
@@ -1,13 +1,6 @@
1import { Component, forwardRef, Input } from '@angular/core' 1import { Component, forwardRef, Input } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3 3import { SelectOptionsItem } from '../../../../types/select-options-item.model'
4export type SelectOptionsItem = {
5 id: string | number
6 label: string
7 description?: string
8 group?: string
9 groupLabel?: string
10}
11 4
12@Component({ 5@Component({
13 selector: 'my-select-options', 6 selector: 'my-select-options',
diff --git a/client/src/app/shared/shared-forms/select/select-shared.component.scss b/client/src/app/shared/shared-forms/select/select-shared.component.scss
index 1a4192b55..80196b8df 100644
--- a/client/src/app/shared/shared-forms/select/select-shared.component.scss
+++ b/client/src/app/shared/shared-forms/select/select-shared.component.scss
@@ -33,15 +33,20 @@ ng-select ::ng-deep {
33 33
34.root { 34.root {
35 display:flex; 35 display:flex;
36 align-items: center;
36 37
37 > my-select-options { 38 > my-select-options {
38 flex-grow: 1; 39 flex-grow: 1;
39 } 40 }
40} 41}
41 42
42input[type=text] { 43my-select-options + input {
43 margin-left: 5px; 44 margin-left: 5px;
44 45
45 @include peertube-input-text($form-base-input-width); 46 @include peertube-input-text($form-base-input-width);
46 display: block; 47 display: block;
47} 48}
49
50.input-suffix {
51 margin-left: 5px;
52}
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 2497e001c..d74c2b2d8 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
@@ -3,9 +3,10 @@ import { forkJoin, Subject, Subscription } from 'rxjs'
3import { first } from 'rxjs/operators' 3import { first } from 'rxjs/operators'
4import { Component, Input, OnDestroy, OnInit } from '@angular/core' 4import { Component, Input, OnDestroy, OnInit } from '@angular/core'
5import { AuthService, Notifier, ServerService, User, UserService } from '@app/core' 5import { AuthService, Notifier, ServerService, User, UserService } from '@app/core'
6import { FormReactive, FormValidatorService, ItemSelectCheckboxValue, SelectOptionsItem } from '@app/shared/shared-forms' 6import { FormReactive, FormValidatorService, ItemSelectCheckboxValue } from '@app/shared/shared-forms'
7import { UserUpdateMe } from '@shared/models' 7import { UserUpdateMe } from '@shared/models'
8import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' 8import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
9import { SelectOptionsItem } from '../../../types/select-options-item.model'
9 10
10@Component({ 11@Component({
11 selector: 'my-user-video-settings', 12 selector: 'my-user-video-settings',
diff --git a/client/src/types/select-options-item.model.ts b/client/src/types/select-options-item.model.ts
new file mode 100644
index 000000000..895965a74
--- /dev/null
+++ b/client/src/types/select-options-item.model.ts
@@ -0,0 +1,13 @@
1export interface SelectOptionsItem {
2 id: string | number
3 label: string
4 description?: string
5 group?: string
6 groupLabel?: string
7}
8
9export interface SelectChannelItem extends SelectOptionsItem {
10 id: number
11 support: string
12 avatarPath?: string
13}