From bf64ed4196938ba9002c887cadb01bd2a6e3127a Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Sat, 28 Dec 2019 01:10:26 +0100 Subject: [PATCH] Add search bars for a user's videos and playlist library --- .../my-account-video-playlists.component.html | 2 ++ .../my-account-video-playlists.component.scss | 7 ++++++ .../my-account-video-playlists.component.ts | 18 +++++++++++-- .../my-account-videos.component.html | 4 +++ .../my-account-videos.component.scss | 11 ++++++++ .../my-account-videos.component.ts | 25 +++++++++++++++---- client/src/app/shared/users/user.service.ts | 2 +- .../video-add-to-playlist.component.html | 2 +- .../app/shared/video/abstract-video-list.ts | 2 +- .../video/video-miniature.component.scss | 3 ++- client/src/app/shared/video/video.service.ts | 5 ++-- .../comment/video-comments.component.scss | 1 + client/src/sass/primeng-custom.scss | 6 +++++ server/controllers/api/users/me.ts | 3 ++- server/models/video/video.ts | 24 +++++++++++++++--- 15 files changed, 98 insertions(+), 17 deletions(-) diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.html b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.html index 307884c70..878772359 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.html +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.html @@ -1,4 +1,6 @@
+ + Create a new playlist diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.scss b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.scss index d5635417d..4fb4ed4be 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.scss +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.scss @@ -29,12 +29,19 @@ .video-playlist-buttons { min-width: 190px; + height: max-content; } } .video-playlists-header { + display: flex; + justify-content: space-between; text-align: right; margin: 20px 0 50px; + + input[type=text] { + @include peertube-input-text(300px); + } } @media screen and (max-width: 800px) { diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts index 76b13fe2b..42e4782eb 100644 --- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts +++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlists.component.ts @@ -3,7 +3,7 @@ import { Notifier } from '@app/core' import { AuthService } from '../../core/auth' import { ConfirmService } from '../../core/confirm' import { User } from '@app/shared' -import { flatMap } from 'rxjs/operators' +import { flatMap, debounceTime } from 'rxjs/operators' import { I18n } from '@ngx-translate/i18n-polyfill' import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' import { ComponentPagination } from '@app/shared/rest/component-pagination.model' @@ -17,7 +17,9 @@ import { Subject } from 'rxjs' styleUrls: [ './my-account-video-playlists.component.scss' ] }) export class MyAccountVideoPlaylistsComponent implements OnInit { + videoPlaylistsSearch: string videoPlaylists: VideoPlaylist[] = [] + videoPlaylistSearchChanged = new Subject() pagination: ComponentPagination = { currentPage: 1, @@ -41,6 +43,13 @@ export class MyAccountVideoPlaylistsComponent implements OnInit { this.user = this.authService.getUser() this.loadVideoPlaylists() + + this.videoPlaylistSearchChanged + .pipe( + debounceTime(500)) + .subscribe(() => { + this.loadVideoPlaylists() + }) } async deleteVideoPlaylist (videoPlaylist: VideoPlaylist) { @@ -80,12 +89,17 @@ export class MyAccountVideoPlaylistsComponent implements OnInit { this.loadVideoPlaylists() } + onVideoPlaylistSearchChanged () { + this.videoPlaylistSearchChanged.next() + } + private loadVideoPlaylists () { this.authService.userInformationLoaded .pipe(flatMap(() => { - return this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt') + return this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt', this.videoPlaylistsSearch) })) .subscribe(res => { + this.videoPlaylists = [] this.videoPlaylists = this.videoPlaylists.concat(res.data) this.pagination.totalItems = res.total diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html index 2854093c4..a898cd938 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html @@ -1,3 +1,7 @@ +
+ +
+ () getVideosObservableFunction = this.getVideosObservable.bind(this) constructor ( @@ -59,6 +61,19 @@ export class MyAccountVideosComponent implements DisableForReuseHook { this.titlePage = this.i18n('My videos') } + ngOnInit () { + this.videosSearchChanged + .pipe( + debounceTime(500)) + .subscribe(() => { + this.videosSelection.reloadVideos() + }) + } + + onVideosSearchChanged () { + this.videosSearchChanged.next() + } + disableForReuse () { this.videosSelection.disableForReuse() } @@ -70,7 +85,7 @@ export class MyAccountVideosComponent implements DisableForReuseHook { getVideosObservable (page: number, sort: VideoSortField) { const newPagination = immutableAssign(this.pagination, { currentPage: page }) - return this.videoService.getMyVideos(newPagination, sort) + return this.videoService.getMyVideos(newPagination, sort, this.videosSearch) } async deleteSelectedVideos () { diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts index 41ee87197..051e0bfa4 100644 --- a/client/src/app/shared/users/user.service.ts +++ b/client/src/app/shared/users/user.service.ts @@ -88,7 +88,7 @@ export class UserService { } getMyVideoQuotaUsed () { - const url = UserService.BASE_USERS_URL + '/me/video-quota-used' + const url = UserService.BASE_USERS_URL + 'me/video-quota-used' return this.authHttp.get(url) .pipe(catchError(err => this.restExtractor.handleError(err))) diff --git a/client/src/app/shared/video-playlist/video-add-to-playlist.component.html b/client/src/app/shared/video-playlist/video-add-to-playlist.component.html index ba30953b9..6e0989227 100644 --- a/client/src/app/shared/video-playlist/video-add-to-playlist.component.html +++ b/client/src/app/shared/video-playlist/video-add-to-playlist.component.html @@ -42,7 +42,7 @@
- +
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index a2a12bec7..746359851 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -150,6 +150,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor this.getVideosObservable(this.pagination.currentPage).subscribe( ({ data, total }) => { this.pagination.totalItems = total + this.videos = [] this.videos = this.videos.concat(data) if (this.groupByDate) this.buildGroupedDateLabels() @@ -170,7 +171,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor reloadVideos () { this.pagination.currentPage = 1 - this.videos = [] this.loadMoreVideos() } diff --git a/client/src/app/shared/video/video-miniature.component.scss b/client/src/app/shared/video/video-miniature.component.scss index 3988cc055..ac83c5dfa 100644 --- a/client/src/app/shared/video/video-miniature.component.scss +++ b/client/src/app/shared/video/video-miniature.component.scss @@ -100,7 +100,8 @@ $more-margin-right: 15px; flex-direction: row; margin-bottom: 0; height: auto; - width: 100%; + display: flex; + flex-grow: 1; my-video-thumbnail { margin-right: 10px; diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index 9adf46495..2dd47d74e 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -121,14 +121,15 @@ export class VideoService implements VideosProvider { .pipe(catchError(err => this.restExtractor.handleError(err))) } - getMyVideos (videoPagination: ComponentPagination, sort: VideoSortField): Observable> { + getMyVideos (videoPagination: ComponentPagination, sort: VideoSortField, search?: string): Observable> { const pagination = this.restService.componentPaginationToRestPagination(videoPagination) let params = new HttpParams() params = this.restService.addRestGetParams(params, pagination, sort) + params = this.restService.addObjectParams(params, { search }) return this.authHttp - .get>(UserService.BASE_USERS_URL + '/me/videos', { params }) + .get>(UserService.BASE_USERS_URL + 'me/videos', { params }) .pipe( switchMap(res => this.extractVideos(res)), catchError(err => this.restExtractor.handleError(err)) diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.scss b/client/src/app/videos/+video-watch/comment/video-comments.component.scss index 9e3682295..c02f6c21b 100644 --- a/client/src/app/videos/+video-watch/comment/video-comments.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comments.component.scss @@ -27,6 +27,7 @@ font-weight: 600; text-transform: uppercase; border: none; + transform: translateY(-7%); } my-feed { diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss index 0acffef3c..9398f0adc 100644 --- a/client/src/sass/primeng-custom.scss +++ b/client/src/sass/primeng-custom.scss @@ -10,6 +10,12 @@ color: var(--mainForegroundColor) !important; } +my-edit-button, +my-delete-button, +my-button { + height: max-content; +} + // data table customizations p-table { .ui-table-caption { diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index ba976ab03..b1f29f252 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -99,7 +99,8 @@ async function getUserVideos (req: express.Request, res: express.Response) { user.Account.id, req.query.start as number, req.query.count as number, - req.query.sort as VideoSortField + req.query.sort as VideoSortField, + req.query.search as string ) const additionalAttributes = { diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 164122ee2..1f3c25ecb 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -1196,9 +1196,15 @@ export class VideoModel extends Model { }) } - static listUserVideosForApi (accountId: number, start: number, count: number, sort: string) { + static listUserVideosForApi ( + accountId: number, + start: number, + count: number, + sort: string, + search?: string + ) { function buildBaseQuery (): FindOptions { - return { + let baseQuery = { offset: start, limit: count, order: getVideoSort(sort), @@ -1218,12 +1224,24 @@ export class VideoModel extends Model { } ] } + + if (search) { + baseQuery = Object.assign(baseQuery, { + where: { + name: { + [ Op.iLike ]: '%' + search + '%' + } + } + }) + } + + return baseQuery } const countQuery = buildBaseQuery() const findQuery = buildBaseQuery() - const findScopes = [ + const findScopes: (string | ScopeOptions)[] = [ ScopeNames.WITH_SCHEDULED_UPDATE, ScopeNames.WITH_BLACKLISTED, ScopeNames.WITH_THUMBNAILS -- 2.41.0