From 69b623b8fb755a6b254757146caaf3ef87b74aa3 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sat, 30 Jul 2022 09:28:08 -0400 Subject: [PATCH] Comment Tree paging (#726) * Updating translations. * Forgot to add comment-sort-select * Upgrading deps --- lemmy-translations | 2 +- package.json | 2 +- .../components/comment/comment-form.tsx | 2 +- .../components/comment/comment-node.tsx | 138 ++++-- .../components/comment/comment-nodes.tsx | 10 +- .../components/comment/comment-report.tsx | 7 +- .../components/common/comment-sort-select.tsx | 70 ++++ src/shared/components/common/sort-select.tsx | 1 + src/shared/components/community/community.tsx | 18 +- src/shared/components/home/home.tsx | 18 +- src/shared/components/person/inbox.tsx | 185 ++++---- .../components/person/person-details.tsx | 6 +- src/shared/components/post/post-listing.tsx | 52 +-- src/shared/components/post/post.tsx | 395 +++++++++++------- src/shared/components/search.tsx | 12 +- src/shared/interfaces.ts | 22 +- src/shared/routes.ts | 4 +- src/shared/utils.ts | 143 +++---- yarn.lock | 8 +- 19 files changed, 652 insertions(+), 443 deletions(-) create mode 100644 src/shared/components/common/comment-sort-select.tsx diff --git a/lemmy-translations b/lemmy-translations index 7c1b691..7c39457 160000 --- a/lemmy-translations +++ b/lemmy-translations @@ -1 +1 @@ -Subproject commit 7c1b691af63845a2fe2f8219b4620b8db3c9c3ba +Subproject commit 7c3945745dcd07774b19453803f7f14ab80ab3d3 diff --git a/package.json b/package.json index 4213e89..31e9c87 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "eslint-plugin-prettier": "^4.2.1", "husky": "^8.0.1", "import-sort-style-module": "^6.0.0", - "lemmy-js-client": "0.17.0-rc.38", + "lemmy-js-client": "0.17.0-rc.39", "lint-staged": "^13.0.3", "mini-css-extract-plugin": "^2.6.1", "node-fetch": "^2.6.1", diff --git a/src/shared/components/comment/comment-form.tsx b/src/shared/components/comment/comment-form.tsx index 7abf39b..64841e7 100644 --- a/src/shared/components/comment/comment-form.tsx +++ b/src/shared/components/comment/comment-form.tsx @@ -3,6 +3,7 @@ import { Component } from "inferno"; import { T } from "inferno-i18next-dess"; import { Link } from "inferno-router"; import { + CommentNode as CommentNodeI, CommentResponse, CreateComment, EditComment, @@ -12,7 +13,6 @@ import { } from "lemmy-js-client"; import { Subscription } from "rxjs"; import { i18n } from "../../i18next"; -import { CommentNode as CommentNodeI } from "../../interfaces"; import { UserService, WebSocketService } from "../../services"; import { auth, diff --git a/src/shared/components/comment/comment-node.tsx b/src/shared/components/comment/comment-node.tsx index 27e209e..d4bd1fe 100644 --- a/src/shared/components/comment/comment-node.tsx +++ b/src/shared/components/comment/comment-node.tsx @@ -8,12 +8,16 @@ import { BanFromCommunity, BanPerson, BlockPerson, + CommentNode as CommentNodeI, + CommentReplyView, CommentView, CommunityModeratorView, CreateCommentLike, CreateCommentReport, DeleteComment, - MarkCommentAsRead, + GetComments, + ListingType, + MarkCommentReplyAsRead, MarkPersonMentionAsRead, PersonMentionView, PersonViewSafe, @@ -26,11 +30,7 @@ import { } from "lemmy-js-client"; import moment from "moment"; import { i18n } from "../../i18next"; -import { - BanType, - CommentNode as CommentNodeI, - PurgeType, -} from "../../interfaces"; +import { BanType, CommentViewType, PurgeType } from "../../interfaces"; import { UserService, WebSocketService } from "../../services"; import { amCommunityCreator, @@ -38,6 +38,7 @@ import { canAdmin, canMod, colorList, + commentTreeMaxDepth, futureDaysToUnixTime, isAdmin, isBanned, @@ -82,7 +83,6 @@ interface CommentNodeState { score: number; upvotes: number; downvotes: number; - borderColor: string; readLoading: boolean; saveLoading: boolean; } @@ -99,6 +99,7 @@ interface CommentNodeProps { showContext?: boolean; showCommunity?: boolean; enableDownvotes: boolean; + viewType: CommentViewType; } export class CommentNode extends Component { @@ -129,9 +130,6 @@ export class CommentNode extends Component { score: this.props.node.comment_view.counts.score, upvotes: this.props.node.comment_view.counts.upvotes, downvotes: this.props.node.comment_view.counts.downvotes, - borderColor: this.props.node.depth - ? colorList[this.props.node.depth % colorList.length] - : colorList[0], readLoading: false, saveLoading: false, }; @@ -181,10 +179,23 @@ export class CommentNode extends Component { cv.creator.id ); + let borderColor = this.props.node.depth + ? colorList[(this.props.node.depth - 1) % colorList.length] + : colorList[0]; + let moreRepliesBorderColor = this.props.node.depth + ? colorList[this.props.node.depth % colorList.length] + : colorList[0]; + + let showMoreChildren = + this.props.viewType == CommentViewType.Tree && + !this.state.collapsed && + node.children.length == 0 && + node.comment_view.counts.child_count > 0; + return (
{ } ${this.isCommentNew ? "mark" : ""}`} style={ !this.props.noIndent && - cv.comment.parent_id.isSome() && - `border-left: 2px ${this.state.borderColor} solid !important` + this.props.node.depth && + `border-left: 2px ${borderColor} solid !important` } > + {showMoreChildren && ( +
+ +
+ )} {/* end of details */} {this.state.showRemoveDialog && (
{ focus /> )} - {!this.state.collapsed && node.children && ( + {!this.state.collapsed && node.children.length > 0 && ( { admins={this.props.admins} maxCommentsShown={None} enableDownvotes={this.props.enableDownvotes} + viewType={this.props.viewType} /> )} {/* A collapsed clearfix */} @@ -947,11 +973,16 @@ export class CommentNode extends Component { ); } - get commentOrMentionRead() { + get commentReplyOrMentionRead(): boolean { let cv = this.props.node.comment_view; - return this.isPersonMentionType(cv) - ? cv.person_mention.read - : cv.comment.read; + + if (this.isPersonMentionType(cv)) { + return cv.person_mention.read; + } else if (this.isCommentReplyType(cv)) { + return cv.comment_reply.read; + } else { + return false; + } } linkBtn(small = false) { @@ -968,7 +999,7 @@ export class CommentNode extends Component { <> @@ -1061,7 +1092,7 @@ export class CommentNode extends Component { this.setState(this.state); } - handleCommentUpvote(i: CommentNodeI, event: any) { + handleCommentUpvote(event: any) { event.preventDefault(); let myVote = this.state.my_vote.unwrapOr(0); let newVote = myVote == 1 ? 0 : 1; @@ -1081,17 +1112,16 @@ export class CommentNode extends Component { this.state.my_vote = Some(newVote); let form = new CreateCommentLike({ - comment_id: i.comment_view.comment.id, + comment_id: this.props.node.comment_view.comment.id, score: newVote, auth: auth().unwrap(), }); - WebSocketService.Instance.send(wsClient.likeComment(form)); this.setState(this.state); setupTippy(); } - handleCommentDownvote(i: CommentNodeI, event: any) { + handleCommentDownvote(event: any) { event.preventDefault(); let myVote = this.state.my_vote.unwrapOr(0); let newVote = myVote == -1 ? 0 : -1; @@ -1111,7 +1141,7 @@ export class CommentNode extends Component { this.state.my_vote = Some(newVote); let form = new CreateCommentLike({ - comment_id: i.comment_view.comment.id, + comment_id: this.props.node.comment_view.comment.id, score: newVote, auth: auth().unwrap(), }); @@ -1175,11 +1205,17 @@ export class CommentNode extends Component { } isPersonMentionType( - item: CommentView | PersonMentionView + item: CommentView | PersonMentionView | CommentReplyView ): item is PersonMentionView { return (item as PersonMentionView).person_mention?.id !== undefined; } + isCommentReplyType( + item: CommentView | PersonMentionView | CommentReplyView + ): item is CommentReplyView { + return (item as CommentReplyView).comment_reply?.id !== undefined; + } + handleMarkRead(i: CommentNode) { if (i.isPersonMentionType(i.props.node.comment_view)) { let form = new MarkPersonMentionAsRead({ @@ -1188,13 +1224,13 @@ export class CommentNode extends Component { auth: auth().unwrap(), }); WebSocketService.Instance.send(wsClient.markPersonMentionAsRead(form)); - } else { - let form = new MarkCommentAsRead({ - comment_id: i.props.node.comment_view.comment.id, - read: !i.props.node.comment_view.comment.read, + } else if (i.isCommentReplyType(i.props.node.comment_view)) { + let form = new MarkCommentReplyAsRead({ + comment_reply_id: i.props.node.comment_view.comment_reply.id, + read: !i.props.node.comment_view.comment_reply.read, auth: auth().unwrap(), }); - WebSocketService.Instance.send(wsClient.markCommentAsRead(form)); + WebSocketService.Instance.send(wsClient.markCommentReplyAsRead(form)); } i.state.readLoading = true; @@ -1419,6 +1455,24 @@ export class CommentNode extends Component { setupTippy(); } + handleFetchChildren(i: CommentNode) { + let form = new GetComments({ + post_id: Some(i.props.node.comment_view.post.id), + parent_id: Some(i.props.node.comment_view.comment.id), + max_depth: Some(commentTreeMaxDepth), + page: None, + sort: None, + limit: Some(999), + type_: Some(ListingType.All), + community_name: None, + community_id: None, + saved_only: Some(false), + auth: auth(false).ok(), + }); + + WebSocketService.Instance.send(wsClient.getComments(form)); + } + get scoreColor() { if (this.state.my_vote.unwrapOr(0) == 1) { return "text-info"; diff --git a/src/shared/components/comment/comment-nodes.tsx b/src/shared/components/comment/comment-nodes.tsx index 62167ec..f9484c2 100644 --- a/src/shared/components/comment/comment-nodes.tsx +++ b/src/shared/components/comment/comment-nodes.tsx @@ -1,7 +1,11 @@ import { Option } from "@sniptt/monads"; import { Component } from "inferno"; -import { CommunityModeratorView, PersonViewSafe } from "lemmy-js-client"; -import { CommentNode as CommentNodeI } from "../../interfaces"; +import { + CommentNode as CommentNodeI, + CommunityModeratorView, + PersonViewSafe, +} from "lemmy-js-client"; +import { CommentViewType } from "../../interfaces"; import { CommentNode } from "./comment-node"; interface CommentNodesProps { @@ -17,6 +21,7 @@ interface CommentNodesProps { showContext?: boolean; showCommunity?: boolean; enableDownvotes?: boolean; + viewType: CommentViewType; } export class CommentNodes extends Component { @@ -45,6 +50,7 @@ export class CommentNodes extends Component { showContext={this.props.showContext} showCommunity={this.props.showCommunity} enableDownvotes={this.props.enableDownvotes} + viewType={this.props.viewType} /> ))}
diff --git a/src/shared/components/comment/comment-report.tsx b/src/shared/components/comment/comment-report.tsx index 0a65226..a2d2b10 100644 --- a/src/shared/components/comment/comment-report.tsx +++ b/src/shared/components/comment/comment-report.tsx @@ -2,13 +2,14 @@ import { None } from "@sniptt/monads"; import { Component, linkEvent } from "inferno"; import { T } from "inferno-i18next-dess"; import { + CommentNode as CommentNodeI, CommentReportView, CommentView, ResolveCommentReport, SubscribedType, } from "lemmy-js-client"; import { i18n } from "../../i18next"; -import { CommentNode as CommentNodeI } from "../../interfaces"; +import { CommentViewType } from "../../interfaces"; import { WebSocketService } from "../../services"; import { auth, wsClient } from "../../utils"; import { Icon } from "../common/icon"; @@ -44,18 +45,20 @@ export class CommentReport extends Component { subscribed: SubscribedType.NotSubscribed, saved: false, creator_blocked: false, - recipient: None, my_vote: r.my_vote, }; let node: CommentNodeI = { comment_view, + children: [], + depth: 0, }; return (
{ + private id = `sort-select-${randomStr()}`; + private emptyState: CommentSortSelectState = { + sort: this.props.sort, + }; + + constructor(props: any, context: any) { + super(props, context); + this.state = this.emptyState; + } + + static getDerivedStateFromProps(props: any): CommentSortSelectState { + return { + sort: props.sort, + }; + } + + render() { + return ( + <> + + + + + + ); + } + + handleSortChange(i: CommentSortSelect, event: any) { + i.props.onChange(event.target.value); + } +} diff --git a/src/shared/components/common/sort-select.tsx b/src/shared/components/common/sort-select.tsx index 1188064..3f815f5 100644 --- a/src/shared/components/common/sort-select.tsx +++ b/src/shared/components/common/sort-select.tsx @@ -51,6 +51,7 @@ export class SortSelect extends Component { , ]} + {!this.props.hideMostComments && [