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 5f0a5ff6c..844620ca2 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 @@ -445,13 +445,11 @@ allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart. -
- +
+ + jobs in parallel
+
{{ formErrors.import.concurrency }}
@@ -892,13 +890,13 @@ will claim at least {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with live transcoding -
- -
+ +
{{ formErrors.transcoding.threads }}
@@ -908,13 +906,11 @@ allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart. -
- +
+ + jobs in parallel
+
{{ formErrors.transcoding.concurrency }}
@@ -922,7 +918,7 @@ new transcoding profiles can be added by PeerTube plugins - x264, targeting maximum device compatibility - +
{{ formErrors.transcoding.profile }}
@@ -1007,10 +1003,10 @@
- + bindLabel="label" bindValue="value" [clearable]="false" [searchable]="true" + >
@@ -1069,13 +1065,12 @@ will claim at least {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with VOD transcoding -
- -
+
{{ formErrors.live.transcoding.threads }}
@@ -1083,7 +1078,7 @@ new live transcoding profiles can be added by PeerTube plugins - x264, targeting maximum device compatibility - +
{{ formErrors.live.transcoding.profile }}
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss index 665247368..c12465d45 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss @@ -42,7 +42,8 @@ input[type=checkbox] { @include peertube-select-container($form-base-input-width); } -ng-select, +my-select-options, +my-select-custom-value, my-select-checkbox { @include responsive-width($form-base-input-width); 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 48fb86968..a9f72d7db 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 @@ -37,12 +37,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A resolutions: { id: string, label: string, description?: string }[] = [] liveResolutions: { id: string, label: string, description?: string }[] = [] - concurrencyOptions: number[] = [] - transcodingThreadOptions: { label: string, value: number }[] = [] - liveMaxDurationOptions: { label: string, value: number }[] = [] - vodTranscodingProfileOptions: string[] = [] - liveTranscodingProfileOptions: string[] = [] + transcodingThreadOptions: SelectOptionsItem[] = [] + liveMaxDurationOptions: SelectOptionsItem[] = [] languageItems: SelectOptionsItem[] = [] categoryItems: SelectOptionsItem[] = [] @@ -99,23 +96,22 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A this.liveResolutions = this.resolutions.filter(r => r.id !== '0p') this.transcodingThreadOptions = [ - { value: 0, label: $localize`Auto (via ffmpeg)` }, - { value: 1, label: '1' }, - { value: 2, label: '2' }, - { value: 4, label: '4' }, - { value: 8, label: '8' } + { id: 0, label: $localize`Auto (via ffmpeg)` }, + { id: 1, label: '1' }, + { id: 2, label: '2' }, + { id: 4, label: '4' }, + { id: 8, label: '8' }, + { id: 12, label: '12' }, + { id: 16, label: '16' }, + { id: 32, label: '32' } ] - this.concurrencyOptions = [ 1, 2, 3, 4, 5, 6 ] - - this.vodTranscodingProfileOptions = [ 'default' ] - this.liveTranscodingProfileOptions = [ 'default' ] this.liveMaxDurationOptions = [ - { value: -1, label: $localize`No limit` }, - { value: 1000 * 3600, label: $localize`1 hour` }, - { value: 1000 * 3600 * 3, label: $localize`3 hours` }, - { value: 1000 * 3600 * 5, label: $localize`5 hours` }, - { value: 1000 * 3600 * 10, label: $localize`10 hours` } + { id: -1, label: $localize`No limit` }, + { id: 1000 * 3600, label: $localize`1 hour` }, + { id: 1000 * 3600 * 3, label: $localize`3 hours` }, + { id: 1000 * 3600 * 5, label: $localize`5 hours` }, + { id: 1000 * 3600 * 10, label: $localize`10 hours` } ] } @@ -137,11 +133,11 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A } getAvailableTranscodingProfile (type: 'live' | 'vod') { - if (type === 'live') { - return this.serverConfig.live.transcoding.availableProfiles - } + const profiles = type === 'live' + ? this.serverConfig.live.transcoding.availableProfiles + : this.serverConfig.transcoding.availableProfiles - return this.serverConfig.transcoding.availableProfiles + return profiles.map(p => ({ id: p, label: p })) } getTotalTranscodingThreads () { diff --git a/client/src/app/shared/shared-forms/select/index.ts b/client/src/app/shared/shared-forms/select/index.ts index 33459b23b..e387e1f48 100644 --- a/client/src/app/shared/shared-forms/select/index.ts +++ b/client/src/app/shared/shared-forms/select/index.ts @@ -1,4 +1,5 @@ export * from './select-channel.component' +export * from './select-checkbox.component' +export * from './select-custom-value.component' export * from './select-options.component' export * from './select-tags.component' -export * from './select-checkbox.component' diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.html b/client/src/app/shared/shared-forms/select/select-custom-input.component.html deleted file mode 100644 index 84fa15c3d..000000000 --- a/client/src/app/shared/shared-forms/select/select-custom-input.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - {{ channel.label }} - - - - diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.scss b/client/src/app/shared/shared-forms/select/select-custom-input.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.ts b/client/src/app/shared/shared-forms/select/select-custom-input.component.ts deleted file mode 100644 index ba6fef8ad..000000000 --- a/client/src/app/shared/shared-forms/select/select-custom-input.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component, forwardRef, Input } from '@angular/core' -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' - -@Component({ - selector: 'my-select-custom-input', - styleUrls: [ './select-custom-input.component.scss' ], - templateUrl: './select-custom-input.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => SelectCustomInputComponent), - multi: true - } - ] -}) -export class SelectCustomInputComponent implements ControlValueAccessor { - @Input() items: any[] = [] - - selectedId: number - - // ng-select options - bindLabel = 'label' - bindValue = 'id' - clearable = false - searchable = false - - propagateChange = (_: any) => { /* empty */ } - - writeValue (id: number) { - this.selectedId = id - } - - registerOnChange (fn: (_: any) => void) { - this.propagateChange = fn - } - - registerOnTouched () { - // Unused - } - - onModelChange () { - this.propagateChange(this.selectedId) - } -} 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 new file mode 100644 index 000000000..5fdf432ff --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.html @@ -0,0 +1,14 @@ +
+ + + +
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 new file mode 100644 index 000000000..a8e5ad0d3 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.ts @@ -0,0 +1,76 @@ +import { Component, forwardRef, Input, OnChanges } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { SelectOptionsItem } from './select-options.component' + +@Component({ + selector: 'my-select-custom-value', + styleUrls: [ './select-shared.component.scss' ], + templateUrl: './select-custom-value.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectCustomValueComponent), + multi: true + } + ] +}) +export class SelectCustomValueComponent implements ControlValueAccessor, OnChanges { + @Input() items: SelectOptionsItem[] = [] + @Input() clearable = false + @Input() searchable = false + @Input() groupBy: string + @Input() labelForId: string + + customValue: number | string = '' + selectedId: number | string + + itemsWithCustom: SelectOptionsItem[] = [] + + ngOnChanges () { + this.itemsWithCustom = this.getItems() + } + + propagateChange = (_: any) => { /* empty */ } + + writeValue (id: number | string) { + this.selectedId = id + + if (this.isSelectedIdInItems() !== true) { + this.selectedId = 'other' + this.customValue = id + } + } + + registerOnChange (fn: (_: any) => void) { + this.propagateChange = fn + } + + registerOnTouched () { + // Unused + } + + onModelChange () { + if (this.selectedId === 'other') { + return this.propagateChange(this.customValue) + } + + return this.propagateChange(this.selectedId) + } + + isSelectedIdInItems () { + return !!this.items.find(i => i.id === this.selectedId) + } + + getItems () { + const other: SelectOptionsItem = { + id: 'other', + label: $localize`Custom value...` + } + + return this.items.concat([ other ]) + } + + isCustomValue () { + return this.selectedId === 'other' + } +} diff --git a/client/src/app/shared/shared-forms/select/select-options.component.html b/client/src/app/shared/shared-forms/select/select-options.component.html index 6d0d7e925..3b1761255 100644 --- a/client/src/app/shared/shared-forms/select/select-options.component.html +++ b/client/src/app/shared/shared-forms/select/select-options.component.html @@ -6,6 +6,7 @@ [clearable]="clearable" [labelForId]="labelForId" [searchable]="searchable" + [searchFn]="searchFn" bindLabel="label" bindValue="id" 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 f0abd1a68..51a3f515d 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 @@ -27,6 +27,7 @@ export class SelectOptionsComponent implements ControlValueAccessor { @Input() searchable = false @Input() groupBy: string @Input() labelForId: string + @Input() searchFn: any selectedId: number | string 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 0b4c6b784..1a4192b55 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 @@ -30,3 +30,18 @@ ng-select ::ng-deep { width: 20px; } } + +.root { + display:flex; + + > my-select-options { + flex-grow: 1; + } +} + +input[type=text] { + margin-left: 5px; + + @include peertube-input-text($form-base-input-width); + display: block; +} diff --git a/client/src/app/shared/shared-forms/shared-form.module.ts b/client/src/app/shared/shared-forms/shared-form.module.ts index 22e8dd05a..9bdd138a1 100644 --- a/client/src/app/shared/shared-forms/shared-form.module.ts +++ b/client/src/app/shared/shared-forms/shared-form.module.ts @@ -7,13 +7,19 @@ import { SharedGlobalIconModule } from '../shared-icons' import { SharedMainModule } from '../shared-main/shared-main.module' import { DynamicFormFieldComponent } from './dynamic-form-field.component' import { FormValidatorService } from './form-validator.service' -import { InputToggleHiddenComponent } from './input-toggle-hidden.component' import { InputSwitchComponent } from './input-switch.component' +import { InputToggleHiddenComponent } from './input-toggle-hidden.component' import { MarkdownTextareaComponent } from './markdown-textarea.component' import { PeertubeCheckboxComponent } from './peertube-checkbox.component' import { PreviewUploadComponent } from './preview-upload.component' import { ReactiveFileComponent } from './reactive-file.component' -import { SelectChannelComponent, SelectCheckboxComponent, SelectOptionsComponent, SelectTagsComponent } from './select' +import { + SelectChannelComponent, + SelectCheckboxComponent, + SelectCustomValueComponent, + SelectOptionsComponent, + SelectTagsComponent +} from './select' import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' import { TimestampInputComponent } from './timestamp-input.component' @@ -44,6 +50,7 @@ import { TimestampInputComponent } from './timestamp-input.component' SelectOptionsComponent, SelectTagsComponent, SelectCheckboxComponent, + SelectCustomValueComponent, DynamicFormFieldComponent ], @@ -69,6 +76,7 @@ import { TimestampInputComponent } from './timestamp-input.component' SelectOptionsComponent, SelectTagsComponent, SelectCheckboxComponent, + SelectCustomValueComponent, DynamicFormFieldComponent ],