diff options
author | Chocobozzz <me@florianbigard.com> | 2021-12-10 11:02:42 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-12-10 11:02:42 +0100 |
commit | 8cf43a6524d354fbfa0f0eaf789e8d4756bd25d6 (patch) | |
tree | 3f33a5e36a89eedf7e4ebfa4d08336262e9604c2 /client/src/app | |
parent | 90701ec1d8d27d0072d6b0d2b19362d471484f9a (diff) | |
download | PeerTube-8cf43a6524d354fbfa0f0eaf789e8d4756bd25d6.tar.gz PeerTube-8cf43a6524d354fbfa0f0eaf789e8d4756bd25d6.tar.zst PeerTube-8cf43a6524d354fbfa0f0eaf789e8d4756bd25d6.zip |
Add filter on search results
Diffstat (limited to 'client/src/app')
5 files changed, 82 insertions, 22 deletions
diff --git a/client/src/app/+search/search-filters.component.html b/client/src/app/+search/search-filters.component.html index 4b87a2102..c4861e8c4 100644 --- a/client/src/app/+search/search-filters.component.html +++ b/client/src/app/+search/search-filters.component.html | |||
@@ -182,6 +182,31 @@ | |||
182 | > | 182 | > |
183 | </div> | 183 | </div> |
184 | 184 | ||
185 | <div class="form-group"> | ||
186 | <div class="radio-label label-container"> | ||
187 | <label i18n>Result types</label> | ||
188 | <button i18n class="reset-button reset-button-small" (click)="resetField('resultType')" *ngIf="advancedSearch.resultType !== undefined"> | ||
189 | Reset | ||
190 | </button> | ||
191 | </div> | ||
192 | |||
193 | <div class="peertube-radio-container"> | ||
194 | <input type="radio" name="resultType" id="resultTypeVideos" value="videos" [(ngModel)]="advancedSearch.resultType"> | ||
195 | <label i18n for="resultTypeVideos" class="radio">Videos</label> | ||
196 | </div> | ||
197 | |||
198 | <div class="peertube-radio-container"> | ||
199 | <input type="radio" name="resultType" id="resultTypeChannels" value="channels" [(ngModel)]="advancedSearch.resultType"> | ||
200 | <label i18n for="resultTypeChannels" class="radio">Channels</label> | ||
201 | </div> | ||
202 | |||
203 | <div class="peertube-radio-container"> | ||
204 | <input type="radio" name="resultType" id="resultTypePlaylists" value="playlists" [(ngModel)]="advancedSearch.resultType"> | ||
205 | <label i18n for="resultTypePlaylists" class="radio">Playlists</label> | ||
206 | </div> | ||
207 | |||
208 | </div> | ||
209 | |||
185 | <div class="form-group" *ngIf="isSearchTargetEnabled()"> | 210 | <div class="form-group" *ngIf="isSearchTargetEnabled()"> |
186 | <div class="radio-label label-container"> | 211 | <div class="radio-label label-container"> |
187 | <label i18n>Search target</label> | 212 | <label i18n>Search target</label> |
diff --git a/client/src/app/+search/search-filters.component.ts b/client/src/app/+search/search-filters.component.ts index 5972ba553..aaa4ecc5a 100644 --- a/client/src/app/+search/search-filters.component.ts +++ b/client/src/app/+search/search-filters.component.ts | |||
@@ -22,7 +22,6 @@ export class SearchFiltersComponent implements OnInit { | |||
22 | publishedDateRanges: FormOption[] = [] | 22 | publishedDateRanges: FormOption[] = [] |
23 | sorts: FormOption[] = [] | 23 | sorts: FormOption[] = [] |
24 | durationRanges: FormOption[] = [] | 24 | durationRanges: FormOption[] = [] |
25 | videoType: FormOption[] = [] | ||
26 | 25 | ||
27 | publishedDateRange: string | 26 | publishedDateRange: string |
28 | durationRange: string | 27 | durationRange: string |
@@ -54,17 +53,6 @@ export class SearchFiltersComponent implements OnInit { | |||
54 | } | 53 | } |
55 | ] | 54 | ] |
56 | 55 | ||
57 | this.videoType = [ | ||
58 | { | ||
59 | id: 'vod', | ||
60 | label: $localize`VOD videos` | ||
61 | }, | ||
62 | { | ||
63 | id: 'live', | ||
64 | label: $localize`Live videos` | ||
65 | } | ||
66 | ] | ||
67 | |||
68 | this.durationRanges = [ | 56 | this.durationRanges = [ |
69 | { | 57 | { |
70 | id: 'short', | 58 | id: 'short', |
diff --git a/client/src/app/+search/search.component.ts b/client/src/app/+search/search.component.ts index fcf6ebbec..b9ec6dbcc 100644 --- a/client/src/app/+search/search.component.ts +++ b/client/src/app/+search/search.component.ts | |||
@@ -47,10 +47,6 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
47 | private subActivatedRoute: Subscription | 47 | private subActivatedRoute: Subscription |
48 | private isInitialLoad = false // set to false to show the search filters on first arrival | 48 | private isInitialLoad = false // set to false to show the search filters on first arrival |
49 | 49 | ||
50 | private channelsPerPage = 2 | ||
51 | private playlistsPerPage = 2 | ||
52 | private videosPerPage = 10 | ||
53 | |||
54 | private hasMoreResults = true | 50 | private hasMoreResults = true |
55 | private isSearching = false | 51 | private isSearching = false |
56 | 52 | ||
@@ -247,7 +243,6 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
247 | private resetPagination () { | 243 | private resetPagination () { |
248 | this.pagination.currentPage = 1 | 244 | this.pagination.currentPage = 1 |
249 | this.pagination.totalItems = null | 245 | this.pagination.totalItems = null |
250 | this.channelsPerPage = 2 | ||
251 | 246 | ||
252 | this.results = [] | 247 | this.results = [] |
253 | } | 248 | } |
@@ -272,7 +267,7 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
272 | private getVideosObs () { | 267 | private getVideosObs () { |
273 | const params = { | 268 | const params = { |
274 | search: this.currentSearch, | 269 | search: this.currentSearch, |
275 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.videosPerPage }), | 270 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: 10 }), |
276 | advancedSearch: this.advancedSearch | 271 | advancedSearch: this.advancedSearch |
277 | } | 272 | } |
278 | 273 | ||
@@ -288,7 +283,7 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
288 | private getVideoChannelObs () { | 283 | private getVideoChannelObs () { |
289 | const params = { | 284 | const params = { |
290 | search: this.currentSearch, | 285 | search: this.currentSearch, |
291 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.channelsPerPage }), | 286 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.buildChannelsPerPage() }), |
292 | advancedSearch: this.advancedSearch | 287 | advancedSearch: this.advancedSearch |
293 | } | 288 | } |
294 | 289 | ||
@@ -304,7 +299,7 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
304 | private getVideoPlaylistObs () { | 299 | private getVideoPlaylistObs () { |
305 | const params = { | 300 | const params = { |
306 | search: this.currentSearch, | 301 | search: this.currentSearch, |
307 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.playlistsPerPage }), | 302 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.buildPlaylistsPerPage() }), |
308 | advancedSearch: this.advancedSearch | 303 | advancedSearch: this.advancedSearch |
309 | } | 304 | } |
310 | 305 | ||
@@ -334,4 +329,16 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
334 | 329 | ||
335 | return undefined | 330 | return undefined |
336 | } | 331 | } |
332 | |||
333 | private buildChannelsPerPage () { | ||
334 | if (this.advancedSearch.resultType === 'channels') return 10 | ||
335 | |||
336 | return 2 | ||
337 | } | ||
338 | |||
339 | private buildPlaylistsPerPage () { | ||
340 | if (this.advancedSearch.resultType === 'playlists') return 10 | ||
341 | |||
342 | return 2 | ||
343 | } | ||
337 | } | 344 | } |
diff --git a/client/src/app/shared/shared-search/advanced-search.model.ts b/client/src/app/shared/shared-search/advanced-search.model.ts index 2675c6135..724c4d834 100644 --- a/client/src/app/shared/shared-search/advanced-search.model.ts +++ b/client/src/app/shared/shared-search/advanced-search.model.ts | |||
@@ -8,6 +8,8 @@ import { | |||
8 | VideosSearchQuery | 8 | VideosSearchQuery |
9 | } from '@shared/models' | 9 | } from '@shared/models' |
10 | 10 | ||
11 | export type AdvancedSearchResultType = 'videos' | 'playlists' | 'channels' | ||
12 | |||
11 | export class AdvancedSearch { | 13 | export class AdvancedSearch { |
12 | startDate: string // ISO 8601 | 14 | startDate: string // ISO 8601 |
13 | endDate: string // ISO 8601 | 15 | endDate: string // ISO 8601 |
@@ -36,6 +38,7 @@ export class AdvancedSearch { | |||
36 | sort: string | 38 | sort: string |
37 | 39 | ||
38 | searchTarget: SearchTargetType | 40 | searchTarget: SearchTargetType |
41 | resultType: AdvancedSearchResultType | ||
39 | 42 | ||
40 | // Filters we don't want to count, because they are mandatory | 43 | // Filters we don't want to count, because they are mandatory |
41 | private silentFilters = new Set([ 'sort', 'searchTarget' ]) | 44 | private silentFilters = new Set([ 'sort', 'searchTarget' ]) |
@@ -61,6 +64,7 @@ export class AdvancedSearch { | |||
61 | durationMax?: string | 64 | durationMax?: string |
62 | sort?: string | 65 | sort?: string |
63 | searchTarget?: SearchTargetType | 66 | searchTarget?: SearchTargetType |
67 | resultType?: AdvancedSearchResultType | ||
64 | }) { | 68 | }) { |
65 | if (!options) return | 69 | if (!options) return |
66 | 70 | ||
@@ -84,6 +88,12 @@ export class AdvancedSearch { | |||
84 | 88 | ||
85 | this.searchTarget = options.searchTarget || undefined | 89 | this.searchTarget = options.searchTarget || undefined |
86 | 90 | ||
91 | this.resultType = options.resultType || undefined | ||
92 | |||
93 | if (!this.resultType && this.hasVideoFilter()) { | ||
94 | this.resultType = 'videos' | ||
95 | } | ||
96 | |||
87 | if (isNaN(this.durationMin)) this.durationMin = undefined | 97 | if (isNaN(this.durationMin)) this.durationMin = undefined |
88 | if (isNaN(this.durationMax)) this.durationMax = undefined | 98 | if (isNaN(this.durationMax)) this.durationMax = undefined |
89 | 99 | ||
@@ -137,7 +147,8 @@ export class AdvancedSearch { | |||
137 | isLive: this.isLive, | 147 | isLive: this.isLive, |
138 | host: this.host, | 148 | host: this.host, |
139 | sort: this.sort, | 149 | sort: this.sort, |
140 | searchTarget: this.searchTarget | 150 | searchTarget: this.searchTarget, |
151 | resultType: this.resultType | ||
141 | } | 152 | } |
142 | } | 153 | } |
143 | 154 | ||
@@ -199,4 +210,21 @@ export class AdvancedSearch { | |||
199 | 210 | ||
200 | return true | 211 | return true |
201 | } | 212 | } |
213 | |||
214 | private hasVideoFilter () { | ||
215 | return this.startDate !== undefined || | ||
216 | this.endDate !== undefined || | ||
217 | this.originallyPublishedStartDate !== undefined || | ||
218 | this.originallyPublishedEndDate !== undefined || | ||
219 | this.nsfw !== undefined !== undefined || | ||
220 | this.categoryOneOf !== undefined || | ||
221 | this.licenceOneOf !== undefined || | ||
222 | this.languageOneOf !== undefined || | ||
223 | this.tagsOneOf !== undefined || | ||
224 | this.tagsAllOf !== undefined || | ||
225 | this.durationMin !== undefined || | ||
226 | this.durationMax !== undefined || | ||
227 | this.host !== undefined || | ||
228 | this.isLive !== undefined | ||
229 | } | ||
202 | } | 230 | } |
diff --git a/client/src/app/shared/shared-search/search.service.ts b/client/src/app/shared/shared-search/search.service.ts index 71350c733..415bf083c 100644 --- a/client/src/app/shared/shared-search/search.service.ts +++ b/client/src/app/shared/shared-search/search.service.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Observable } from 'rxjs' | 1 | import { Observable, of } from 'rxjs' |
2 | import { catchError, map, switchMap } from 'rxjs/operators' | 2 | import { catchError, map, switchMap } from 'rxjs/operators' |
3 | import { HttpClient, HttpParams } from '@angular/common/http' | 3 | import { HttpClient, HttpParams } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 4 | import { Injectable } from '@angular/core' |
@@ -39,6 +39,10 @@ export class SearchService { | |||
39 | }): Observable<ResultList<Video>> { | 39 | }): Observable<ResultList<Video>> { |
40 | const { search, uuids, componentPagination, advancedSearch } = parameters | 40 | const { search, uuids, componentPagination, advancedSearch } = parameters |
41 | 41 | ||
42 | if (advancedSearch.resultType !== undefined && advancedSearch.resultType !== 'videos') { | ||
43 | return of({ total: 0, data: [] }) | ||
44 | } | ||
45 | |||
42 | const url = SearchService.BASE_SEARCH_URL + 'videos' | 46 | const url = SearchService.BASE_SEARCH_URL + 'videos' |
43 | let pagination: RestPagination | 47 | let pagination: RestPagination |
44 | 48 | ||
@@ -73,6 +77,10 @@ export class SearchService { | |||
73 | }): Observable<ResultList<VideoChannel>> { | 77 | }): Observable<ResultList<VideoChannel>> { |
74 | const { search, advancedSearch, componentPagination, handles } = parameters | 78 | const { search, advancedSearch, componentPagination, handles } = parameters |
75 | 79 | ||
80 | if (advancedSearch.resultType !== undefined && advancedSearch.resultType !== 'channels') { | ||
81 | return of({ total: 0, data: [] }) | ||
82 | } | ||
83 | |||
76 | const url = SearchService.BASE_SEARCH_URL + 'video-channels' | 84 | const url = SearchService.BASE_SEARCH_URL + 'video-channels' |
77 | 85 | ||
78 | let pagination: RestPagination | 86 | let pagination: RestPagination |
@@ -107,6 +115,10 @@ export class SearchService { | |||
107 | }): Observable<ResultList<VideoPlaylist>> { | 115 | }): Observable<ResultList<VideoPlaylist>> { |
108 | const { search, advancedSearch, componentPagination, uuids } = parameters | 116 | const { search, advancedSearch, componentPagination, uuids } = parameters |
109 | 117 | ||
118 | if (advancedSearch.resultType !== undefined && advancedSearch.resultType !== 'playlists') { | ||
119 | return of({ total: 0, data: [] }) | ||
120 | } | ||
121 | |||
110 | const url = SearchService.BASE_SEARCH_URL + 'video-playlists' | 122 | const url = SearchService.BASE_SEARCH_URL + 'video-playlists' |
111 | 123 | ||
112 | let pagination: RestPagination | 124 | let pagination: RestPagination |