aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRigel Kent <sendmemail@rigelk.eu>2019-12-27 17:02:34 +0100
committerRigel Kent <sendmemail@rigelk.eu>2019-12-27 17:02:44 +0100
commitc1125bcadc1fa129856e56dc62f4c472cffa736a (patch)
treee6873bf7a306bfe809809f099d2d465dae3407b0
parent6f79be110d31f4f751b989fe36b9de0d0f259fe0 (diff)
downloadPeerTube-c1125bcadc1fa129856e56dc62f4c472cffa736a.tar.gz
PeerTube-c1125bcadc1fa129856e56dc62f4c472cffa736a.tar.zst
PeerTube-c1125bcadc1fa129856e56dc62f4c472cffa736a.zip
Add comment filtering by reply count
-rw-r--r--client/src/app/shared/video/sort-field.type.ts3
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.service.ts4
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.html10
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.scss6
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.ts11
-rw-r--r--server/initializers/constants.ts2
-rw-r--r--server/models/utils.ts14
-rw-r--r--server/models/video/video-comment.ts4
8 files changed, 47 insertions, 7 deletions
diff --git a/client/src/app/shared/video/sort-field.type.ts b/client/src/app/shared/video/sort-field.type.ts
index d1088d244..65b24d946 100644
--- a/client/src/app/shared/video/sort-field.type.ts
+++ b/client/src/app/shared/video/sort-field.type.ts
@@ -5,3 +5,6 @@ export type VideoSortField = 'name' | '-name'
5 | 'views' | '-views' 5 | 'views' | '-views'
6 | 'likes' | '-likes' 6 | 'likes' | '-likes'
7 | 'trending' | '-trending' 7 | 'trending' | '-trending'
8
9export type CommentSortField = 'createdAt' | '-createdAt'
10 | 'totalReplies' | '-totalReplies'
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.service.ts b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
index 550d42fa8..72fbf5d25 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.service.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
@@ -12,7 +12,7 @@ import {
12import { environment } from '../../../../environments/environment' 12import { environment } from '../../../../environments/environment'
13import { RestExtractor, RestService } from '../../../shared/rest' 13import { RestExtractor, RestService } from '../../../shared/rest'
14import { ComponentPagination } from '../../../shared/rest/component-pagination.model' 14import { ComponentPagination } from '../../../shared/rest/component-pagination.model'
15import { VideoSortField } from '../../../shared/video/sort-field.type' 15import { CommentSortField } from '../../../shared/video/sort-field.type'
16import { VideoComment } from './video-comment.model' 16import { VideoComment } from './video-comment.model'
17 17
18@Injectable() 18@Injectable()
@@ -51,7 +51,7 @@ export class VideoCommentService {
51 getVideoCommentThreads (parameters: { 51 getVideoCommentThreads (parameters: {
52 videoId: number | string, 52 videoId: number | string,
53 componentPagination: ComponentPagination, 53 componentPagination: ComponentPagination,
54 sort: VideoSortField 54 sort: CommentSortField
55 }): Observable<ResultList<VideoComment>> { 55 }): Observable<ResultList<VideoComment>> {
56 const { videoId, componentPagination, sort } = parameters 56 const { videoId, componentPagination, sort } = parameters
57 57
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.html b/client/src/app/videos/+video-watch/comment/video-comments.component.html
index 5fabb7dfe..e284eab0a 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.html
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.html
@@ -10,6 +10,16 @@
10 </div> 10 </div>
11 11
12 <my-feed [syndicationItems]="syndicationItems"></my-feed> 12 <my-feed [syndicationItems]="syndicationItems"></my-feed>
13
14 <div ngbDropdown class="d-inline-block ml-4">
15 <button class="btn btn-sm btn-outline-secondary" id="dropdownSortComments" ngbDropdownToggle i18n>
16 Sort by
17 </button>
18 <div ngbDropdownMenu aria-labelledby="dropdownSortComments">
19 <button (click)="handleSortChange('-createdAt')" ngbDropdownItem i18n>Most recent first (default)</button>
20 <button (click)="handleSortChange('-totalReplies')" ngbDropdownItem i18n>Most replies first</button>
21 </div>
22 </div>
13 </div> 23 </div>
14 24
15 <ng-template [ngIf]="video.commentsEnabled === true"> 25 <ng-template [ngIf]="video.commentsEnabled === true">
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 dde10b068..9e3682295 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
@@ -23,6 +23,12 @@
23 margin-right: 0; 23 margin-right: 0;
24} 24}
25 25
26#dropdownSortComments {
27 font-weight: 600;
28 text-transform: uppercase;
29 border: none;
30}
31
26my-feed { 32my-feed {
27 display: inline-block; 33 display: inline-block;
28 margin-left: 5px; 34 margin-left: 5px;
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.ts b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
index e81401553..974c61d6c 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
@@ -6,7 +6,7 @@ import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/v
6import { AuthService } from '../../../core/auth' 6import { AuthService } from '../../../core/auth'
7import { ComponentPagination, hasMoreItems } from '../../../shared/rest/component-pagination.model' 7import { ComponentPagination, hasMoreItems } from '../../../shared/rest/component-pagination.model'
8import { User } from '../../../shared/users' 8import { User } from '../../../shared/users'
9import { VideoSortField } from '../../../shared/video/sort-field.type' 9import { CommentSortField } from '../../../shared/video/sort-field.type'
10import { VideoDetails } from '../../../shared/video/video-details.model' 10import { VideoDetails } from '../../../shared/video/video-details.model'
11import { VideoComment } from './video-comment.model' 11import { VideoComment } from './video-comment.model'
12import { VideoCommentService } from './video-comment.service' 12import { VideoCommentService } from './video-comment.service'
@@ -28,7 +28,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
28 28
29 comments: VideoComment[] = [] 29 comments: VideoComment[] = []
30 highlightedThread: VideoComment 30 highlightedThread: VideoComment
31 sort: VideoSortField = '-createdAt' 31 sort: CommentSortField = '-createdAt'
32 componentPagination: ComponentPagination = { 32 componentPagination: ComponentPagination = {
33 currentPage: 1, 33 currentPage: 1,
34 itemsPerPage: 10, 34 itemsPerPage: 10,
@@ -152,6 +152,13 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
152 this.viewReplies(commentTree.comment.id) 152 this.viewReplies(commentTree.comment.id)
153 } 153 }
154 154
155 handleSortChange (sort: CommentSortField) {
156 if (this.sort === sort) return
157
158 this.sort = sort
159 this.resetVideo()
160 }
161
155 handleTimestampClicked (timestamp: number) { 162 handleTimestampClicked (timestamp: number) {
156 this.timestampClicked.emit(timestamp) 163 this.timestampClicked.emit(timestamp)
157 } 164 }
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 79fcd0edf..1b7b94d74 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -46,7 +46,7 @@ const SORTABLE_COLUMNS = {
46 VIDEO_ABUSES: [ 'id', 'createdAt', 'state' ], 46 VIDEO_ABUSES: [ 'id', 'createdAt', 'state' ],
47 VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ], 47 VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ],
48 VIDEO_IMPORTS: [ 'createdAt' ], 48 VIDEO_IMPORTS: [ 'createdAt' ],
49 VIDEO_COMMENT_THREADS: [ 'createdAt' ], 49 VIDEO_COMMENT_THREADS: [ 'createdAt', 'totalReplies' ],
50 VIDEO_RATES: [ 'createdAt' ], 50 VIDEO_RATES: [ 'createdAt' ],
51 BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ], 51 BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ],
52 FOLLOWERS: [ 'createdAt', 'state', 'score' ], 52 FOLLOWERS: [ 'createdAt', 'state', 'score' ],
diff --git a/server/models/utils.ts b/server/models/utils.ts
index b53a52a05..4199cc443 100644
--- a/server/models/utils.ts
+++ b/server/models/utils.ts
@@ -22,6 +22,19 @@ function getSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderIt
22 return [ [ finalField, direction ], lastSort ] 22 return [ [ finalField, direction ], lastSort ]
23} 23}
24 24
25function getCommentSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
26 const { direction, field } = buildDirectionAndField(value)
27
28 if (field === 'totalReplies') {
29 return [
30 [ Sequelize.literal('"totalReplies"'), direction ],
31 lastSort
32 ]
33 }
34
35 return getSort(value, lastSort)
36}
37
25function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { 38function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
26 const { direction, field } = buildDirectionAndField(value) 39 const { direction, field } = buildDirectionAndField(value)
27 40
@@ -167,6 +180,7 @@ export {
167 SortType, 180 SortType,
168 buildLocalAccountIdsIn, 181 buildLocalAccountIdsIn,
169 getSort, 182 getSort,
183 getCommentSort,
170 getVideoSort, 184 getVideoSort,
171 getBlacklistSort, 185 getBlacklistSort,
172 createSimilarityAttribute, 186 createSimilarityAttribute,
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts
index 869a42afe..28f011b03 100644
--- a/server/models/video/video-comment.ts
+++ b/server/models/video/video-comment.ts
@@ -6,7 +6,7 @@ import { isActivityPubUrlValid } from '../../helpers/custom-validators/activityp
6import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' 6import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
7import { AccountModel } from '../account/account' 7import { AccountModel } from '../account/account'
8import { ActorModel } from '../activitypub/actor' 8import { ActorModel } from '../activitypub/actor'
9import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils' 9import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getCommentSort, throwIfNotValid } from '../utils'
10import { VideoModel } from './video' 10import { VideoModel } from './video'
11import { VideoChannelModel } from './video-channel' 11import { VideoChannelModel } from './video-channel'
12import { getServerActor } from '../../helpers/utils' 12import { getServerActor } from '../../helpers/utils'
@@ -259,7 +259,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
259 const query = { 259 const query = {
260 offset: start, 260 offset: start,
261 limit: count, 261 limit: count,
262 order: getSort(sort), 262 order: getCommentSort(sort),
263 where: { 263 where: {
264 videoId, 264 videoId,
265 inReplyToCommentId: null, 265 inReplyToCommentId: null,