Fix tags in search filters
This commit is contained in:
parent
02c01341f4
commit
9abd170dec
|
@ -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'] }}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()">
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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[] = []
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue