Fix tags in search filters

This commit is contained in:
Chocobozzz 2020-08-11 09:22:42 +02:00
parent 02c01341f4
commit 9abd170dec
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
12 changed files with 59 additions and 40 deletions

View File

@ -68,13 +68,10 @@
<div class="form-group"> <div class="form-group">
<label i18n>Channel</label> <label i18n>Channel</label>
<div class="peertube-select-container">
<select formControlName="videoChannelId" class="form-control"> <my-select-channel
<option i18n value="undefined" disabled>Channel to bind the playlist to</option> labelForId="videoChannelIdl" [items]="userVideoChannels" formControlName="videoChannelId"
<option></option> ></my-select-channel>
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
</select>
</div>
<div *ngIf="formErrors['videoChannelId']" class="form-error"> <div *ngIf="formErrors['videoChannelId']" class="form-error">
{{ formErrors['videoChannelId'] }} {{ formErrors['videoChannelId'] }}

View File

@ -1,11 +1,12 @@
import { FormReactive } from '@app/shared/shared-forms' import { FormReactive } from '@app/shared/shared-forms'
import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models' import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models'
import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model'
export abstract class MyAccountVideoPlaylistEdit extends FormReactive { export abstract class MyAccountVideoPlaylistEdit extends FormReactive {
// Declare it here to avoid errors in create template // Declare it here to avoid errors in create template
videoPlaylistToUpdate: VideoPlaylist videoPlaylistToUpdate: VideoPlaylist
userVideoChannels: { id: number, label: string }[] = [] userVideoChannels: SelectChannelItem[] = []
videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = [] videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
abstract isCreation (): boolean abstract isCreation (): boolean

View File

@ -144,7 +144,7 @@
<button i18n class="reset-button reset-button-small" (click)="resetField('tagsAllOf')" *ngIf="advancedSearch.tagsAllOf"> <button i18n class="reset-button reset-button-small" (click)="resetField('tagsAllOf')" *ngIf="advancedSearch.tagsAllOf">
Reset Reset
</button> </button>
<my-select-tags labelForId="tagsAllOf" id="tagsAllOf" [(ngModel)]="advancedSearch.tagsAllOf"></my-select-tags> <my-select-tags name="tagsAllOf" labelForId="tagsAllOf" id="tagsAllOf" [(ngModel)]="advancedSearch.tagsAllOf"></my-select-tags>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -152,7 +152,7 @@
<button i18n class="reset-button reset-button-small" (click)="resetField('tagsOneOf')" *ngIf="advancedSearch.tagsOneOf"> <button i18n class="reset-button reset-button-small" (click)="resetField('tagsOneOf')" *ngIf="advancedSearch.tagsOneOf">
Reset Reset
</button> </button>
<my-select-tags labelForId="tagsOneOf" id="tagsOneOf" [(ngModel)]="advancedSearch.tagsOneOf"></my-select-tags> <my-select-tags name="tagsOneOf" labelForId="tagsOneOf" id="tagsOneOf" [(ngModel)]="advancedSearch.tagsOneOf"></my-select-tags>
</div> </div>
<div class="form-group" *ngIf="isSearchTargetEnabled()"> <div class="form-group" *ngIf="isSearchTargetEnabled()">

View File

@ -1,16 +1,17 @@
import { forkJoin } from 'rxjs'
import { map } from 'rxjs/operators' import { map } from 'rxjs/operators'
import { Component, Input, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' import { Component, Input, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms' import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { removeElementFromArray } from '@app/helpers' import { removeElementFromArray } from '@app/helpers'
import { FormReactiveValidationMessages, FormValidatorService, VideoValidatorsService } from '@app/shared/shared-forms' import { FormReactiveValidationMessages, FormValidatorService, VideoValidatorsService } from '@app/shared/shared-forms'
import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
import { InstanceService } from '@app/shared/shared-instance'
import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component' import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { forkJoin } from 'rxjs'
import { InstanceService } from '@app/shared/shared-instance'
type VideoLanguages = VideoConstant<string> & { group?: string } type VideoLanguages = VideoConstant<string> & { group?: string }
@ -23,7 +24,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
@Input() form: FormGroup @Input() form: FormGroup
@Input() formErrors: { [ id: string ]: string } = {} @Input() formErrors: { [ id: string ]: string } = {}
@Input() validationMessages: FormReactiveValidationMessages = {} @Input() validationMessages: FormReactiveValidationMessages = {}
@Input() userVideoChannels: { id: number, label: string, support: string }[] = [] @Input() userVideoChannels: SelectChannelItem[] = []
@Input() schedulePublicationPossible = true @Input() schedulePublicationPossible = true
@Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = [] @Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = []
@Input() waitTranscodingEnabled = true @Input() waitTranscodingEnabled = true

View File

@ -3,6 +3,7 @@ import { Directive, EventEmitter, OnInit } from '@angular/core'
import { AuthService, CanComponentDeactivateResult, Notifier, ServerService } from '@app/core' import { AuthService, CanComponentDeactivateResult, Notifier, ServerService } from '@app/core'
import { populateAsyncUserVideoChannels } from '@app/helpers' import { populateAsyncUserVideoChannels } from '@app/helpers'
import { FormReactive } from '@app/shared/shared-forms' import { FormReactive } from '@app/shared/shared-forms'
import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
@ -10,7 +11,7 @@ import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
@Directive() @Directive()
// tslint:disable-next-line: directive-class-suffix // tslint:disable-next-line: directive-class-suffix
export abstract class VideoSend extends FormReactive implements OnInit { export abstract class VideoSend extends FormReactive implements OnInit {
userVideoChannels: { id: number, label: string, support: string, avatarPath?: string }[] = [] userVideoChannels: SelectChannelItem[] = []
videoPrivacies: VideoConstant<VideoPrivacy>[] = [] videoPrivacies: VideoConstant<VideoPrivacy>[] = []
videoCaptions: VideoCaptionEdit[] = [] videoCaptions: VideoCaptionEdit[] = []

View File

@ -3,6 +3,7 @@ import { Component, HostListener, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { Notifier } from '@app/core' import { Notifier } from '@app/core'
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { I18n } from '@ngx-translate/i18n-polyfill' import { I18n } from '@ngx-translate/i18n-polyfill'
@ -17,7 +18,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
video: VideoEdit video: VideoEdit
isUpdatingVideo = false isUpdatingVideo = false
userVideoChannels: { id: number, label: string, support: string, avatar?: string }[] = [] userVideoChannels: SelectChannelItem[] = []
schedulePublicationPossible = false schedulePublicationPossible = false
videoCaptions: VideoCaptionEdit[] = [] videoCaptions: VideoCaptionEdit[] = []
waitTranscodingEnabled = true waitTranscodingEnabled = true

View File

@ -49,7 +49,7 @@ export class RestService {
const value = object[name] const value = object[name]
if (value === undefined || value === null) continue if (value === undefined || value === null) continue
if (Array.isArray(value) && value.length !== 0) { if (Array.isArray(value)) {
for (const v of value) params = params.append(name, v) for (const v of value) params = params.append(name, v)
} else { } else {
params = params.append(name, value) params = params.append(name, value)

View File

@ -1,6 +1,7 @@
import { DatePipe } from '@angular/common' import { DatePipe } from '@angular/common'
import { environment } from '../../environments/environment' import { environment } from '../../environments/environment'
import { AuthService } from '../core/auth' import { AuthService } from '../core/auth'
import { SelectChannelItem } from '@app/shared/shared-forms/select-channel.component'
// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript // Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
function getParameterByName (name: string, url: string) { function getParameterByName (name: string, url: string) {
@ -18,7 +19,7 @@ function getParameterByName (name: string, url: string) {
function populateAsyncUserVideoChannels ( function populateAsyncUserVideoChannels (
authService: AuthService, authService: AuthService,
channel: { id: number, label: string, support?: string, avatarPath?: string, recent?: boolean }[] channel: SelectChannelItem[]
) { ) {
return new Promise(res => { return new Promise(res => {
authService.userInformationLoaded authService.userInformationLoaded

View File

@ -1,7 +1,14 @@
import { Component, Input, forwardRef, ViewChild } from '@angular/core' import { Component, forwardRef, Input } from '@angular/core'
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { Actor } from '../shared-main' import { Actor } from '../shared-main'
export type SelectChannelItem = {
id: number
label: string
support: string
avatarPath?: string
}
@Component({ @Component({
selector: 'my-select-channel', selector: 'my-select-channel',
styleUrls: [ './select-shared.component.scss' ], styleUrls: [ './select-shared.component.scss' ],
@ -15,7 +22,7 @@ import { Actor } from '../shared-main'
] ]
}) })
export class SelectChannelComponent implements ControlValueAccessor { export class SelectChannelComponent implements ControlValueAccessor {
@Input() items: { id: number, label: string, support: string, avatarPath?: string }[] = [] @Input() items: SelectChannelItem[] = []
selectedId: number selectedId: number

View File

@ -1,6 +1,6 @@
<ng-select <ng-select
[items]="items" [items]="availableItems"
[(ngModel)]="_items" [(ngModel)]="selectedItems"
(ngModelChange)="onModelChange()" (ngModelChange)="onModelChange()"
i18n-placeholder placeholder="Enter a new tag" i18n-placeholder placeholder="Enter a new tag"
[maxSelectedItems]="5" [maxSelectedItems]="5"

View File

@ -14,14 +14,14 @@ import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'
] ]
}) })
export class SelectTagsComponent implements ControlValueAccessor { export class SelectTagsComponent implements ControlValueAccessor {
@Input() items: string[] = [] @Input() availableItems: string[] = []
@Input() _items: string[] = [] @Input() selectedItems: string[] = []
propagateChange = (_: any) => { /* empty */ } propagateChange = (_: any) => { /* empty */ }
writeValue (items: string[]) { writeValue (items: string[]) {
this._items = items this.selectedItems = items
this.propagateChange(this._items) this.propagateChange(this.selectedItems)
} }
registerOnChange (fn: (_: any) => void) { registerOnChange (fn: (_: any) => void) {
@ -33,6 +33,8 @@ export class SelectTagsComponent implements ControlValueAccessor {
} }
onModelChange () { onModelChange () {
this.propagateChange(this._items) console.log(this.selectedItems)
this.propagateChange(this.selectedItems)
} }
} }

View File

@ -15,8 +15,8 @@ export class AdvancedSearch {
languageOneOf: string languageOneOf: string
tagsOneOf: string tagsOneOf: string[]
tagsAllOf: string tagsAllOf: string[]
durationMin: number // seconds durationMin: number // seconds
durationMax: number // seconds durationMax: number // seconds
@ -37,8 +37,10 @@ export class AdvancedSearch {
categoryOneOf?: string categoryOneOf?: string
licenceOneOf?: string licenceOneOf?: string
languageOneOf?: string languageOneOf?: string
tagsOneOf?: string
tagsAllOf?: string tagsOneOf?: any
tagsAllOf?: any
durationMin?: string durationMin?: string
durationMax?: string durationMax?: string
sort?: string sort?: string
@ -55,8 +57,8 @@ export class AdvancedSearch {
this.categoryOneOf = options.categoryOneOf || undefined this.categoryOneOf = options.categoryOneOf || undefined
this.licenceOneOf = options.licenceOneOf || undefined this.licenceOneOf = options.licenceOneOf || undefined
this.languageOneOf = options.languageOneOf || undefined this.languageOneOf = options.languageOneOf || undefined
this.tagsOneOf = options.tagsOneOf || undefined this.tagsOneOf = this.intoArray(options.tagsOneOf)
this.tagsAllOf = options.tagsAllOf || undefined this.tagsAllOf = this.intoArray(options.tagsAllOf)
this.durationMin = parseInt(options.durationMin, 10) this.durationMin = parseInt(options.durationMin, 10)
this.durationMax = parseInt(options.durationMax, 10) this.durationMax = parseInt(options.durationMax, 10)
@ -69,13 +71,11 @@ export class AdvancedSearch {
} }
containsValues () { containsValues () {
const exceptions = new Set([ 'sort', 'searchTarget' ])
const obj = this.toUrlObject() const obj = this.toUrlObject()
for (const k of Object.keys(obj)) { for (const k of Object.keys(obj)) {
if (this.silentFilters.has(k)) continue if (this.silentFilters.has(k)) continue
if (obj[k] !== undefined && obj[k] !== '') return true if (this.isValidValue(obj[k])) return true
} }
return false return false
@ -127,8 +127,8 @@ export class AdvancedSearch {
categoryOneOf: this.intoArray(this.categoryOneOf), categoryOneOf: this.intoArray(this.categoryOneOf),
licenceOneOf: this.intoArray(this.licenceOneOf), licenceOneOf: this.intoArray(this.licenceOneOf),
languageOneOf: this.intoArray(this.languageOneOf), languageOneOf: this.intoArray(this.languageOneOf),
tagsOneOf: this.intoArray(this.tagsOneOf), tagsOneOf: this.tagsOneOf,
tagsAllOf: this.intoArray(this.tagsAllOf), tagsAllOf: this.tagsAllOf,
durationMin: this.durationMin, durationMin: this.durationMin,
durationMax: this.durationMax, durationMax: this.durationMax,
sort: this.sort, sort: this.sort,
@ -143,12 +143,20 @@ export class AdvancedSearch {
for (const k of Object.keys(obj)) { for (const k of Object.keys(obj)) {
if (this.silentFilters.has(k)) continue if (this.silentFilters.has(k)) continue
if (obj[k] !== undefined && obj[k] !== '') acc++ if (this.isValidValue(obj[k])) acc++
} }
return acc return acc
} }
private isValidValue (val: any) {
if (val === undefined) return false
if (val === '') return false
if (Array.isArray(val) && val.length === 0) return false
return true
}
private intoArray (value: any) { private intoArray (value: any) {
if (!value) return undefined if (!value) return undefined
if (Array.isArray(value)) return value if (Array.isArray(value)) return value