diff options
author | Chocobozzz <me@florianbigard.com> | 2020-05-29 16:16:24 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-06-10 14:02:41 +0200 |
commit | 5fb2e2888ce032c638e4b75d07458642f0833e52 (patch) | |
tree | 8830d873569316889b8134027e9a43b198cca38f /client/src/app/search/search.component.ts | |
parent | 62e7be634bc189f942ae51cb4b080079ab503ff0 (diff) | |
download | PeerTube-5fb2e2888ce032c638e4b75d07458642f0833e52.tar.gz PeerTube-5fb2e2888ce032c638e4b75d07458642f0833e52.tar.zst PeerTube-5fb2e2888ce032c638e4b75d07458642f0833e52.zip |
First implem global search
Diffstat (limited to 'client/src/app/search/search.component.ts')
-rw-r--r-- | client/src/app/search/search.component.ts | 98 |
1 files changed, 69 insertions, 29 deletions
diff --git a/client/src/app/search/search.component.ts b/client/src/app/search/search.component.ts index 075994dd3..d3c0761d7 100644 --- a/client/src/app/search/search.component.ts +++ b/client/src/app/search/search.component.ts | |||
@@ -1,16 +1,18 @@ | |||
1 | import { forkJoin, of, Subscription } from 'rxjs' | ||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | 2 | import { Component, OnDestroy, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { AuthService, Notifier } from '@app/core' | 4 | import { AuthService, Notifier, ServerService } from '@app/core' |
4 | import { forkJoin, of, Subscription } from 'rxjs' | 5 | import { HooksService } from '@app/core/plugins/hooks.service' |
6 | import { AdvancedSearch } from '@app/search/advanced-search.model' | ||
5 | import { SearchService } from '@app/search/search.service' | 7 | import { SearchService } from '@app/search/search.service' |
8 | import { immutableAssign } from '@app/shared/misc/utils' | ||
6 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | 9 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
8 | import { MetaService } from '@ngx-meta/core' | ||
9 | import { AdvancedSearch } from '@app/search/advanced-search.model' | ||
10 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | 10 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' |
11 | import { immutableAssign } from '@app/shared/misc/utils' | ||
12 | import { Video } from '@app/shared/video/video.model' | 11 | import { Video } from '@app/shared/video/video.model' |
13 | import { HooksService } from '@app/core/plugins/hooks.service' | 12 | import { MetaService } from '@ngx-meta/core' |
13 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
14 | import { ServerConfig } from '@shared/models' | ||
15 | import { UserService } from '@app/shared' | ||
14 | 16 | ||
15 | @Component({ | 17 | @Component({ |
16 | selector: 'my-search', | 18 | selector: 'my-search', |
@@ -29,6 +31,9 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
29 | isSearchFilterCollapsed = true | 31 | isSearchFilterCollapsed = true |
30 | currentSearch: string | 32 | currentSearch: string |
31 | 33 | ||
34 | errorMessage: string | ||
35 | serverConfig: ServerConfig | ||
36 | |||
32 | private subActivatedRoute: Subscription | 37 | private subActivatedRoute: Subscription |
33 | private isInitialLoad = false // set to false to show the search filters on first arrival | 38 | private isInitialLoad = false // set to false to show the search filters on first arrival |
34 | private firstSearch = true | 39 | private firstSearch = true |
@@ -43,7 +48,8 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
43 | private notifier: Notifier, | 48 | private notifier: Notifier, |
44 | private searchService: SearchService, | 49 | private searchService: SearchService, |
45 | private authService: AuthService, | 50 | private authService: AuthService, |
46 | private hooks: HooksService | 51 | private hooks: HooksService, |
52 | private serverService: ServerService | ||
47 | ) { } | 53 | ) { } |
48 | 54 | ||
49 | get user () { | 55 | get user () { |
@@ -51,8 +57,11 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
51 | } | 57 | } |
52 | 58 | ||
53 | ngOnInit () { | 59 | ngOnInit () { |
60 | this.serverService.getConfig() | ||
61 | .subscribe(config => this.serverConfig = config) | ||
62 | |||
54 | this.subActivatedRoute = this.route.queryParams.subscribe( | 63 | this.subActivatedRoute = this.route.queryParams.subscribe( |
55 | queryParams => { | 64 | async queryParams => { |
56 | const querySearch = queryParams['search'] | 65 | const querySearch = queryParams['search'] |
57 | 66 | ||
58 | // Search updated, reset filters | 67 | // Search updated, reset filters |
@@ -65,6 +74,9 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
65 | } | 74 | } |
66 | 75 | ||
67 | this.advancedSearch = new AdvancedSearch(queryParams) | 76 | this.advancedSearch = new AdvancedSearch(queryParams) |
77 | if (!this.advancedSearch.searchTarget) { | ||
78 | this.advancedSearch.searchTarget = await this.serverService.getDefaultSearchTarget() | ||
79 | } | ||
68 | 80 | ||
69 | // Don't hide filters if we have some of them AND the user just came on the webpage | 81 | // Don't hide filters if we have some of them AND the user just came on the webpage |
70 | this.isSearchFilterCollapsed = this.isInitialLoad === false || !this.advancedSearch.containsValues() | 82 | this.isSearchFilterCollapsed = this.isInitialLoad === false || !this.advancedSearch.containsValues() |
@@ -99,28 +111,37 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
99 | forkJoin([ | 111 | forkJoin([ |
100 | this.getVideosObs(), | 112 | this.getVideosObs(), |
101 | this.getVideoChannelObs() | 113 | this.getVideoChannelObs() |
102 | ]) | 114 | ]).subscribe( |
103 | .subscribe( | 115 | ([videosResult, videoChannelsResult]) => { |
104 | ([ videosResult, videoChannelsResult ]) => { | 116 | this.results = this.results |
105 | this.results = this.results | 117 | .concat(videoChannelsResult.data) |
106 | .concat(videoChannelsResult.data) | 118 | .concat(videosResult.data) |
107 | .concat(videosResult.data) | 119 | |
108 | this.pagination.totalItems = videosResult.total + videoChannelsResult.total | 120 | this.pagination.totalItems = videosResult.total + videoChannelsResult.total |
109 | |||
110 | // Focus on channels if there are no enough videos | ||
111 | if (this.firstSearch === true && videosResult.data.length < this.pagination.itemsPerPage) { | ||
112 | this.resetPagination() | ||
113 | this.firstSearch = false | ||
114 | |||
115 | this.channelsPerPage = 10 | ||
116 | this.search() | ||
117 | } | ||
118 | 121 | ||
122 | // Focus on channels if there are no enough videos | ||
123 | if (this.firstSearch === true && videosResult.data.length < this.pagination.itemsPerPage) { | ||
124 | this.resetPagination() | ||
119 | this.firstSearch = false | 125 | this.firstSearch = false |
120 | }, | ||
121 | 126 | ||
122 | err => this.notifier.error(err.message) | 127 | this.channelsPerPage = 10 |
123 | ) | 128 | this.search() |
129 | } | ||
130 | |||
131 | this.firstSearch = false | ||
132 | }, | ||
133 | |||
134 | err => { | ||
135 | if (this.advancedSearch.searchTarget !== 'search-index') this.notifier.error(err.message) | ||
136 | |||
137 | this.notifier.error( | ||
138 | this.i18n('Search index is unavailable. Retrying with instance results instead.'), | ||
139 | this.i18n('Search error') | ||
140 | ) | ||
141 | this.advancedSearch.searchTarget = 'local' | ||
142 | this.search() | ||
143 | } | ||
144 | ) | ||
124 | } | 145 | } |
125 | 146 | ||
126 | onNearOfBottom () { | 147 | onNearOfBottom () { |
@@ -146,6 +167,24 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
146 | this.results = this.results.filter(r => !this.isVideo(r) || r.id !== video.id) | 167 | this.results = this.results.filter(r => !this.isVideo(r) || r.id !== video.id) |
147 | } | 168 | } |
148 | 169 | ||
170 | getChannelUrl (channel: VideoChannel) { | ||
171 | if (this.advancedSearch.searchTarget === 'search-index' && channel.url) { | ||
172 | const remoteUriConfig = this.serverConfig.search.remoteUri | ||
173 | |||
174 | // Redirect on the external instance if not allowed to fetch remote data | ||
175 | const externalRedirect = (!this.authService.isLoggedIn() && !remoteUriConfig.anonymous) || !remoteUriConfig.users | ||
176 | const fromPath = window.location.pathname + window.location.search | ||
177 | |||
178 | return [ '/search/lazy-load-channel', { url: channel.url, externalRedirect, fromPath } ] | ||
179 | } | ||
180 | |||
181 | return [ '/video-channels', channel.nameWithHost ] | ||
182 | } | ||
183 | |||
184 | hideActions () { | ||
185 | return this.advancedSearch.searchTarget === 'search-index' | ||
186 | } | ||
187 | |||
149 | private resetPagination () { | 188 | private resetPagination () { |
150 | this.pagination.currentPage = 1 | 189 | this.pagination.currentPage = 1 |
151 | this.pagination.totalItems = null | 190 | this.pagination.totalItems = null |
@@ -189,7 +228,8 @@ export class SearchComponent implements OnInit, OnDestroy { | |||
189 | 228 | ||
190 | const params = { | 229 | const params = { |
191 | search: this.currentSearch, | 230 | search: this.currentSearch, |
192 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.channelsPerPage }) | 231 | componentPagination: immutableAssign(this.pagination, { itemsPerPage: this.channelsPerPage }), |
232 | searchTarget: this.advancedSearch.searchTarget | ||
193 | } | 233 | } |
194 | 234 | ||
195 | return this.hooks.wrapObsFun( | 235 | return this.hooks.wrapObsFun( |