diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2021-01-19 13:43:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-19 13:43:33 +0100 |
commit | 370240824e2fb28b314255f6c23f5ea7d6b08625 (patch) | |
tree | 6d4350fd93ea0b960bd278a948cecbdfbd2b67d7 /client/src/app/shared/shared-main | |
parent | 2264c1ceedcf27998108b8f8b706e51ed910d4fb (diff) | |
download | PeerTube-370240824e2fb28b314255f6c23f5ea7d6b08625.tar.gz PeerTube-370240824e2fb28b314255f6c23f5ea7d6b08625.tar.zst PeerTube-370240824e2fb28b314255f6c23f5ea7d6b08625.zip |
Allow users/visitors to search through an account's videos (#3589)
* WIP: account search
* add search to account view
* add tests for account search
Diffstat (limited to 'client/src/app/shared/shared-main')
6 files changed, 107 insertions, 2 deletions
diff --git a/client/src/app/shared/shared-main/misc/index.ts b/client/src/app/shared/shared-main/misc/index.ts index e806fd2f2..dc8ef9754 100644 --- a/client/src/app/shared/shared-main/misc/index.ts +++ b/client/src/app/shared/shared-main/misc/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './help.component' | 1 | export * from './help.component' |
2 | export * from './list-overflow.component' | 2 | export * from './list-overflow.component' |
3 | export * from './top-menu-dropdown.component' | 3 | export * from './top-menu-dropdown.component' |
4 | export * from './simple-search-input.component' | ||
diff --git a/client/src/app/shared/shared-main/misc/simple-search-input.component.html b/client/src/app/shared/shared-main/misc/simple-search-input.component.html new file mode 100644 index 000000000..fb0d97122 --- /dev/null +++ b/client/src/app/shared/shared-main/misc/simple-search-input.component.html | |||
@@ -0,0 +1,14 @@ | |||
1 | <span> | ||
2 | <my-global-icon iconName="search" aria-label="Search" role="button" (click)="showInput()"></my-global-icon> | ||
3 | |||
4 | <input | ||
5 | #ref | ||
6 | type="text" | ||
7 | [(ngModel)]="value" | ||
8 | (focusout)="focusLost()" | ||
9 | (keyup.enter)="searchChange()" | ||
10 | [hidden]="!shown" | ||
11 | [name]="name" | ||
12 | [placeholder]="placeholder" | ||
13 | > | ||
14 | </span> | ||
diff --git a/client/src/app/shared/shared-main/misc/simple-search-input.component.scss b/client/src/app/shared/shared-main/misc/simple-search-input.component.scss new file mode 100644 index 000000000..591b04fb2 --- /dev/null +++ b/client/src/app/shared/shared-main/misc/simple-search-input.component.scss | |||
@@ -0,0 +1,29 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | span { | ||
5 | opacity: .6; | ||
6 | |||
7 | &:focus-within { | ||
8 | opacity: 1; | ||
9 | } | ||
10 | } | ||
11 | |||
12 | my-global-icon { | ||
13 | height: 18px; | ||
14 | position: relative; | ||
15 | top: -2px; | ||
16 | } | ||
17 | |||
18 | input { | ||
19 | @include peertube-input-text(150px); | ||
20 | |||
21 | height: 22px; // maximum height for the account/video-channels links | ||
22 | padding-left: 10px; | ||
23 | background-color: transparent; | ||
24 | border: none; | ||
25 | |||
26 | &::placeholder { | ||
27 | font-size: 15px; | ||
28 | } | ||
29 | } | ||
diff --git a/client/src/app/shared/shared-main/misc/simple-search-input.component.ts b/client/src/app/shared/shared-main/misc/simple-search-input.component.ts new file mode 100644 index 000000000..86ae9ab42 --- /dev/null +++ b/client/src/app/shared/shared-main/misc/simple-search-input.component.ts | |||
@@ -0,0 +1,54 @@ | |||
1 | import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | ||
3 | import { Subject } from 'rxjs' | ||
4 | import { debounceTime, distinctUntilChanged } from 'rxjs/operators' | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'simple-search-input', | ||
8 | templateUrl: './simple-search-input.component.html', | ||
9 | styleUrls: [ './simple-search-input.component.scss' ] | ||
10 | }) | ||
11 | export class SimpleSearchInputComponent implements OnInit { | ||
12 | @ViewChild('ref') input: ElementRef | ||
13 | |||
14 | @Input() name = 'search' | ||
15 | @Input() placeholder = $localize`Search` | ||
16 | |||
17 | @Output() searchChanged = new EventEmitter<string>() | ||
18 | |||
19 | value = '' | ||
20 | shown: boolean | ||
21 | |||
22 | private searchSubject = new Subject<string>() | ||
23 | |||
24 | constructor ( | ||
25 | private router: Router, | ||
26 | private route: ActivatedRoute | ||
27 | ) {} | ||
28 | |||
29 | ngOnInit () { | ||
30 | this.searchSubject | ||
31 | .pipe( | ||
32 | debounceTime(400), | ||
33 | distinctUntilChanged() | ||
34 | ) | ||
35 | .subscribe(value => this.searchChanged.emit(value)) | ||
36 | |||
37 | this.searchSubject.next(this.value) | ||
38 | } | ||
39 | |||
40 | showInput () { | ||
41 | this.shown = true | ||
42 | setTimeout(() => this.input.nativeElement.focus()) | ||
43 | } | ||
44 | |||
45 | focusLost () { | ||
46 | if (this.value !== '') return | ||
47 | this.shown = false | ||
48 | } | ||
49 | |||
50 | searchChange () { | ||
51 | this.router.navigate(['./search'], { relativeTo: this.route }) | ||
52 | this.searchSubject.next(this.value) | ||
53 | } | ||
54 | } | ||
diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts index 123b5a3e3..c69a4c8b2 100644 --- a/client/src/app/shared/shared-main/shared-main.module.ts +++ b/client/src/app/shared/shared-main/shared-main.module.ts | |||
@@ -30,7 +30,7 @@ import { ActionDropdownComponent, ButtonComponent, DeleteButtonComponent, EditBu | |||
30 | import { DateToggleComponent } from './date' | 30 | import { DateToggleComponent } from './date' |
31 | import { FeedComponent } from './feeds' | 31 | import { FeedComponent } from './feeds' |
32 | import { LoaderComponent, SmallLoaderComponent } from './loaders' | 32 | import { LoaderComponent, SmallLoaderComponent } from './loaders' |
33 | import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent } from './misc' | 33 | import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent, SimpleSearchInputComponent } from './misc' |
34 | import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users' | 34 | import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users' |
35 | import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' | 35 | import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' |
36 | import { VideoCaptionService } from './video-caption' | 36 | import { VideoCaptionService } from './video-caption' |
@@ -88,6 +88,7 @@ import { VideoChannelService } from './video-channel' | |||
88 | HelpComponent, | 88 | HelpComponent, |
89 | ListOverflowComponent, | 89 | ListOverflowComponent, |
90 | TopMenuDropdownComponent, | 90 | TopMenuDropdownComponent, |
91 | SimpleSearchInputComponent, | ||
91 | 92 | ||
92 | UserQuotaComponent, | 93 | UserQuotaComponent, |
93 | UserNotificationsComponent | 94 | UserNotificationsComponent |
@@ -140,6 +141,7 @@ import { VideoChannelService } from './video-channel' | |||
140 | HelpComponent, | 141 | HelpComponent, |
141 | ListOverflowComponent, | 142 | ListOverflowComponent, |
142 | TopMenuDropdownComponent, | 143 | TopMenuDropdownComponent, |
144 | SimpleSearchInputComponent, | ||
143 | 145 | ||
144 | UserQuotaComponent, | 146 | UserQuotaComponent, |
145 | UserNotificationsComponent | 147 | UserNotificationsComponent |
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts index 59860c5cb..0b708b692 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts | |||
@@ -140,8 +140,9 @@ export class VideoService implements VideosProvider { | |||
140 | sort: VideoSortField | 140 | sort: VideoSortField |
141 | nsfwPolicy?: NSFWPolicyType | 141 | nsfwPolicy?: NSFWPolicyType |
142 | videoFilter?: VideoFilter | 142 | videoFilter?: VideoFilter |
143 | search?: string | ||
143 | }): Observable<ResultList<Video>> { | 144 | }): Observable<ResultList<Video>> { |
144 | const { account, videoPagination, sort, videoFilter, nsfwPolicy } = parameters | 145 | const { account, videoPagination, sort, videoFilter, nsfwPolicy, search } = parameters |
145 | 146 | ||
146 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) | 147 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) |
147 | 148 | ||
@@ -156,6 +157,10 @@ export class VideoService implements VideosProvider { | |||
156 | params = params.set('filter', videoFilter) | 157 | params = params.set('filter', videoFilter) |
157 | } | 158 | } |
158 | 159 | ||
160 | if (search) { | ||
161 | params = params.set('search', search) | ||
162 | } | ||
163 | |||
159 | return this.authHttp | 164 | return this.authHttp |
160 | .get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params }) | 165 | .get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params }) |
161 | .pipe( | 166 | .pipe( |