Using auto-generated types from ts-rs. (#1003)

* Using auto-generated types from ts-rs.

- Fixes #998
- Added support for new `GetFederatedInstances`
- Fixed a few bugs in the process.

* Update imports to use SleeplessOne1917's fix.
This commit is contained in:
Dessalines 2023-05-11 14:32:32 -04:00 committed by GitHub
parent 06bfb7eadf
commit c5fd084577
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 753 additions and 750 deletions

@ -1 +1 @@
Subproject commit 007e53683768aeba63e9e4c179c1d240217bcee2 Subproject commit 3bb45c26cb54325c3d8d605f4334447b9b78293a

View file

@ -59,7 +59,7 @@
"inferno-server": "^8.1.1", "inferno-server": "^8.1.1",
"isomorphic-cookie": "^1.2.4", "isomorphic-cookie": "^1.2.4",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lemmy-js-client": "0.17.2-rc.5", "lemmy-js-client": "0.17.2-rc.14",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"markdown-it-container": "^3.0.0", "markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.2", "markdown-it-emoji": "^2.0.2",

View file

@ -39,7 +39,7 @@ export class Footer extends Component<FooterProps, any> {
</NavLink> </NavLink>
</li> </li>
)} )}
{this.props.site.federated_instances && ( {this.props.site.site_view.local_site.federation_enabled && (
<li className="nav-item"> <li className="nav-item">
<NavLink className="nav-link" to="/instances"> <NavLink className="nav-link" to="/instances">
{i18n.t("instances")} {i18n.t("instances")}

View file

@ -40,9 +40,9 @@ interface NavbarProps {
interface NavbarState { interface NavbarState {
expanded: boolean; expanded: boolean;
unreadInboxCount: number; unreadInboxCount: bigint;
unreadReportCount: number; unreadReportCount: bigint;
unreadApplicationCount: number; unreadApplicationCount: bigint;
showDropdown: boolean; showDropdown: boolean;
onSiteBanner?(url: string): any; onSiteBanner?(url: string): any;
} }
@ -54,9 +54,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
private unreadReportCountSub: Subscription; private unreadReportCountSub: Subscription;
private unreadApplicationCountSub: Subscription; private unreadApplicationCountSub: Subscription;
state: NavbarState = { state: NavbarState = {
unreadInboxCount: 0, unreadInboxCount: 0n,
unreadReportCount: 0, unreadReportCount: 0n,
unreadApplicationCount: 0, unreadApplicationCount: 0n,
expanded: false, expanded: false,
showDropdown: false, showDropdown: false,
}; };
@ -144,7 +144,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="p-1 navbar-toggler nav-link border-0" className="p-1 navbar-toggler nav-link border-0"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_messages", { title={i18n.t("unread_messages", {
count: this.state.unreadInboxCount, count: Number(this.state.unreadInboxCount),
formattedCount: numToSI(this.state.unreadInboxCount), formattedCount: numToSI(this.state.unreadInboxCount),
})} })}
> >
@ -165,7 +165,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="p-1 navbar-toggler nav-link border-0" className="p-1 navbar-toggler nav-link border-0"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_reports", { title={i18n.t("unread_reports", {
count: this.state.unreadReportCount, count: Number(this.state.unreadReportCount),
formattedCount: numToSI(this.state.unreadReportCount), formattedCount: numToSI(this.state.unreadReportCount),
})} })}
> >
@ -187,7 +187,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="p-1 navbar-toggler nav-link border-0" className="p-1 navbar-toggler nav-link border-0"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", { title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount, count: Number(this.state.unreadApplicationCount),
formattedCount: numToSI( formattedCount: numToSI(
this.state.unreadApplicationCount this.state.unreadApplicationCount
), ),
@ -305,7 +305,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/inbox" to="/inbox"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_messages", { title={i18n.t("unread_messages", {
count: this.state.unreadInboxCount, count: Number(this.state.unreadInboxCount),
formattedCount: numToSI(this.state.unreadInboxCount), formattedCount: numToSI(this.state.unreadInboxCount),
})} })}
> >
@ -326,7 +326,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/reports" to="/reports"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_reports", { title={i18n.t("unread_reports", {
count: this.state.unreadReportCount, count: Number(this.state.unreadReportCount),
formattedCount: numToSI(this.state.unreadReportCount), formattedCount: numToSI(this.state.unreadReportCount),
})} })}
> >
@ -348,7 +348,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="nav-link" className="nav-link"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)} onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", { title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount, count: Number(this.state.unreadApplicationCount),
formattedCount: numToSI( formattedCount: numToSI(
this.state.unreadApplicationCount this.state.unreadApplicationCount
), ),
@ -512,7 +512,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
unreadReportCount: unreadReportCount:
data.post_reports + data.post_reports +
data.comment_reports + data.comment_reports +
(data.private_message_reports ?? 0), (data.private_message_reports ?? 0n),
}); });
this.sendReportUnread(); this.sendReportUnread();
} else if (op == UserOperation.GetUnreadRegistrationApplicationCount) { } else if (op == UserOperation.GetUnreadRegistrationApplicationCount) {
@ -528,7 +528,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
data.recipient_ids.includes(mui.local_user_view.local_user.id) data.recipient_ids.includes(mui.local_user_view.local_user.id)
) { ) {
this.setState({ this.setState({
unreadInboxCount: this.state.unreadInboxCount + 1, unreadInboxCount: this.state.unreadInboxCount + 1n,
}); });
this.sendUnreadCount(); this.sendUnreadCount();
notifyComment(data.comment_view, this.context.router); notifyComment(data.comment_view, this.context.router);
@ -541,7 +541,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
UserService.Instance.myUserInfo?.local_user_view.person.id UserService.Instance.myUserInfo?.local_user_view.person.id
) { ) {
this.setState({ this.setState({
unreadInboxCount: this.state.unreadInboxCount + 1, unreadInboxCount: this.state.unreadInboxCount + 1n,
}); });
this.sendUnreadCount(); this.sendUnreadCount();
notifyPrivateMessage(data.private_message_view, this.context.router); notifyPrivateMessage(data.private_message_view, this.context.router);

View file

@ -2,7 +2,6 @@ import { Component } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { import {
CommentNode as CommentNodeI,
CommentResponse, CommentResponse,
CreateComment, CreateComment,
EditComment, EditComment,
@ -12,6 +11,7 @@ import {
wsUserOp, wsUserOp,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { CommentNodeI } from "shared/interfaces";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {

View file

@ -7,21 +7,19 @@ import {
BanFromCommunity, BanFromCommunity,
BanPerson, BanPerson,
BlockPerson, BlockPerson,
CommentNode as CommentNodeI,
CommentReplyView, CommentReplyView,
CommentView, CommentView,
CommunityModeratorView, CommunityModeratorView,
CreateCommentLike, CreateCommentLike,
CreateCommentReport, CreateCommentReport,
DeleteComment, DeleteComment,
EditComment, DistinguishComment,
GetComments, GetComments,
Language, Language,
ListingType,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
PersonMentionView, PersonMentionView,
PersonViewSafe, PersonView,
PurgeComment, PurgeComment,
PurgePerson, PurgePerson,
RemoveComment, RemoveComment,
@ -30,7 +28,12 @@ import {
} from "lemmy-js-client"; } from "lemmy-js-client";
import moment from "moment"; import moment from "moment";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { BanType, CommentViewType, PurgeType } from "../../interfaces"; import {
BanType,
CommentNodeI,
CommentViewType,
PurgeType,
} from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
amCommunityCreator, amCommunityCreator,
@ -81,9 +84,9 @@ interface CommentNodeState {
showReportDialog: boolean; showReportDialog: boolean;
reportReason?: string; reportReason?: string;
my_vote?: number; my_vote?: number;
score: number; score: bigint;
upvotes: number; upvotes: bigint;
downvotes: number; downvotes: bigint;
readLoading: boolean; readLoading: boolean;
saveLoading: boolean; saveLoading: boolean;
} }
@ -91,7 +94,7 @@ interface CommentNodeState {
interface CommentNodeProps { interface CommentNodeProps {
node: CommentNodeI; node: CommentNodeI;
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonViewSafe[]; admins?: PersonView[];
noBorder?: boolean; noBorder?: boolean;
noIndent?: boolean; noIndent?: boolean;
viewOnly?: boolean; viewOnly?: boolean;
@ -296,8 +299,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
<span <span
className="mr-1 font-weight-bold" className="mr-1 font-weight-bold"
aria-label={i18n.t("number_of_points", { aria-label={i18n.t("number_of_points", {
count: this.state.score, count: Number(this.state.score),
formattedCount: this.state.score, formattedCount: numToSI(this.state.score),
})} })}
> >
{numToSI(this.state.score)} {numToSI(this.state.score)}
@ -835,7 +838,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
> >
{i18n.t("x_more_replies", { {i18n.t("x_more_replies", {
count: node.comment_view.counts.child_count, count: node.comment_view.counts.child_count,
formattedCount: numToSI(node.comment_view.counts.child_count), formattedCount: numToSI(
BigInt(node.comment_view.counts.child_count)
),
})}{" "} })}{" "}
</button> </button>
@ -1152,19 +1157,19 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
if (myVote == 1) { if (myVote == 1) {
this.setState({ this.setState({
score: this.state.score - 1, score: this.state.score - 1n,
upvotes: this.state.upvotes - 1, upvotes: this.state.upvotes - 1n,
}); });
} else if (myVote == -1) { } else if (myVote == -1) {
this.setState({ this.setState({
downvotes: this.state.downvotes - 1, downvotes: this.state.downvotes - 1n,
upvotes: this.state.upvotes + 1, upvotes: this.state.upvotes + 1n,
score: this.state.score + 2, score: this.state.score + 2n,
}); });
} else { } else {
this.setState({ this.setState({
score: this.state.score + 1, score: this.state.score + 1n,
upvotes: this.state.upvotes + 1, upvotes: this.state.upvotes + 1n,
}); });
} }
@ -1189,19 +1194,19 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
if (myVote == 1) { if (myVote == 1) {
this.setState({ this.setState({
downvotes: this.state.downvotes + 1, downvotes: this.state.downvotes + 1n,
upvotes: this.state.upvotes - 1, upvotes: this.state.upvotes - 1n,
score: this.state.score - 2, score: this.state.score - 2n,
}); });
} else if (myVote == -1) { } else if (myVote == -1) {
this.setState({ this.setState({
downvotes: this.state.downvotes - 1, downvotes: this.state.downvotes - 1n,
score: this.state.score + 1, score: this.state.score + 1n,
}); });
} else { } else {
this.setState({ this.setState({
downvotes: this.state.downvotes + 1, downvotes: this.state.downvotes + 1n,
score: this.state.score - 1, score: this.state.score - 1n,
}); });
} }
@ -1278,7 +1283,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
let comment = i.props.node.comment_view.comment; let comment = i.props.node.comment_view.comment;
let auth = myAuth(); let auth = myAuth();
if (auth) { if (auth) {
let form: EditComment = { let form: DistinguishComment = {
comment_id: comment.id, comment_id: comment.id,
distinguished: !comment.distinguished, distinguished: !comment.distinguished,
auth, auth,
@ -1542,8 +1547,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
post_id: i.props.node.comment_view.post.id, post_id: i.props.node.comment_view.post.id,
parent_id: i.props.node.comment_view.comment.id, parent_id: i.props.node.comment_view.comment.id,
max_depth: commentTreeMaxDepth, max_depth: commentTreeMaxDepth,
limit: 999, // TODO limit: 999n, // TODO
type_: ListingType.All, type_: "All",
saved_only: false, saved_only: false,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -1563,18 +1568,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get pointsTippy(): string { get pointsTippy(): string {
let points = i18n.t("number_of_points", { let points = i18n.t("number_of_points", {
count: this.state.score, count: Number(this.state.score),
formattedCount: this.state.score, formattedCount: numToSI(this.state.score),
}); });
let upvotes = i18n.t("number_of_upvotes", { let upvotes = i18n.t("number_of_upvotes", {
count: this.state.upvotes, count: Number(this.state.upvotes),
formattedCount: this.state.upvotes, formattedCount: numToSI(this.state.upvotes),
}); });
let downvotes = i18n.t("number_of_downvotes", { let downvotes = i18n.t("number_of_downvotes", {
count: this.state.downvotes, count: Number(this.state.downvotes),
formattedCount: this.state.downvotes, formattedCount: numToSI(this.state.downvotes),
}); });
return `${points}${upvotes}${downvotes}`; return `${points}${upvotes}${downvotes}`;

View file

@ -1,17 +1,12 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { import { CommunityModeratorView, Language, PersonView } from "lemmy-js-client";
CommentNode as CommentNodeI, import { CommentNodeI, CommentViewType } from "../../interfaces";
CommunityModeratorView,
Language,
PersonViewSafe,
} from "lemmy-js-client";
import { CommentViewType } from "../../interfaces";
import { CommentNode } from "./comment-node"; import { CommentNode } from "./comment-node";
interface CommentNodesProps { interface CommentNodesProps {
nodes: CommentNodeI[]; nodes: CommentNodeI[];
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonViewSafe[]; admins?: PersonView[];
maxCommentsShown?: number; maxCommentsShown?: number;
noBorder?: boolean; noBorder?: boolean;
noIndent?: boolean; noIndent?: boolean;

View file

@ -1,14 +1,12 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { import {
CommentNode as CommentNodeI,
CommentReportView, CommentReportView,
CommentView, CommentView,
ResolveCommentReport, ResolveCommentReport,
SubscribedType,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { CommentViewType } from "../../interfaces"; import { CommentNodeI, CommentViewType } from "../../interfaces";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { myAuth, wsClient } from "../../utils"; import { myAuth, wsClient } from "../../utils";
import { Icon } from "../common/icon"; import { Icon } from "../common/icon";
@ -41,7 +39,7 @@ export class CommentReport extends Component<CommentReportProps, any> {
community: r.community, community: r.community,
creator_banned_from_community: r.creator_banned_from_community, creator_banned_from_community: r.creator_banned_from_community,
counts: r.counts, counts: r.counts,
subscribed: SubscribedType.NotSubscribed, subscribed: "NotSubscribed",
saved: false, saved: false,
creator_blocked: false, creator_blocked: false,
my_vote: r.my_vote, my_vote: r.my_vote,

View file

@ -46,10 +46,10 @@ export class CommentSortSelect extends Component<
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t("sort_type")} {i18n.t("sort_type")}
</option> </option>
<option value={CommentSortType.Hot}>{i18n.t("hot")}</option>, <option value={"Hot"}>{i18n.t("hot")}</option>,
<option value={CommentSortType.Top}>{i18n.t("top")}</option>, <option value={"Top"}>{i18n.t("top")}</option>,
<option value={CommentSortType.New}>{i18n.t("new")}</option> <option value={"New"}>{i18n.t("new")}</option>
<option value={CommentSortType.Old}>{i18n.t("old")}</option> <option value={"Old"}>{i18n.t("old")}</option>
</select> </select>
<a <a
className="text-muted" className="text-muted"

View file

@ -44,15 +44,15 @@ export class ListingTypeSelect extends Component<
<label <label
title={i18n.t("subscribed_description")} title={i18n.t("subscribed_description")}
className={`btn btn-outline-secondary className={`btn btn-outline-secondary
${this.state.type_ == ListingType.Subscribed && "active"} ${this.state.type_ == "Subscribed" && "active"}
${!UserService.Instance.myUserInfo ? "disabled" : "pointer"} ${!UserService.Instance.myUserInfo ? "disabled" : "pointer"}
`} `}
> >
<input <input
id={`${this.id}-subscribed`} id={`${this.id}-subscribed`}
type="radio" type="radio"
value={ListingType.Subscribed} value={"Subscribed"}
checked={this.state.type_ == ListingType.Subscribed} checked={this.state.type_ == "Subscribed"}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
disabled={!UserService.Instance.myUserInfo} disabled={!UserService.Instance.myUserInfo}
/> />
@ -63,14 +63,14 @@ export class ListingTypeSelect extends Component<
<label <label
title={i18n.t("local_description")} title={i18n.t("local_description")}
className={`pointer btn btn-outline-secondary ${ className={`pointer btn btn-outline-secondary ${
this.state.type_ == ListingType.Local && "active" this.state.type_ == "Local" && "active"
}`} }`}
> >
<input <input
id={`${this.id}-local`} id={`${this.id}-local`}
type="radio" type="radio"
value={ListingType.Local} value={"Local"}
checked={this.state.type_ == ListingType.Local} checked={this.state.type_ == "Local"}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t("local")} {i18n.t("local")}
@ -79,17 +79,15 @@ export class ListingTypeSelect extends Component<
<label <label
title={i18n.t("all_description")} title={i18n.t("all_description")}
className={`pointer btn btn-outline-secondary ${ className={`pointer btn btn-outline-secondary ${
(this.state.type_ == ListingType.All && "active") || (this.state.type_ == "All" && "active") ||
(!this.props.showLocal && (!this.props.showLocal && this.state.type_ == "Local" && "active")
this.state.type_ == ListingType.Local &&
"active")
}`} }`}
> >
<input <input
id={`${this.id}-all`} id={`${this.id}-all`}
type="radio" type="radio"
value={ListingType.All} value={"All"}
checked={this.state.type_ == ListingType.All} checked={this.state.type_ == "All"}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
/> />
{i18n.t("all")} {i18n.t("all")}

View file

@ -353,7 +353,7 @@ export class MarkdownTextArea extends Component<
if (files.length > maxUploadImages) { if (files.length > maxUploadImages) {
toast( toast(
i18n.t("too_many_images_upload", { i18n.t("too_many_images_upload", {
count: maxUploadImages, count: Number(maxUploadImages),
formattedCount: numToSI(maxUploadImages), formattedCount: numToSI(maxUploadImages),
}), }),
"danger" "danger"

View file

@ -2,8 +2,8 @@ import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
interface PaginatorProps { interface PaginatorProps {
page: number; page: bigint;
onChange(val: number): any; onChange(val: bigint): any;
} }
export class Paginator extends Component<PaginatorProps, any> { export class Paginator extends Component<PaginatorProps, any> {
@ -15,7 +15,7 @@ export class Paginator extends Component<PaginatorProps, any> {
<div className="my-2"> <div className="my-2">
<button <button
className="btn btn-secondary mr-2" className="btn btn-secondary mr-2"
disabled={this.props.page == 1} disabled={this.props.page == 1n}
onClick={linkEvent(this, this.handlePrev)} onClick={linkEvent(this, this.handlePrev)}
> >
{i18n.t("prev")} {i18n.t("prev")}
@ -31,10 +31,10 @@ export class Paginator extends Component<PaginatorProps, any> {
} }
handlePrev(i: Paginator) { handlePrev(i: Paginator) {
i.props.onChange(i.props.page - 1); i.props.onChange(i.props.page - 1n);
} }
handleNext(i: Paginator) { handleNext(i: Paginator) {
i.props.onChange(i.props.page + 1); i.props.onChange(i.props.page + 1n);
} }
} }

View file

@ -46,31 +46,31 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
{i18n.t("sort_type")} {i18n.t("sort_type")}
</option> </option>
{!this.props.hideHot && [ {!this.props.hideHot && [
<option key={SortType.Hot} value={SortType.Hot}> <option key={"Hot"} value={"Hot"}>
{i18n.t("hot")} {i18n.t("hot")}
</option>, </option>,
<option key={SortType.Active} value={SortType.Active}> <option key={"Active"} value={"Active"}>
{i18n.t("active")} {i18n.t("active")}
</option>, </option>,
]} ]}
<option value={SortType.New}>{i18n.t("new")}</option> <option value={"New"}>{i18n.t("new")}</option>
<option value={SortType.Old}>{i18n.t("old")}</option> <option value={"Old"}>{i18n.t("old")}</option>
{!this.props.hideMostComments && [ {!this.props.hideMostComments && [
<option key={SortType.MostComments} value={SortType.MostComments}> <option key={"MostComments"} value={"MostComments"}>
{i18n.t("most_comments")} {i18n.t("most_comments")}
</option>, </option>,
<option key={SortType.NewComments} value={SortType.NewComments}> <option key={"NewComments"} value={"NewComments"}>
{i18n.t("new_comments")} {i18n.t("new_comments")}
</option>, </option>,
]} ]}
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
</option> </option>
<option value={SortType.TopDay}>{i18n.t("top_day")}</option> <option value={"TopDay"}>{i18n.t("top_day")}</option>
<option value={SortType.TopWeek}>{i18n.t("top_week")}</option> <option value={"TopWeek"}>{i18n.t("top_week")}</option>
<option value={SortType.TopMonth}>{i18n.t("top_month")}</option> <option value={"TopMonth"}>{i18n.t("top_month")}</option>
<option value={SortType.TopYear}>{i18n.t("top_year")}</option> <option value={"TopYear"}>{i18n.t("top_year")}</option>
<option value={SortType.TopAll}>{i18n.t("top_all")}</option> <option value={"TopAll"}>{i18n.t("top_all")}</option>
</select> </select>
<a <a
className="text-muted" className="text-muted"

View file

@ -6,8 +6,6 @@ import {
ListCommunities, ListCommunities,
ListCommunitiesResponse, ListCommunitiesResponse,
ListingType, ListingType,
SortType,
SubscribedType,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -24,7 +22,6 @@ import {
isBrowser, isBrowser,
myAuth, myAuth,
numToSI, numToSI,
routeListingTypeToEnum,
setIsoData, setIsoData,
showLocal, showLocal,
toast, toast,
@ -37,7 +34,7 @@ import { ListingTypeSelect } from "../common/listing-type-select";
import { Paginator } from "../common/paginator"; import { Paginator } from "../common/paginator";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
const communityLimit = 50; const communityLimit = 50n;
interface CommunitiesState { interface CommunitiesState {
listCommunitiesResponse?: ListCommunitiesResponse; listCommunitiesResponse?: ListCommunitiesResponse;
@ -48,7 +45,7 @@ interface CommunitiesState {
interface CommunitiesProps { interface CommunitiesProps {
listingType: ListingType; listingType: ListingType;
page: number; page: bigint;
} }
function getCommunitiesQueryParams() { function getCommunitiesQueryParams() {
@ -59,7 +56,7 @@ function getCommunitiesQueryParams() {
} }
function getListingTypeFromQuery(listingType?: string): ListingType { function getListingTypeFromQuery(listingType?: string): ListingType {
return routeListingTypeToEnum(listingType ?? "", ListingType.Local); return listingType ? (listingType as ListingType) : "Local";
} }
function toggleSubscribe(community_id: number, follow: boolean) { function toggleSubscribe(community_id: number, follow: boolean) {
@ -80,7 +77,7 @@ function refetch() {
const listCommunitiesForm: ListCommunities = { const listCommunitiesForm: ListCommunities = {
type_: listingType, type_: listingType,
sort: SortType.TopMonth, sort: "TopMonth",
limit: communityLimit, limit: communityLimit,
page, page,
auth: myAuth(false), auth: myAuth(false),
@ -203,7 +200,7 @@ export class Communities extends Component<any, CommunitiesState> {
{numToSI(cv.counts.comments)} {numToSI(cv.counts.comments)}
</td> </td>
<td className="text-right"> <td className="text-right">
{cv.subscribed == SubscribedType.Subscribed && ( {cv.subscribed == "Subscribed" && (
<button <button
className="btn btn-link d-inline-block" className="btn btn-link d-inline-block"
onClick={linkEvent( onClick={linkEvent(
@ -214,7 +211,7 @@ export class Communities extends Component<any, CommunitiesState> {
{i18n.t("unsubscribe")} {i18n.t("unsubscribe")}
</button> </button>
)} )}
{cv.subscribed === SubscribedType.NotSubscribed && ( {cv.subscribed === "NotSubscribed" && (
<button <button
className="btn btn-link d-inline-block" className="btn btn-link d-inline-block"
onClick={linkEvent( onClick={linkEvent(
@ -225,7 +222,7 @@ export class Communities extends Component<any, CommunitiesState> {
{i18n.t("subscribe")} {i18n.t("subscribe")}
</button> </button>
)} )}
{cv.subscribed === SubscribedType.Pending && ( {cv.subscribed === "Pending" && (
<div className="text-warning d-inline-block"> <div className="text-warning d-inline-block">
{i18n.t("subscribe_pending")} {i18n.t("subscribe_pending")}
</div> </div>
@ -283,14 +280,14 @@ export class Communities extends Component<any, CommunitiesState> {
refetch(); refetch();
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
} }
handleListingTypeChange(val: ListingType) { handleListingTypeChange(val: ListingType) {
this.updateUrl({ this.updateUrl({
listingType: val, listingType: val,
page: 1, page: 1n,
}); });
} }
@ -318,7 +315,7 @@ export class Communities extends Component<any, CommunitiesState> {
}: InitialFetchRequest<QueryParams<CommunitiesProps>>): Promise<any>[] { }: InitialFetchRequest<QueryParams<CommunitiesProps>>): Promise<any>[] {
const listCommunitiesForm: ListCommunities = { const listCommunitiesForm: ListCommunities = {
type_: getListingTypeFromQuery(listingType), type_: getListingTypeFromQuery(listingType),
sort: SortType.TopMonth, sort: "TopMonth",
limit: communityLimit, limit: communityLimit,
page: getPageFromString(page), page: getPageFromString(page),
auth: auth, auth: auth,

View file

@ -1,11 +1,11 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { CommunitySafe } from "lemmy-js-client"; import { Community } from "lemmy-js-client";
import { hostname, relTags, showAvatars } from "../../utils"; import { hostname, relTags, showAvatars } from "../../utils";
import { PictrsImage } from "../common/pictrs-image"; import { PictrsImage } from "../common/pictrs-image";
interface CommunityLinkProps { interface CommunityLinkProps {
community: CommunitySafe; community: Community;
realLink?: boolean; realLink?: boolean;
useApubName?: boolean; useApubName?: boolean;
muted?: boolean; muted?: boolean;

View file

@ -14,7 +14,6 @@ import {
GetCommunityResponse, GetCommunityResponse,
GetPosts, GetPosts,
GetPostsResponse, GetPostsResponse,
ListingType,
PostReportResponse, PostReportResponse,
PostResponse, PostResponse,
PostView, PostView,
@ -54,8 +53,6 @@ import {
postToCommentSortType, postToCommentSortType,
relTags, relTags,
restoreScrollPosition, restoreScrollPosition,
routeDataTypeToEnum,
routeSortTypeToEnum,
saveCommentRes, saveCommentRes,
saveScrollPosition, saveScrollPosition,
setIsoData, setIsoData,
@ -91,7 +88,7 @@ interface State {
interface CommunityProps { interface CommunityProps {
dataType: DataType; dataType: DataType;
sort: SortType; sort: SortType;
page: number; page: bigint;
} }
function getCommunityQueryParams() { function getCommunityQueryParams() {
@ -102,18 +99,16 @@ function getCommunityQueryParams() {
}); });
} }
const getDataTypeFromQuery = (type?: string): DataType => function getDataTypeFromQuery(type?: string): DataType {
routeDataTypeToEnum(type ?? "", DataType.Post); return type ? DataType[type] : DataType.Post;
}
function getSortTypeFromQuery(type?: string): SortType { function getSortTypeFromQuery(type?: string): SortType {
const mySortType = const mySortType =
UserService.Instance.myUserInfo?.local_user_view.local_user UserService.Instance.myUserInfo?.local_user_view.local_user
.default_sort_type; .default_sort_type;
return routeSortTypeToEnum( return type ? (type as SortType) : mySortType ?? "Active";
type ?? "",
mySortType ? Object.values(SortType)[mySortType] : SortType.Active
);
} }
export class Community extends Component< export class Community extends Component<
@ -217,7 +212,7 @@ export class Community extends Component<
page, page,
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_: ListingType.All, type_: "All",
saved_only: false, saved_only: false,
auth, auth,
}; };
@ -229,7 +224,7 @@ export class Community extends Component<
page, page,
limit: fetchLimit, limit: fetchLimit,
sort: postToCommentSortType(sort), sort: postToCommentSortType(sort),
type_: ListingType.All, type_: "All",
saved_only: false, saved_only: false,
auth, auth,
}; };
@ -432,18 +427,18 @@ export class Community extends Component<
); );
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
handleSortChange(sort: SortType) { handleSortChange(sort: SortType) {
this.updateUrl({ sort, page: 1 }); this.updateUrl({ sort, page: 1n });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
handleDataTypeChange(dataType: DataType) { handleDataTypeChange(dataType: DataType) {
this.updateUrl({ dataType, page: 1 }); this.updateUrl({ dataType, page: 1n });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
@ -489,7 +484,7 @@ export class Community extends Component<
page, page,
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_: ListingType.All, type_: "All",
community_name: name, community_name: name,
saved_only: false, saved_only: false,
auth: myAuth(false), auth: myAuth(false),
@ -500,7 +495,7 @@ export class Community extends Component<
page, page,
limit: fetchLimit, limit: fetchLimit,
sort: postToCommentSortType(sort), sort: postToCommentSortType(sort),
type_: ListingType.All, type_: "All",
community_name: name, community_name: name,
saved_only: false, saved_only: false,
auth: myAuth(false), auth: myAuth(false),
@ -611,7 +606,11 @@ export class Community extends Component<
.show_new_post_notifs; .show_new_post_notifs;
// Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked // Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked
if (page === 1 && nsfwCheck(post_view) && !isPostBlocked(post_view)) { if (
page === 1n &&
nsfwCheck(post_view) &&
!isPostBlocked(post_view)
) {
this.state.posts.unshift(post_view); this.state.posts.unshift(post_view);
if (showPostNotifs) { if (showPostNotifs) {
notifyPost(post_view, this.context.router); notifyPost(post_view, this.context.router);

View file

@ -8,10 +8,9 @@ import {
DeleteCommunity, DeleteCommunity,
FollowCommunity, FollowCommunity,
Language, Language,
PersonViewSafe, PersonView,
PurgeCommunity, PurgeCommunity,
RemoveCommunity, RemoveCommunity,
SubscribedType,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
@ -35,7 +34,7 @@ import { PersonListing } from "../person/person-listing";
interface SidebarProps { interface SidebarProps {
community_view: CommunityView; community_view: CommunityView;
moderators: CommunityModeratorView[]; moderators: CommunityModeratorView[];
admins: PersonViewSafe[]; admins: PersonView[];
allLanguages: Language[]; allLanguages: Language[];
siteLanguages: number[]; siteLanguages: number[];
communityLanguages?: number[]; communityLanguages?: number[];
@ -134,7 +133,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<BannerIconHeader icon={community.icon} banner={community.banner} /> <BannerIconHeader icon={community.icon} banner={community.banner} />
)} )}
<span className="mr-2">{community.title}</span> <span className="mr-2">{community.title}</span>
{subscribed === SubscribedType.Subscribed && ( {subscribed === "Subscribed" && (
<button <button
className="btn btn-secondary btn-sm mr-2" className="btn btn-secondary btn-sm mr-2"
onClick={linkEvent(this, this.handleUnsubscribe)} onClick={linkEvent(this, this.handleUnsubscribe)}
@ -143,7 +142,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
{i18n.t("joined")} {i18n.t("joined")}
</button> </button>
)} )}
{subscribed === SubscribedType.Pending && ( {subscribed === "Pending" && (
<button <button
className="btn btn-warning mr-2" className="btn btn-warning mr-2"
onClick={linkEvent(this, this.handleUnsubscribe)} onClick={linkEvent(this, this.handleUnsubscribe)}
@ -186,18 +185,18 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_online", { {i18n.t("number_online", {
count: this.props.online, count: this.props.online,
formattedCount: numToSI(this.props.online), formattedCount: numToSI(BigInt(this.props.online)),
})} })}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_day", { data-tippy-content={i18n.t("active_users_in_the_last_day", {
count: counts.users_active_day, count: Number(counts.users_active_day),
formattedCount: counts.users_active_day, formattedCount: numToSI(counts.users_active_day),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_day, count: Number(counts.users_active_day),
formattedCount: numToSI(counts.users_active_day), formattedCount: numToSI(counts.users_active_day),
})}{" "} })}{" "}
/ {i18n.t("day")} / {i18n.t("day")}
@ -205,12 +204,12 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_week", { data-tippy-content={i18n.t("active_users_in_the_last_week", {
count: counts.users_active_week, count: Number(counts.users_active_week),
formattedCount: counts.users_active_week, formattedCount: numToSI(counts.users_active_week),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_week, count: Number(counts.users_active_week),
formattedCount: numToSI(counts.users_active_week), formattedCount: numToSI(counts.users_active_week),
})}{" "} })}{" "}
/ {i18n.t("week")} / {i18n.t("week")}
@ -218,12 +217,12 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_month", { data-tippy-content={i18n.t("active_users_in_the_last_month", {
count: counts.users_active_month, count: Number(counts.users_active_month),
formattedCount: counts.users_active_month, formattedCount: numToSI(counts.users_active_month),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_month, count: Number(counts.users_active_month),
formattedCount: numToSI(counts.users_active_month), formattedCount: numToSI(counts.users_active_month),
})}{" "} })}{" "}
/ {i18n.t("month")} / {i18n.t("month")}
@ -231,31 +230,31 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_six_months", { data-tippy-content={i18n.t("active_users_in_the_last_six_months", {
count: counts.users_active_half_year, count: Number(counts.users_active_half_year),
formattedCount: counts.users_active_half_year, formattedCount: numToSI(counts.users_active_half_year),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_half_year, count: Number(counts.users_active_half_year),
formattedCount: numToSI(counts.users_active_half_year), formattedCount: numToSI(counts.users_active_half_year),
})}{" "} })}{" "}
/ {i18n.t("number_of_months", { count: 6, formattedCount: 6 })} / {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_subscribers", { {i18n.t("number_of_subscribers", {
count: counts.subscribers, count: Number(counts.subscribers),
formattedCount: numToSI(counts.subscribers), formattedCount: numToSI(counts.subscribers),
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_posts", { {i18n.t("number_of_posts", {
count: counts.posts, count: Number(counts.posts),
formattedCount: numToSI(counts.posts), formattedCount: numToSI(counts.posts),
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_comments", { {i18n.t("number_of_comments", {
count: counts.comments, count: Number(counts.comments),
formattedCount: numToSI(counts.comments), formattedCount: numToSI(counts.comments),
})} })}
</li> </li>
@ -302,7 +301,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
let community_view = this.props.community_view; let community_view = this.props.community_view;
return ( return (
<div className="mb-2"> <div className="mb-2">
{community_view.subscribed == SubscribedType.NotSubscribed && ( {community_view.subscribed == "NotSubscribed" && (
<button <button
className="btn btn-secondary btn-block" className="btn btn-secondary btn-block"
onClick={linkEvent(this, this.handleSubscribe)} onClick={linkEvent(this, this.handleSubscribe)}
@ -320,7 +319,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
return ( return (
<div className="mb-2"> <div className="mb-2">
{community_view.subscribed == SubscribedType.NotSubscribed && {community_view.subscribed == "NotSubscribed" &&
(blocked ? ( (blocked ? (
<button <button
className="btn btn-danger btn-block" className="btn btn-danger btn-block"

View file

@ -3,8 +3,9 @@ import { Component, linkEvent } from "inferno";
import { import {
BannedPersonsResponse, BannedPersonsResponse,
GetBannedPersons, GetBannedPersons,
GetFederatedInstancesResponse,
GetSiteResponse, GetSiteResponse,
PersonViewSafe, PersonView,
SiteResponse, SiteResponse,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
@ -34,7 +35,8 @@ import { TaglineForm } from "./tagline-form";
interface AdminSettingsState { interface AdminSettingsState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
banned: PersonViewSafe[]; instancesRes?: GetFederatedInstancesResponse;
banned: PersonView[];
loading: boolean; loading: boolean;
leaveAdminTeamLoading: boolean; leaveAdminTeamLoading: boolean;
currentTab: string; currentTab: string;
@ -63,6 +65,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state = { this.state = {
...this.state, ...this.state,
banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned, banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned,
instancesRes: this.isoData
.routeData[1] as GetFederatedInstancesResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -73,6 +77,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
auth: cAuth, auth: cAuth,
}) })
); );
WebSocketService.Instance.send(
wsClient.getFederatedInstances({ auth: cAuth })
);
} }
} }
} }
@ -84,6 +91,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
if (auth) { if (auth) {
let bannedPersonsForm: GetBannedPersons = { auth }; let bannedPersonsForm: GetBannedPersons = { auth };
promises.push(req.client.getBannedPersons(bannedPersonsForm)); promises.push(req.client.getBannedPersons(bannedPersonsForm));
promises.push(req.client.getFederatedInstances({ auth }));
} }
return promises; return promises;
@ -167,6 +175,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<div className="col-12 col-md-6"> <div className="col-12 col-md-6">
<SiteForm <SiteForm
siteRes={this.state.siteRes} siteRes={this.state.siteRes}
instancesRes={this.state.instancesRes}
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
/> />
</div> </div>
@ -269,9 +278,11 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
let data = wsJsonToRes<GetSiteResponse>(msg); let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState(s => ((s.siteRes.site_view = data.site_view), s)); this.setState(s => ((s.siteRes.site_view = data.site_view), s));
this.setState({ leaveAdminTeamLoading: false }); this.setState({ leaveAdminTeamLoading: false });
toast(i18n.t("left_admin_team")); toast(i18n.t("left_admin_team"));
this.context.router.history.push("/"); this.context.router.history.push("/");
} else if (op == UserOperation.GetFederatedInstances) {
let data = wsJsonToRes<GetFederatedInstancesResponse>(msg);
this.setState({ instancesRes: data });
} }
} }
} }

View file

@ -1,17 +1,15 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import {
GetSiteResponse,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "lemmy-js-client";
import { import {
CreateCustomEmoji, CreateCustomEmoji,
CustomEmojiResponse, CustomEmojiResponse,
DeleteCustomEmoji, DeleteCustomEmoji,
DeleteCustomEmojiResponse, DeleteCustomEmojiResponse,
EditCustomEmoji, EditCustomEmoji,
} from "lemmy-js-client/dist/interfaces/api/custom_emoji"; GetSiteResponse,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "lemmy-js-client";
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
@ -37,7 +35,7 @@ interface EmojiFormState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
customEmojis: CustomEmojiViewForm[]; customEmojis: CustomEmojiViewForm[];
loading: boolean; loading: boolean;
page: number; page: bigint;
} }
interface CustomEmojiViewForm { interface CustomEmojiViewForm {
@ -48,7 +46,7 @@ interface CustomEmojiViewForm {
alt_text: string; alt_text: string;
keywords: string; keywords: string;
changed: boolean; changed: boolean;
page: number; page: bigint;
} }
export class EmojiForm extends Component<any, EmojiFormState> { export class EmojiForm extends Component<any, EmojiFormState> {
@ -66,9 +64,9 @@ export class EmojiForm extends Component<any, EmojiFormState> {
alt_text: x.custom_emoji.alt_text, alt_text: x.custom_emoji.alt_text,
keywords: x.keywords.map(x => x.keyword).join(" "), keywords: x.keywords.map(x => x.keyword).join(" "),
changed: false, changed: false,
page: 1 + Math.floor(index / this.itemsPerPage), page: BigInt(1 + Math.floor(index / this.itemsPerPage)),
})), })),
page: 1, page: 1n,
}; };
state: EmojiFormState; state: EmojiFormState;
private scrollRef: any = {}; private scrollRef: any = {};
@ -127,8 +125,11 @@ export class EmojiForm extends Component<any, EmojiFormState> {
<tbody> <tbody>
{this.state.customEmojis {this.state.customEmojis
.slice( .slice(
(this.state.page - 1) * this.itemsPerPage, Number((this.state.page - 1n) * BigInt(this.itemsPerPage)),
(this.state.page - 1) * this.itemsPerPage + this.itemsPerPage Number(
(this.state.page - 1n) * BigInt(this.itemsPerPage) +
BigInt(this.itemsPerPage)
)
) )
.map((cv, index) => ( .map((cv, index) => (
<tr key={index} ref={e => (this.scrollRef[cv.shortcode] = e)}> <tr key={index} ref={e => (this.scrollRef[cv.shortcode] = e)}>
@ -303,7 +304,7 @@ export class EmojiForm extends Component<any, EmojiFormState> {
else return i18n.t("custom_emoji_save_validation"); else return i18n.t("custom_emoji_save_validation");
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.setState({ page: page }); this.setState({ page: page });
} }
@ -326,13 +327,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) { ) {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
let item = { let item = {
...props.form.state.customEmojis[pagedIndex], ...props.form.state.customEmojis[Number(pagedIndex)],
category: event.target.value, category: event.target.value,
changed: true, changed: true,
}; };
custom_emojis[pagedIndex] = item; custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
@ -342,13 +344,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) { ) {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
let item = { let item = {
...props.form.state.customEmojis[pagedIndex], ...props.form.state.customEmojis[Number(pagedIndex)],
shortcode: event.target.value, shortcode: event.target.value,
changed: true, changed: true,
}; };
custom_emojis[pagedIndex] = item; custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
@ -358,13 +361,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) { ) {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
let item = { let item = {
...props.form.state.customEmojis[pagedIndex], ...props.form.state.customEmojis[Number(pagedIndex)],
image_url: props.overrideValue ?? event.target.value, image_url: props.overrideValue ?? event.target.value,
changed: true, changed: true,
}; };
custom_emojis[pagedIndex] = item; custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
@ -374,13 +378,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) { ) {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
let item = { let item = {
...props.form.state.customEmojis[pagedIndex], ...props.form.state.customEmojis[Number(pagedIndex)],
alt_text: event.target.value, alt_text: event.target.value,
changed: true, changed: true,
}; };
custom_emojis[pagedIndex] = item; custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
@ -390,13 +395,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) { ) {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
let item = { let item = {
...props.form.state.customEmojis[pagedIndex], ...props.form.state.customEmojis[Number(pagedIndex)],
keywords: event.target.value, keywords: event.target.value,
changed: true, changed: true,
}; };
custom_emojis[pagedIndex] = item; custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
@ -406,7 +412,8 @@ export class EmojiForm extends Component<any, EmojiFormState> {
cv: CustomEmojiViewForm; cv: CustomEmojiViewForm;
}) { }) {
let pagedIndex = let pagedIndex =
(props.form.state.page - 1) * props.form.itemsPerPage + props.index; (props.form.state.page - 1n) * BigInt(props.form.itemsPerPage) +
BigInt(props.index);
if (props.cv.id != 0) { if (props.cv.id != 0) {
const deleteForm: DeleteCustomEmoji = { const deleteForm: DeleteCustomEmoji = {
id: props.cv.id, id: props.cv.id,
@ -415,7 +422,7 @@ export class EmojiForm extends Component<any, EmojiFormState> {
WebSocketService.Instance.send(wsClient.deleteCustomEmoji(deleteForm)); WebSocketService.Instance.send(wsClient.deleteCustomEmoji(deleteForm));
} else { } else {
let custom_emojis = [...props.form.state.customEmojis]; let custom_emojis = [...props.form.state.customEmojis];
custom_emojis.splice(pagedIndex, 1); custom_emojis.splice(Number(pagedIndex), 1);
props.form.setState({ customEmojis: custom_emojis }); props.form.setState({ customEmojis: custom_emojis });
} }
} }
@ -451,8 +458,9 @@ export class EmojiForm extends Component<any, EmojiFormState> {
handleAddEmojiClick(form: EmojiForm, event: any) { handleAddEmojiClick(form: EmojiForm, event: any) {
event.preventDefault(); event.preventDefault();
let custom_emojis = [...form.state.customEmojis]; let custom_emojis = [...form.state.customEmojis];
const page = const page = BigInt(
1 + Math.floor(form.state.customEmojis.length / form.itemsPerPage); 1 + Math.floor(form.state.customEmojis.length / form.itemsPerPage)
);
let item: CustomEmojiViewForm = { let item: CustomEmojiViewForm = {
id: 0, id: 0,
shortcode: "", shortcode: "",

View file

@ -61,9 +61,6 @@ import {
QueryParams, QueryParams,
relTags, relTags,
restoreScrollPosition, restoreScrollPosition,
routeDataTypeToEnum,
routeListingTypeToEnum,
routeSortTypeToEnum,
saveCommentRes, saveCommentRes,
saveScrollPosition, saveScrollPosition,
setIsoData, setIsoData,
@ -103,36 +100,27 @@ interface HomeProps {
listingType: ListingType; listingType: ListingType;
dataType: DataType; dataType: DataType;
sort: SortType; sort: SortType;
page: number; page: bigint;
} }
const getDataTypeFromQuery = (type?: string) => function getDataTypeFromQuery(type?: string): DataType {
routeDataTypeToEnum(type ?? "", DataType.Post); return type ? DataType[type] : DataType.Post;
function getListingTypeFromQuery(type?: string) {
const mui = UserService.Instance.myUserInfo;
return routeListingTypeToEnum(
type ?? "",
mui
? Object.values(ListingType)[
mui.local_user_view.local_user.default_listing_type
]
: ListingType.Local
);
} }
function getSortTypeFromQuery(type?: string) { function getListingTypeFromQuery(type?: string): ListingType {
const mui = UserService.Instance.myUserInfo; const myListingType =
UserService.Instance.myUserInfo?.local_user_view?.local_user
?.default_listing_type;
return routeSortTypeToEnum( return type ? (type as ListingType) : myListingType ?? "Local";
type ?? "", }
mui
? Object.values(SortType)[ function getSortTypeFromQuery(type?: string): SortType {
mui.local_user_view.local_user.default_listing_type const mySortType =
] UserService.Instance.myUserInfo?.local_user_view?.local_user
: SortType.Active ?.default_sort_type;
);
return type ? (type as SortType) : mySortType ?? "Active";
} }
const getHomeQueryParams = () => const getHomeQueryParams = () =>
@ -145,8 +133,8 @@ const getHomeQueryParams = () =>
function fetchTrendingCommunities() { function fetchTrendingCommunities() {
const listCommunitiesForm: ListCommunities = { const listCommunitiesForm: ListCommunities = {
type_: ListingType.Local, type_: "Local",
sort: SortType.Hot, sort: "Hot",
limit: trendingFetchLimit, limit: trendingFetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -222,15 +210,15 @@ function getRss(listingType: ListingType) {
let rss: string | undefined = undefined; let rss: string | undefined = undefined;
switch (listingType) { switch (listingType) {
case ListingType.All: { case "All": {
rss = `/feeds/all.xml?sort=${sort}`; rss = `/feeds/all.xml?sort=${sort}`;
break; break;
} }
case ListingType.Local: { case "Local": {
rss = `/feeds/local.xml?sort=${sort}`; rss = `/feeds/local.xml?sort=${sort}`;
break; break;
} }
case ListingType.Subscribed: { case "Subscribed": {
rss = auth ? `/feeds/front/${auth}.xml?sort=${sort}` : undefined; rss = auth ? `/feeds/front/${auth}.xml?sort=${sort}` : undefined;
break; break;
} }
@ -336,7 +324,7 @@ export class Home extends Component<any, HomeState> {
const type_ = getListingTypeFromQuery(listingType); const type_ = getListingTypeFromQuery(listingType);
const sort = getSortTypeFromQuery(urlSort); const sort = getSortTypeFromQuery(urlSort);
const page = urlPage ? Number(urlPage) : 1; const page = urlPage ? BigInt(urlPage) : 1n;
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
@ -366,8 +354,8 @@ export class Home extends Component<any, HomeState> {
} }
const trendingCommunitiesForm: ListCommunities = { const trendingCommunitiesForm: ListCommunities = {
type_: ListingType.Local, type_: "Local",
sort: SortType.Hot, sort: "Hot",
limit: trendingFetchLimit, limit: trendingFetchLimit,
auth, auth,
}; };
@ -712,23 +700,23 @@ export class Home extends Component<any, HomeState> {
i.setState({ subscribedCollapsed: !i.state.subscribedCollapsed }); i.setState({ subscribedCollapsed: !i.state.subscribedCollapsed });
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
handleSortChange(val: SortType) { handleSortChange(val: SortType) {
this.updateUrl({ sort: val, page: 1 }); this.updateUrl({ sort: val, page: 1n });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
handleListingTypeChange(val: ListingType) { handleListingTypeChange(val: ListingType) {
this.updateUrl({ listingType: val, page: 1 }); this.updateUrl({ listingType: val, page: 1n });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
handleDataTypeChange(val: DataType) { handleDataTypeChange(val: DataType) {
this.updateUrl({ dataType: val, page: 1 }); this.updateUrl({ dataType: val, page: 1n });
window.scrollTo(0, 0); window.scrollTo(0, 0);
} }
@ -777,21 +765,25 @@ export class Home extends Component<any, HomeState> {
const { post_view } = wsJsonToRes<PostResponse>(msg); const { post_view } = wsJsonToRes<PostResponse>(msg);
// Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked // Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked
if (page === 1 && nsfwCheck(post_view) && !isPostBlocked(post_view)) { if (
page === 1n &&
nsfwCheck(post_view) &&
!isPostBlocked(post_view)
) {
const mui = UserService.Instance.myUserInfo; const mui = UserService.Instance.myUserInfo;
const showPostNotifs = const showPostNotifs =
mui?.local_user_view.local_user.show_new_post_notifs; mui?.local_user_view.local_user.show_new_post_notifs;
let shouldAddPost: boolean; let shouldAddPost: boolean;
switch (listingType) { switch (listingType) {
case ListingType.Subscribed: { case "Subscribed": {
// If you're on subscribed, only push it if you're subscribed. // If you're on subscribed, only push it if you're subscribed.
shouldAddPost = !!mui?.follows.some( shouldAddPost = !!mui?.follows.some(
({ community: { id } }) => id === post_view.community.id ({ community: { id } }) => id === post_view.community.id
); );
break; break;
} }
case ListingType.Local: { case "Local": {
// If you're on the local view, only push it if its local // If you're on the local view, only push it if its local
shouldAddPost = post_view.post.local; shouldAddPost = post_view.post.local;
break; break;
@ -885,7 +877,7 @@ export class Home extends Component<any, HomeState> {
// If you're on subscribed, only push it if you're subscribed. // If you're on subscribed, only push it if you're subscribed.
const shouldAddComment = const shouldAddComment =
listingType === ListingType.Subscribed listingType === "Subscribed"
? UserService.Instance.myUserInfo?.follows.some( ? UserService.Instance.myUserInfo?.follows.some(
({ community: { id } }) => id === comment_view.community.id ({ community: { id } }) => id === comment_view.community.id
) )

View file

@ -1,29 +1,79 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client"; import {
GetFederatedInstancesResponse,
GetSiteResponse,
Instance,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "lemmy-js-client";
import { Subscription } from "rxjs";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { relTags, setIsoData } from "../../utils"; import { InitialFetchRequest } from "../../interfaces";
import { WebSocketService } from "../../services";
import {
isBrowser,
relTags,
setIsoData,
toast,
wsClient,
wsSubscribe,
} from "../../utils";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
interface InstancesState { interface InstancesState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
instancesRes?: GetFederatedInstancesResponse;
loading: boolean;
} }
export class Instances extends Component<any, InstancesState> { export class Instances extends Component<any, InstancesState> {
private isoData = setIsoData(this.context); private isoData = setIsoData(this.context);
state: InstancesState = { state: InstancesState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: true,
}; };
private subscription?: Subscription;
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
instancesRes: this.isoData
.routeData[0] as GetFederatedInstancesResponse,
loading: false,
};
} else {
WebSocketService.Instance.send(wsClient.getFederatedInstances({}));
}
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = [];
promises.push(req.client.getFederatedInstances({}));
return promises;
} }
get documentTitle(): string { get documentTitle(): string {
return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`; return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
} }
componentWillUnmount() {
if (isBrowser()) {
this.subscription?.unsubscribe();
}
}
render() { render() {
let federated_instances = this.state.siteRes.federated_instances; let federated_instances = this.state.instancesRes?.federated_instances;
return federated_instances ? ( return federated_instances ? (
<div className="container-lg"> <div className="container-lg">
<HtmlTags <HtmlTags
@ -56,20 +106,47 @@ export class Instances extends Component<any, InstancesState> {
); );
} }
itemList(items: string[]) { itemList(items: Instance[]) {
let noneFound = <div>{i18n.t("none_found")}</div>;
return items.length > 0 ? ( return items.length > 0 ? (
<ul> <div className="table-responsive">
<table id="instances_table" className="table table-sm table-hover">
<thead className="pointer">
<tr>
<th>{i18n.t("name")}</th>
<th>{i18n.t("software")}</th>
<th>{i18n.t("version")}</th>
</tr>
</thead>
<tbody>
{items.map(i => ( {items.map(i => (
<li key={i}> <tr key={i.domain}>
<a href={`https://${i}`} rel={relTags}> <td>
{i} <a href={`https://${i.domain}`} rel={relTags}>
{i.domain}
</a> </a>
</li> </td>
<td>{i.software}</td>
<td>{i.version}</td>
</tr>
))} ))}
</ul> </tbody>
</table>
</div>
) : ( ) : (
noneFound <div>{i18n.t("none_found")}</div>
); );
} }
parseMessage(msg: any) {
let op = wsUserOp(msg);
console.log(msg);
if (msg.error) {
toast(i18n.t(msg.error), "danger");
this.context.router.history.push("/");
this.setState({ loading: false });
return;
} else if (op == UserOperation.GetFederatedInstances) {
let data = wsJsonToRes<GetFederatedInstancesResponse>(msg);
this.setState({ loading: false, instancesRes: data });
}
}
} }

View file

@ -51,7 +51,7 @@ export class Login extends Component<any, State> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (isBrowser()) { if (isBrowser()) {
WebSocketService.Instance.send(wsClient.getCaptcha()); WebSocketService.Instance.send(wsClient.getCaptcha({}));
} }
} }

View file

@ -8,7 +8,6 @@ import {
GetSiteResponse, GetSiteResponse,
LoginResponse, LoginResponse,
Register, Register,
RegistrationMode,
SiteView, SiteView,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
@ -99,7 +98,7 @@ export class Signup extends Component<any, State> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (isBrowser()) { if (isBrowser()) {
WebSocketService.Instance.send(wsClient.getCaptcha()); WebSocketService.Instance.send(wsClient.getCaptcha({}));
} }
} }
@ -258,8 +257,7 @@ export class Signup extends Component<any, State> {
</div> </div>
</div> </div>
{siteView.local_site.registration_mode == {siteView.local_site.registration_mode == "RequireApplication" && (
RegistrationMode.RequireApplication && (
<> <>
<div className="form-group row"> <div className="form-group row">
<div className="offset-sm-2 col-sm-10"> <div className="offset-sm-2 col-sm-10">
@ -486,7 +484,7 @@ export class Signup extends Component<any, State> {
handleRegenCaptcha(i: Signup) { handleRegenCaptcha(i: Signup) {
i.audio = undefined; i.audio = undefined;
i.setState({ captchaPlaying: false }); i.setState({ captchaPlaying: false });
WebSocketService.Instance.send(wsClient.getCaptcha()); WebSocketService.Instance.send(wsClient.getCaptcha({}));
} }
handleCaptchaPlay(i: Signup) { handleCaptchaPlay(i: Signup) {

View file

@ -3,9 +3,9 @@ import { Prompt } from "inferno-router";
import { import {
CreateSite, CreateSite,
EditSite, EditSite,
GetFederatedInstancesResponse,
GetSiteResponse, GetSiteResponse,
ListingType, ListingType,
RegistrationMode,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
@ -23,6 +23,7 @@ import { MarkdownTextArea } from "../common/markdown-textarea";
interface SiteFormProps { interface SiteFormProps {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
instancesRes?: GetFederatedInstancesResponse;
showLocal?: boolean; showLocal?: boolean;
} }
@ -104,8 +105,14 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
federation_worker_count: ls.federation_worker_count, federation_worker_count: ls.federation_worker_count,
captcha_enabled: ls.captcha_enabled, captcha_enabled: ls.captcha_enabled,
captcha_difficulty: ls.captcha_difficulty, captcha_difficulty: ls.captcha_difficulty,
allowed_instances: this.props.siteRes.federated_instances?.allowed, allowed_instances:
blocked_instances: this.props.siteRes.federated_instances?.blocked, this.props.instancesRes?.federated_instances?.allowed.map(
i => i.domain
),
blocked_instances:
this.props.instancesRes?.federated_instances?.blocked.map(
i => i.domain
),
auth: "TODO", auth: "TODO",
}, },
}; };
@ -295,20 +302,15 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
)} )}
className="custom-select w-auto" className="custom-select w-auto"
> >
<option value={RegistrationMode.RequireApplication}> <option value={"RequireApplication"}>
{i18n.t("require_registration_application")} {i18n.t("require_registration_application")}
</option> </option>
<option value={RegistrationMode.Open}> <option value={"Open"}>{i18n.t("open_registration")}</option>
{i18n.t("open_registration")} <option value={"Closed"}>{i18n.t("close_registration")}</option>
</option>
<option value={RegistrationMode.Closed}>
{i18n.t("close_registration")}
</option>
</select> </select>
</div> </div>
</div> </div>
{this.state.siteForm.registration_mode == {this.state.siteForm.registration_mode == "RequireApplication" && (
RegistrationMode.RequireApplication && (
<div className="form-group row"> <div className="form-group row">
<label className="col-12 col-form-label"> <label className="col-12 col-form-label">
{i18n.t("application_questionnaire")} {i18n.t("application_questionnaire")}
@ -438,9 +440,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<div className="col-sm-9"> <div className="col-sm-9">
<ListingTypeSelect <ListingTypeSelect
type_={ type_={
ListingType[
this.state.siteForm.default_post_listing_type ?? "Local" this.state.siteForm.default_post_listing_type ?? "Local"
]
} }
showLocal showLocal
showSubscribed={false} showSubscribed={false}
@ -1256,12 +1256,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
} }
handleDefaultPostListingTypeChange(val: ListingType) { handleDefaultPostListingTypeChange(val: ListingType) {
this.setState( this.setState(s => ((s.siteForm.default_post_listing_type = val), s));
s => (
(s.siteForm.default_post_listing_type = ListingType[ListingType[val]]),
s
)
);
} }
} }

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client"; import { PersonView, Site, SiteAggregates } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { mdToHtml, numToSI } from "../../utils"; import { mdToHtml, numToSI } from "../../utils";
import { BannerIconHeader } from "../common/banner-icon-header"; import { BannerIconHeader } from "../common/banner-icon-header";
@ -11,7 +11,7 @@ interface SiteSidebarProps {
site: Site; site: Site;
showLocal: boolean; showLocal: boolean;
counts?: SiteAggregates; counts?: SiteAggregates;
admins?: PersonViewSafe[]; admins?: PersonView[];
online?: number; online?: number;
} }
@ -84,7 +84,7 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
); );
} }
admins(admins: PersonViewSafe[]) { admins(admins: PersonView[]) {
return ( return (
<ul className="mt-1 list-inline small mb-0"> <ul className="mt-1 list-inline small mb-0">
<li className="list-inline-item">{i18n.t("admins")}:</li> <li className="list-inline-item">{i18n.t("admins")}:</li>
@ -105,18 +105,18 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_online", { {i18n.t("number_online", {
count: online, count: online,
formattedCount: numToSI(online), formattedCount: numToSI(BigInt(online)),
})} })}
</li> </li>
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_day", { data-tippy-content={i18n.t("active_users_in_the_last_day", {
count: counts.users_active_day, count: Number(counts.users_active_day),
formattedCount: numToSI(counts.users_active_day), formattedCount: numToSI(counts.users_active_day),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_day, count: Number(counts.users_active_day),
formattedCount: numToSI(counts.users_active_day), formattedCount: numToSI(counts.users_active_day),
})}{" "} })}{" "}
/ {i18n.t("day")} / {i18n.t("day")}
@ -124,12 +124,12 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_week", { data-tippy-content={i18n.t("active_users_in_the_last_week", {
count: counts.users_active_week, count: Number(counts.users_active_week),
formattedCount: counts.users_active_week, formattedCount: numToSI(counts.users_active_week),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_week, count: Number(counts.users_active_week),
formattedCount: numToSI(counts.users_active_week), formattedCount: numToSI(counts.users_active_week),
})}{" "} })}{" "}
/ {i18n.t("week")} / {i18n.t("week")}
@ -137,12 +137,12 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_month", { data-tippy-content={i18n.t("active_users_in_the_last_month", {
count: counts.users_active_month, count: Number(counts.users_active_month),
formattedCount: counts.users_active_month, formattedCount: numToSI(counts.users_active_month),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_month, count: Number(counts.users_active_month),
formattedCount: numToSI(counts.users_active_month), formattedCount: numToSI(counts.users_active_month),
})}{" "} })}{" "}
/ {i18n.t("month")} / {i18n.t("month")}
@ -150,37 +150,37 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
<li <li
className="list-inline-item badge badge-secondary pointer" className="list-inline-item badge badge-secondary pointer"
data-tippy-content={i18n.t("active_users_in_the_last_six_months", { data-tippy-content={i18n.t("active_users_in_the_last_six_months", {
count: counts.users_active_half_year, count: Number(counts.users_active_half_year),
formattedCount: counts.users_active_half_year, formattedCount: numToSI(counts.users_active_half_year),
})} })}
> >
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users_active_half_year, count: Number(counts.users_active_half_year),
formattedCount: numToSI(counts.users_active_half_year), formattedCount: numToSI(counts.users_active_half_year),
})}{" "} })}{" "}
/ {i18n.t("number_of_months", { count: 6, formattedCount: 6 })} / {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_users", { {i18n.t("number_of_users", {
count: counts.users, count: Number(counts.users),
formattedCount: numToSI(counts.users), formattedCount: numToSI(counts.users),
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_communities", { {i18n.t("number_of_communities", {
count: counts.communities, count: Number(counts.communities),
formattedCount: numToSI(counts.communities), formattedCount: numToSI(counts.communities),
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_posts", { {i18n.t("number_of_posts", {
count: counts.posts, count: Number(counts.posts),
formattedCount: numToSI(counts.posts), formattedCount: numToSI(counts.posts),
})} })}
</li> </li>
<li className="list-inline-item badge badge-secondary"> <li className="list-inline-item badge badge-secondary">
{i18n.t("number_of_comments", { {i18n.t("number_of_comments", {
count: counts.comments, count: Number(counts.comments),
formattedCount: numToSI(counts.comments), formattedCount: numToSI(counts.comments),
})} })}
</li> </li>

View file

@ -26,7 +26,7 @@ import {
ModRemovePostView, ModRemovePostView,
ModTransferCommunityView, ModTransferCommunityView,
ModlogActionType, ModlogActionType,
PersonSafe, Person,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -86,7 +86,7 @@ type View =
interface ModlogType { interface ModlogType {
id: number; id: number;
type_: ModlogActionType; type_: ModlogActionType;
moderator?: PersonSafe; moderator?: Person;
view: View; view: View;
when_: string; when_: string;
} }
@ -111,23 +111,22 @@ interface ModlogState {
} }
interface ModlogProps { interface ModlogProps {
page: number; page: bigint;
userId?: number | null; userId?: number | null;
modId?: number | null; modId?: number | null;
actionType: ModlogActionType; actionType: ModlogActionType;
} }
const getActionFromString = (action?: string) => function getActionFromString(action?: string): ModlogActionType {
action return action !== undefined ? (action as ModlogActionType) : "All";
? ModlogActionType[action] ?? ModlogActionType.All }
: ModlogActionType.All;
const getModlogActionMapper = const getModlogActionMapper =
( (
actionType: ModlogActionType, actionType: ModlogActionType,
getAction: (view: View) => { id: number; when_: string } getAction: (view: View) => { id: number; when_: string }
) => ) =>
(view: View & { moderator?: PersonSafe; admin?: PersonSafe }): ModlogType => { (view: View & { moderator?: Person; admin?: Person }): ModlogType => {
const { id, when_ } = getAction(view); const { id, when_ } = getAction(view);
return { return {
@ -158,14 +157,14 @@ function buildCombined({
const combined = removed_posts const combined = removed_posts
.map( .map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModRemovePost, "ModRemovePost",
({ mod_remove_post }: ModRemovePostView) => mod_remove_post ({ mod_remove_post }: ModRemovePostView) => mod_remove_post
) )
) )
.concat( .concat(
locked_posts.map( locked_posts.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModLockPost, "ModLockPost",
({ mod_lock_post }: ModLockPostView) => mod_lock_post ({ mod_lock_post }: ModLockPostView) => mod_lock_post
) )
) )
@ -173,7 +172,7 @@ function buildCombined({
.concat( .concat(
featured_posts.map( featured_posts.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModFeaturePost, "ModFeaturePost",
({ mod_feature_post }: ModFeaturePostView) => mod_feature_post ({ mod_feature_post }: ModFeaturePostView) => mod_feature_post
) )
) )
@ -181,7 +180,7 @@ function buildCombined({
.concat( .concat(
removed_comments.map( removed_comments.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModRemoveComment, "ModRemoveComment",
({ mod_remove_comment }: ModRemoveCommentView) => mod_remove_comment ({ mod_remove_comment }: ModRemoveCommentView) => mod_remove_comment
) )
) )
@ -189,7 +188,7 @@ function buildCombined({
.concat( .concat(
removed_communities.map( removed_communities.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModRemoveCommunity, "ModRemoveCommunity",
({ mod_remove_community }: ModRemoveCommunityView) => ({ mod_remove_community }: ModRemoveCommunityView) =>
mod_remove_community mod_remove_community
) )
@ -198,7 +197,7 @@ function buildCombined({
.concat( .concat(
banned_from_community.map( banned_from_community.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModBanFromCommunity, "ModBanFromCommunity",
({ mod_ban_from_community }: ModBanFromCommunityView) => ({ mod_ban_from_community }: ModBanFromCommunityView) =>
mod_ban_from_community mod_ban_from_community
) )
@ -207,7 +206,7 @@ function buildCombined({
.concat( .concat(
added_to_community.map( added_to_community.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModAddCommunity, "ModAddCommunity",
({ mod_add_community }: ModAddCommunityView) => mod_add_community ({ mod_add_community }: ModAddCommunityView) => mod_add_community
) )
) )
@ -215,7 +214,7 @@ function buildCombined({
.concat( .concat(
transferred_to_community.map( transferred_to_community.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.ModTransferCommunity, "ModTransferCommunity",
({ mod_transfer_community }: ModTransferCommunityView) => ({ mod_transfer_community }: ModTransferCommunityView) =>
mod_transfer_community mod_transfer_community
) )
@ -223,24 +222,18 @@ function buildCombined({
) )
.concat( .concat(
added.map( added.map(
getModlogActionMapper( getModlogActionMapper("ModAdd", ({ mod_add }: ModAddView) => mod_add)
ModlogActionType.ModAdd,
({ mod_add }: ModAddView) => mod_add
)
) )
) )
.concat( .concat(
banned.map( banned.map(
getModlogActionMapper( getModlogActionMapper("ModBan", ({ mod_ban }: ModBanView) => mod_ban)
ModlogActionType.ModBan,
({ mod_ban }: ModBanView) => mod_ban
)
) )
) )
.concat( .concat(
admin_purged_persons.map( admin_purged_persons.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.AdminPurgePerson, "AdminPurgePerson",
({ admin_purge_person }: AdminPurgePersonView) => admin_purge_person ({ admin_purge_person }: AdminPurgePersonView) => admin_purge_person
) )
) )
@ -248,7 +241,7 @@ function buildCombined({
.concat( .concat(
admin_purged_communities.map( admin_purged_communities.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.AdminPurgeCommunity, "AdminPurgeCommunity",
({ admin_purge_community }: AdminPurgeCommunityView) => ({ admin_purge_community }: AdminPurgeCommunityView) =>
admin_purge_community admin_purge_community
) )
@ -257,7 +250,7 @@ function buildCombined({
.concat( .concat(
admin_purged_posts.map( admin_purged_posts.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.AdminPurgePost, "AdminPurgePost",
({ admin_purge_post }: AdminPurgePostView) => admin_purge_post ({ admin_purge_post }: AdminPurgePostView) => admin_purge_post
) )
) )
@ -265,7 +258,7 @@ function buildCombined({
.concat( .concat(
admin_purged_comments.map( admin_purged_comments.map(
getModlogActionMapper( getModlogActionMapper(
ModlogActionType.AdminPurgeComment, "AdminPurgeComment",
({ admin_purge_comment }: AdminPurgeCommentView) => ({ admin_purge_comment }: AdminPurgeCommentView) =>
admin_purge_comment admin_purge_comment
) )
@ -280,7 +273,7 @@ function buildCombined({
function renderModlogType({ type_, view }: ModlogType) { function renderModlogType({ type_, view }: ModlogType) {
switch (type_) { switch (type_) {
case ModlogActionType.ModRemovePost: { case "ModRemovePost": {
const mrpv = view as ModRemovePostView; const mrpv = view as ModRemovePostView;
const { const {
mod_remove_post: { reason, removed }, mod_remove_post: { reason, removed },
@ -302,7 +295,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModLockPost: { case "ModLockPost": {
const { const {
mod_lock_post: { locked }, mod_lock_post: { locked },
post: { id, name }, post: { id, name },
@ -318,7 +311,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModFeaturePost: { case "ModFeaturePost": {
const { const {
mod_feature_post: { featured, is_featured_community }, mod_feature_post: { featured, is_featured_community },
post: { id, name }, post: { id, name },
@ -334,7 +327,7 @@ function renderModlogType({ type_, view }: ModlogType) {
</> </>
); );
} }
case ModlogActionType.ModRemoveComment: { case "ModRemoveComment": {
const mrc = view as ModRemoveCommentView; const mrc = view as ModRemoveCommentView;
const { const {
mod_remove_comment: { reason, removed }, mod_remove_comment: { reason, removed },
@ -361,7 +354,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModRemoveCommunity: { case "ModRemoveCommunity": {
const mrco = view as ModRemoveCommunityView; const mrco = view as ModRemoveCommunityView;
const { const {
mod_remove_community: { reason, expires, removed }, mod_remove_community: { reason, expires, removed },
@ -388,7 +381,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModBanFromCommunity: { case "ModBanFromCommunity": {
const mbfc = view as ModBanFromCommunityView; const mbfc = view as ModBanFromCommunityView;
const { const {
mod_ban_from_community: { reason, expires, banned }, mod_ban_from_community: { reason, expires, banned },
@ -420,7 +413,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModAddCommunity: { case "ModAddCommunity": {
const { const {
mod_add_community: { removed }, mod_add_community: { removed },
modded_person, modded_person,
@ -441,16 +434,12 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModTransferCommunity: { case "ModTransferCommunity": {
const { const { community, modded_person } = view as ModTransferCommunityView;
mod_transfer_community: { removed },
community,
modded_person,
} = view as ModTransferCommunityView;
return ( return (
<> <>
<span>{removed ? "Removed " : "Transferred "}</span> <span>Transferred</span>
<span> <span>
<CommunityLink community={community} /> <CommunityLink community={community} />
</span> </span>
@ -462,7 +451,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModBan: { case "ModBan": {
const { const {
mod_ban: { reason, expires, banned }, mod_ban: { reason, expires, banned },
banned_person, banned_person,
@ -488,7 +477,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.ModAdd: { case "ModAdd": {
const { const {
mod_add: { removed }, mod_add: { removed },
modded_person, modded_person,
@ -504,7 +493,7 @@ function renderModlogType({ type_, view }: ModlogType) {
</> </>
); );
} }
case ModlogActionType.AdminPurgePerson: { case "AdminPurgePerson": {
const { const {
admin_purge_person: { reason }, admin_purge_person: { reason },
} = view as AdminPurgePersonView; } = view as AdminPurgePersonView;
@ -521,7 +510,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.AdminPurgeCommunity: { case "AdminPurgeCommunity": {
const { const {
admin_purge_community: { reason }, admin_purge_community: { reason },
} = view as AdminPurgeCommunityView; } = view as AdminPurgeCommunityView;
@ -538,7 +527,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.AdminPurgePost: { case "AdminPurgePost": {
const { const {
admin_purge_post: { reason }, admin_purge_post: { reason },
community, community,
@ -557,7 +546,7 @@ function renderModlogType({ type_, view }: ModlogType) {
); );
} }
case ModlogActionType.AdminPurgeComment: { case "AdminPurgeComment": {
const { const {
admin_purge_comment: { reason }, admin_purge_comment: { reason },
post: { id, name }, post: { id, name },
@ -641,7 +630,7 @@ async function createNewOptions({
if (text.length > 0) { if (text.length > 0) {
newOptions.push( newOptions.push(
...(await fetchUsers(text)).users ...(await fetchUsers(text)).users
.slice(0, fetchLimit) .slice(0, Number(fetchLimit))
.map<Choice>(personToChoice) .map<Choice>(personToChoice)
); );
} }
@ -751,7 +740,7 @@ export class Modlog extends Component<
return amAdmin() || amMod(this.state.communityMods); return amAdmin() || amMod(this.state.communityMods);
} }
modOrAdminText(person?: PersonSafe): string { modOrAdminText(person?: Person): string {
return person && return person &&
this.isoData.site_res.admins.some( this.isoData.site_res.admins.some(
({ person: { id } }) => id === person.id ({ person: { id } }) => id === person.id
@ -814,35 +803,21 @@ export class Modlog extends Component<
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t("filter_by_action")} {i18n.t("filter_by_action")}
</option> </option>
<option value={ModlogActionType.All}>{i18n.t("all")}</option> <option value={"All"}>{i18n.t("all")}</option>
<option value={ModlogActionType.ModRemovePost}> <option value={"ModRemovePost"}>Removing Posts</option>
Removing Posts <option value={"ModLockPost"}>Locking Posts</option>
</option> <option value={"ModFeaturePost"}>Featuring Posts</option>
<option value={ModlogActionType.ModLockPost}> <option value={"ModRemoveComment"}>Removing Comments</option>
Locking Posts <option value={"ModRemoveCommunity"}>Removing Communities</option>
</option> <option value={"ModBanFromCommunity"}>
<option value={ModlogActionType.ModFeaturePost}>
Featuring Posts
</option>
<option value={ModlogActionType.ModRemoveComment}>
Removing Comments
</option>
<option value={ModlogActionType.ModRemoveCommunity}>
Removing Communities
</option>
<option value={ModlogActionType.ModBanFromCommunity}>
Banning From Communities Banning From Communities
</option> </option>
<option value={ModlogActionType.ModAddCommunity}> <option value={"ModAddCommunity"}>Adding Mod to Community</option>
Adding Mod to Community <option value={"ModTransferCommunity"}>
</option>
<option value={ModlogActionType.ModTransferCommunity}>
Transferring Communities Transferring Communities
</option> </option>
<option value={ModlogActionType.ModAdd}> <option value={"ModAdd"}>Adding Mod to Site</option>
Adding Mod to Site <option value={"ModBan"}>Banning From Site</option>
</option>
<option value={ModlogActionType.ModBan}>Banning From Site</option>
</select> </select>
</div> </div>
<div className="form-row mb-2"> <div className="form-row mb-2">
@ -892,21 +867,21 @@ export class Modlog extends Component<
handleFilterActionChange(i: Modlog, event: any) { handleFilterActionChange(i: Modlog, event: any) {
i.updateUrl({ i.updateUrl({
actionType: ModlogActionType[event.target.value], actionType: event.target.value as ModlogActionType,
page: 1, page: 1n,
}); });
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
} }
handleUserChange(option: Choice) { handleUserChange(option: Choice) {
this.updateUrl({ userId: getIdFromString(option.value) ?? null, page: 1 }); this.updateUrl({ userId: getIdFromString(option.value) ?? null, page: 1n });
} }
handleModChange(option: Choice) { handleModChange(option: Choice) {
this.updateUrl({ modId: getIdFromString(option.value) ?? null, page: 1 }); this.updateUrl({ modId: getIdFromString(option.value) ?? null, page: 1n });
} }
handleSearchUsers = debounce(async (text: string) => { handleSearchUsers = debounce(async (text: string) => {

View file

@ -84,7 +84,7 @@ interface InboxState {
messages: PrivateMessageView[]; messages: PrivateMessageView[];
combined: ReplyType[]; combined: ReplyType[];
sort: CommentSortType; sort: CommentSortType;
page: number; page: bigint;
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
loading: boolean; loading: boolean;
} }
@ -99,8 +99,8 @@ export class Inbox extends Component<any, InboxState> {
mentions: [], mentions: [],
messages: [], messages: [],
combined: [], combined: [],
sort: CommentSortType.New, sort: "New",
page: 1, page: 1n,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: true, loading: true,
}; };
@ -471,33 +471,33 @@ export class Inbox extends Component<any, InboxState> {
); );
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.setState({ page }); this.setState({ page });
this.refetch(); this.refetch();
} }
handleUnreadOrAllChange(i: Inbox, event: any) { handleUnreadOrAllChange(i: Inbox, event: any) {
i.setState({ unreadOrAll: Number(event.target.value), page: 1 }); i.setState({ unreadOrAll: Number(event.target.value), page: 1n });
i.refetch(); i.refetch();
} }
handleMessageTypeChange(i: Inbox, event: any) { handleMessageTypeChange(i: Inbox, event: any) {
i.setState({ messageType: Number(event.target.value), page: 1 }); i.setState({ messageType: Number(event.target.value), page: 1n });
i.refetch(); i.refetch();
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
let sort = CommentSortType.New; let sort: CommentSortType = "New";
let auth = req.auth; let auth = req.auth;
if (auth) { if (auth) {
// It can be /u/me, or /username/1 // It can be /u/me, or /username/1
let repliesForm: GetReplies = { let repliesForm: GetReplies = {
sort, sort: "New",
unread_only: true, unread_only: true,
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
@ -506,7 +506,7 @@ export class Inbox extends Component<any, InboxState> {
let personMentionsForm: GetPersonMentions = { let personMentionsForm: GetPersonMentions = {
sort, sort,
unread_only: true, unread_only: true,
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
@ -514,7 +514,7 @@ export class Inbox extends Component<any, InboxState> {
let privateMessagesForm: GetPrivateMessages = { let privateMessagesForm: GetPrivateMessages = {
unread_only: true, unread_only: true,
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
@ -565,7 +565,7 @@ export class Inbox extends Component<any, InboxState> {
} }
handleSortChange(val: CommentSortType) { handleSortChange(val: CommentSortType) {
this.setState({ sort: val, page: 1 }); this.setState({ sort: val, page: 1n });
this.refetch(); this.refetch();
} }
@ -579,7 +579,7 @@ export class Inbox extends Component<any, InboxState> {
); );
i.setState({ replies: [], mentions: [], messages: [] }); i.setState({ replies: [], mentions: [], messages: [] });
i.setState({ combined: i.buildCombined() }); i.setState({ combined: i.buildCombined() });
UserService.Instance.unreadInboxCountSub.next(0); UserService.Instance.unreadInboxCountSub.next(0n);
window.scrollTo(0, 0); window.scrollTo(0, 0);
i.setState(i.state); i.setState(i.state);
} }
@ -588,9 +588,9 @@ export class Inbox extends Component<any, InboxState> {
sendUnreadCount(read: boolean) { sendUnreadCount(read: boolean) {
let urcs = UserService.Instance.unreadInboxCountSub; let urcs = UserService.Instance.unreadInboxCountSub;
if (read) { if (read) {
urcs.next(urcs.getValue() - 1); urcs.next(urcs.getValue() - 1n);
} else { } else {
urcs.next(urcs.getValue() + 1); urcs.next(urcs.getValue() + 1n);
} }
} }

View file

@ -2,7 +2,7 @@ import { Component, linkEvent } from "inferno";
import { import {
GetSiteResponse, GetSiteResponse,
LoginResponse, LoginResponse,
PasswordChange as PWordChange, PasswordChangeAfterReset,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -147,7 +147,7 @@ export class PasswordChange extends Component<any, State> {
let password_verify = i.state.form.password_verify; let password_verify = i.state.form.password_verify;
if (password && password_verify) { if (password && password_verify) {
let form: PWordChange = { let form: PasswordChangeAfterReset = {
token: i.state.form.token, token: i.state.form.token,
password, password,
password_verify, password_verify,
@ -164,7 +164,7 @@ export class PasswordChange extends Component<any, State> {
toast(i18n.t(msg.error), "danger"); toast(i18n.t(msg.error), "danger");
this.setState({ loading: false }); this.setState({ loading: false });
return; return;
} else if (op == UserOperation.PasswordChange) { } else if (op == UserOperation.PasswordChangeAfterReset) {
let data = wsJsonToRes<LoginResponse>(msg); let data = wsJsonToRes<LoginResponse>(msg);
UserService.Instance.login(data); UserService.Instance.login(data);
this.props.history.push("/"); this.props.history.push("/");

View file

@ -3,7 +3,7 @@ import {
CommentView, CommentView,
GetPersonDetailsResponse, GetPersonDetailsResponse,
Language, Language,
PersonViewSafe, PersonView,
PostView, PostView,
SortType, SortType,
} from "lemmy-js-client"; } from "lemmy-js-client";
@ -15,16 +15,16 @@ import { PostListing } from "../post/post-listing";
interface PersonDetailsProps { interface PersonDetailsProps {
personRes: GetPersonDetailsResponse; personRes: GetPersonDetailsResponse;
admins: PersonViewSafe[]; admins: PersonView[];
allLanguages: Language[]; allLanguages: Language[];
siteLanguages: number[]; siteLanguages: number[];
page: number; page: bigint;
limit: number; limit: bigint;
sort: SortType; sort: SortType;
enableDownvotes: boolean; enableDownvotes: boolean;
enableNsfw: boolean; enableNsfw: boolean;
view: PersonDetailsView; view: PersonDetailsView;
onPageChange(page: number): number | any; onPageChange(page: bigint): bigint | any;
} }
enum ItemEnum { enum ItemEnum {
@ -36,7 +36,7 @@ type ItemType = {
type_: ItemEnum; type_: ItemEnum;
view: CommentView | PostView; view: CommentView | PostView;
published: string; published: string;
score: number; score: bigint;
}; };
export class PersonDetails extends Component<PersonDetailsProps, any> { export class PersonDetails extends Component<PersonDetailsProps, any> {
@ -144,10 +144,10 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
let combined = [...comments, ...posts]; let combined = [...comments, ...posts];
// Sort it // Sort it
if (this.props.sort === SortType.New) { if (this.props.sort === "New") {
combined.sort((a, b) => b.published.localeCompare(a.published)); combined.sort((a, b) => b.published.localeCompare(a.published));
} else { } else {
combined.sort((a, b) => b.score - a.score); combined.sort((a, b) => Number(b.score - a.score));
} }
return ( return (
@ -199,7 +199,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
); );
} }
handlePageChange(val: number) { handlePageChange(val: bigint) {
this.props.onPageChange(val); this.props.onPageChange(val);
} }
} }

View file

@ -1,12 +1,12 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { PersonSafe } from "lemmy-js-client"; import { Person } from "lemmy-js-client";
import { hostname, isCakeDay, relTags, showAvatars } from "../../utils"; import { hostname, isCakeDay, relTags, showAvatars } from "../../utils";
import { PictrsImage } from "../common/pictrs-image"; import { PictrsImage } from "../common/pictrs-image";
import { CakeDay } from "./cake-day"; import { CakeDay } from "./cake-day";
interface PersonListingProps { interface PersonListingProps {
person: PersonSafe; person: Person;
realLink?: boolean; realLink?: boolean;
useApubName?: boolean; useApubName?: boolean;
muted?: boolean; muted?: boolean;

View file

@ -10,8 +10,8 @@ import {
BlockPerson, BlockPerson,
BlockPersonResponse, BlockPersonResponse,
CommentResponse, CommentResponse,
Community,
CommunityModeratorView, CommunityModeratorView,
CommunitySafe,
GetPersonDetails, GetPersonDetails,
GetPersonDetailsResponse, GetPersonDetailsResponse,
GetSiteResponse, GetSiteResponse,
@ -49,7 +49,6 @@ import {
numToSI, numToSI,
relTags, relTags,
restoreScrollPosition, restoreScrollPosition,
routeSortTypeToEnum,
saveCommentRes, saveCommentRes,
saveScrollPosition, saveScrollPosition,
setIsoData, setIsoData,
@ -82,23 +81,26 @@ interface ProfileState {
interface ProfileProps { interface ProfileProps {
view: PersonDetailsView; view: PersonDetailsView;
sort: SortType; sort: SortType;
page: number; page: bigint;
} }
const getProfileQueryParams = () => function getProfileQueryParams() {
getQueryParams<ProfileProps>({ return getQueryParams<ProfileProps>({
view: getViewFromProps, view: getViewFromProps,
page: getPageFromString, page: getPageFromString,
sort: getSortTypeFromQuery, sort: getSortTypeFromQuery,
}); });
}
const getSortTypeFromQuery = (sort?: string): SortType => function getSortTypeFromQuery(sort?: string): SortType {
sort ? routeSortTypeToEnum(sort, SortType.New) : SortType.New; return sort ? (sort as SortType) : "New";
}
const getViewFromProps = (view?: string): PersonDetailsView => function getViewFromProps(view?: string): PersonDetailsView {
view return view
? PersonDetailsView[view] ?? PersonDetailsView.Overview ? PersonDetailsView[view] ?? PersonDetailsView.Overview
: PersonDetailsView.Overview; : PersonDetailsView.Overview;
}
function toggleBlockPerson(recipientId: number, block: boolean) { function toggleBlockPerson(recipientId: number, block: boolean) {
const auth = myAuth(); const auth = myAuth();
@ -122,7 +124,7 @@ const handleBlockPerson = (personId: number) =>
const getCommunitiesListing = ( const getCommunitiesListing = (
translationKey: NoOptionI18nKeys, translationKey: NoOptionI18nKeys,
communityViews?: { community: CommunitySafe }[] communityViews?: { community: Community }[]
) => ) =>
communityViews && communityViews &&
communityViews.length > 0 && ( communityViews.length > 0 && (
@ -500,13 +502,13 @@ export class Profile extends Component<
<ul className="list-inline mb-2"> <ul className="list-inline mb-2">
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t("number_of_posts", { {i18n.t("number_of_posts", {
count: pv.counts.post_count, count: Number(pv.counts.post_count),
formattedCount: numToSI(pv.counts.post_count), formattedCount: numToSI(pv.counts.post_count),
})} })}
</li> </li>
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t("number_of_comments", { {i18n.t("number_of_comments", {
count: pv.counts.comment_count, count: Number(pv.counts.comment_count),
formattedCount: numToSI(pv.counts.comment_count), formattedCount: numToSI(pv.counts.comment_count),
})} })}
</li> </li>
@ -643,18 +645,18 @@ export class Profile extends Component<
this.fetchUserData(); this.fetchUserData();
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
} }
handleSortChange(sort: SortType) { handleSortChange(sort: SortType) {
this.updateUrl({ sort, page: 1 }); this.updateUrl({ sort, page: 1n });
} }
handleViewChange(i: Profile, event: any) { handleViewChange(i: Profile, event: any) {
i.updateUrl({ i.updateUrl({
view: PersonDetailsView[event.target.value], view: PersonDetailsView[event.target.value],
page: 1, page: 1n,
}); });
} }

View file

@ -37,7 +37,7 @@ interface RegistrationApplicationsState {
listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse; listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse;
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
unreadOrAll: UnreadOrAll; unreadOrAll: UnreadOrAll;
page: number; page: bigint;
loading: boolean; loading: boolean;
} }
@ -50,7 +50,7 @@ export class RegistrationApplications extends Component<
state: RegistrationApplicationsState = { state: RegistrationApplicationsState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
unreadOrAll: UnreadOrAll.Unread, unreadOrAll: UnreadOrAll.Unread,
page: 1, page: 1n,
loading: true, loading: true,
}; };
@ -188,11 +188,11 @@ export class RegistrationApplications extends Component<
} }
handleUnreadOrAllChange(i: RegistrationApplications, event: any) { handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
i.setState({ unreadOrAll: Number(event.target.value), page: 1 }); i.setState({ unreadOrAll: Number(event.target.value), page: 1n });
i.refetch(); i.refetch();
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.setState({ page }); this.setState({ page });
this.refetch(); this.refetch();
} }
@ -204,7 +204,7 @@ export class RegistrationApplications extends Component<
if (auth) { if (auth) {
let form: ListRegistrationApplications = { let form: ListRegistrationApplications = {
unread_only: true, unread_only: true,
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
@ -254,7 +254,7 @@ export class RegistrationApplications extends Component<
); );
let uacs = UserService.Instance.unreadApplicationCountSub; let uacs = UserService.Instance.unreadApplicationCountSub;
// Minor bug, where if the application switches from deny to approve, the count will still go down // Minor bug, where if the application switches from deny to approve, the count will still go down
uacs.next(uacs.getValue() - 1); uacs.next(uacs.getValue() - 1n);
this.setState(this.state); this.setState(this.state);
} }
} }

View file

@ -75,7 +75,7 @@ interface ReportsState {
messageType: MessageType; messageType: MessageType;
combined: ItemType[]; combined: ItemType[];
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
page: number; page: bigint;
loading: boolean; loading: boolean;
} }
@ -86,7 +86,7 @@ export class Reports extends Component<any, ReportsState> {
unreadOrAll: UnreadOrAll.Unread, unreadOrAll: UnreadOrAll.Unread,
messageType: MessageType.All, messageType: MessageType.All,
combined: [], combined: [],
page: 1, page: 1n,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: true, loading: true,
}; };
@ -422,18 +422,18 @@ export class Reports extends Component<any, ReportsState> {
); );
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.setState({ page }); this.setState({ page });
this.refetch(); this.refetch();
} }
handleUnreadOrAllChange(i: Reports, event: any) { handleUnreadOrAllChange(i: Reports, event: any) {
i.setState({ unreadOrAll: Number(event.target.value), page: 1 }); i.setState({ unreadOrAll: Number(event.target.value), page: 1n });
i.refetch(); i.refetch();
} }
handleMessageTypeChange(i: Reports, event: any) { handleMessageTypeChange(i: Reports, event: any) {
i.setState({ messageType: Number(event.target.value), page: 1 }); i.setState({ messageType: Number(event.target.value), page: 1n });
i.refetch(); i.refetch();
} }
@ -441,7 +441,7 @@ export class Reports extends Component<any, ReportsState> {
let promises: Promise<any>[] = []; let promises: Promise<any>[] = [];
let unresolved_only = true; let unresolved_only = true;
let page = 1; let page = 1n;
let limit = fetchLimit; let limit = fetchLimit;
let auth = req.auth; let auth = req.auth;
@ -553,9 +553,9 @@ export class Reports extends Component<any, ReportsState> {
); );
let urcs = UserService.Instance.unreadReportCountSub; let urcs = UserService.Instance.unreadReportCountSub;
if (data.post_report_view.post_report.resolved) { if (data.post_report_view.post_report.resolved) {
urcs.next(urcs.getValue() - 1); urcs.next(urcs.getValue() - 1n);
} else { } else {
urcs.next(urcs.getValue() + 1); urcs.next(urcs.getValue() + 1n);
} }
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.ResolveCommentReport) { } else if (op == UserOperation.ResolveCommentReport) {
@ -566,9 +566,9 @@ export class Reports extends Component<any, ReportsState> {
); );
let urcs = UserService.Instance.unreadReportCountSub; let urcs = UserService.Instance.unreadReportCountSub;
if (data.comment_report_view.comment_report.resolved) { if (data.comment_report_view.comment_report.resolved) {
urcs.next(urcs.getValue() - 1); urcs.next(urcs.getValue() - 1n);
} else { } else {
urcs.next(urcs.getValue() + 1); urcs.next(urcs.getValue() + 1n);
} }
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.ResolvePrivateMessageReport) { } else if (op == UserOperation.ResolvePrivateMessageReport) {
@ -579,9 +579,9 @@ export class Reports extends Component<any, ReportsState> {
); );
let urcs = UserService.Instance.unreadReportCountSub; let urcs = UserService.Instance.unreadReportCountSub;
if (data.private_message_report_view.private_message_report.resolved) { if (data.private_message_report_view.private_message_report.resolved) {
urcs.next(urcs.getValue() - 1); urcs.next(urcs.getValue() - 1n);
} else { } else {
urcs.next(urcs.getValue() + 1); urcs.next(urcs.getValue() + 1n);
} }
this.setState(this.state); this.setState(this.state);
} }

View file

@ -62,8 +62,8 @@ interface SettingsState {
saveUserSettingsForm: { saveUserSettingsForm: {
show_nsfw?: boolean; show_nsfw?: boolean;
theme?: string; theme?: string;
default_sort_type?: number; default_sort_type?: SortType;
default_listing_type?: number; default_listing_type?: ListingType;
interface_language?: string; interface_language?: string;
avatar?: string; avatar?: string;
banner?: string; banner?: string;
@ -650,9 +650,8 @@ export class Settings extends Component<any, SettingsState> {
<div className="col-sm-9"> <div className="col-sm-9">
<ListingTypeSelect <ListingTypeSelect
type_={ type_={
Object.values(ListingType)[ this.state.saveUserSettingsForm.default_listing_type ??
this.state.saveUserSettingsForm.default_listing_type ?? 1 "Local"
]
} }
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
showSubscribed showSubscribed
@ -665,9 +664,7 @@ export class Settings extends Component<any, SettingsState> {
<div className="col-sm-9"> <div className="col-sm-9">
<SortSelect <SortSelect
sort={ sort={
Object.values(SortType)[ this.state.saveUserSettingsForm.default_sort_type ?? "Active"
this.state.saveUserSettingsForm.default_sort_type ?? 0
]
} }
onChange={this.handleSortTypeChange} onChange={this.handleSortTypeChange}
/> />
@ -1096,22 +1093,12 @@ export class Settings extends Component<any, SettingsState> {
} }
handleSortTypeChange(val: SortType) { handleSortTypeChange(val: SortType) {
this.setState( this.setState(s => ((s.saveUserSettingsForm.default_sort_type = val), s));
s => (
(s.saveUserSettingsForm.default_sort_type =
Object.keys(SortType).indexOf(val)),
s
)
);
} }
handleListingTypeChange(val: ListingType) { handleListingTypeChange(val: ListingType) {
this.setState( this.setState(
s => ( s => ((s.saveUserSettingsForm.default_listing_type = val), s)
(s.saveUserSettingsForm.default_listing_type =
Object.keys(ListingType).indexOf(val)),
s
)
); );
} }

View file

@ -3,7 +3,6 @@ import {
GetSiteResponse, GetSiteResponse,
UserOperation, UserOperation,
VerifyEmail as VerifyEmailForm, VerifyEmail as VerifyEmailForm,
VerifyEmailResponse,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
} from "lemmy-js-client"; } from "lemmy-js-client";
@ -85,7 +84,7 @@ export class VerifyEmail extends Component<any, State> {
this.props.history.push("/"); this.props.history.push("/");
return; return;
} else if (op == UserOperation.VerifyEmail) { } else if (op == UserOperation.VerifyEmail) {
let data = wsJsonToRes<VerifyEmailResponse>(msg); let data = wsJsonToRes(msg);
if (data) { if (data) {
toast(i18n.t("email_verified")); toast(i18n.t("email_verified"));
this.props.history.push("/login"); this.props.history.push("/login");

View file

@ -5,13 +5,10 @@ import {
CreatePost, CreatePost,
EditPost, EditPost,
Language, Language,
ListingType,
PostResponse, PostResponse,
PostView, PostView,
Search, Search,
SearchResponse, SearchResponse,
SearchType,
SortType,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -516,10 +513,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
if (url && validURL(url)) { if (url && validURL(url)) {
let form: Search = { let form: Search = {
q: url, q: url,
type_: SearchType.Url, type_: "Url",
sort: SortType.TopAll, sort: "TopAll",
listing_type: ListingType.All, listing_type: "All",
page: 1, page: 1n,
limit: trendingFetchLimit, limit: trendingFetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -545,11 +542,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
if (q && q !== "") { if (q && q !== "") {
let form: Search = { let form: Search = {
q, q,
type_: SearchType.Posts, type_: "Posts",
sort: SortType.TopAll, sort: "TopAll",
listing_type: ListingType.All, listing_type: "All",
community_id: this.state.form.community_id, community_id: this.state.form.community_id,
page: 1, page: 1n,
limit: trendingFetchLimit, limit: trendingFetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -687,9 +684,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
} else if (op == UserOperation.Search) { } else if (op == UserOperation.Search) {
let data = wsJsonToRes<SearchResponse>(msg); let data = wsJsonToRes<SearchResponse>(msg);
if (data.type_ == SearchType[SearchType.Posts]) { if (data.type_ == "Posts") {
this.setState({ suggestedPosts: data.posts }); this.setState({ suggestedPosts: data.posts });
} else if (data.type_ == SearchType[SearchType.Url]) { } else if (data.type_ == "Url") {
this.setState({ crossPosts: data.posts }); this.setState({ crossPosts: data.posts });
} }
} }

View file

@ -14,8 +14,7 @@ import {
FeaturePost, FeaturePost,
Language, Language,
LockPost, LockPost,
PersonViewSafe, PersonView,
PostFeatureType,
PostView, PostView,
PurgePerson, PurgePerson,
PurgePost, PurgePost,
@ -81,16 +80,16 @@ interface PostListingState {
showReportDialog: boolean; showReportDialog: boolean;
reportReason?: string; reportReason?: string;
my_vote?: number; my_vote?: number;
score: number; score: bigint;
upvotes: number; upvotes: bigint;
downvotes: number; downvotes: bigint;
} }
interface PostListingProps { interface PostListingProps {
post_view: PostView; post_view: PostView;
duplicates?: PostView[]; duplicates?: PostView[];
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonViewSafe[]; admins?: PersonView[];
allLanguages: Language[]; allLanguages: Language[];
siteLanguages: number[]; siteLanguages: number[];
showCommunity?: boolean; showCommunity?: boolean;
@ -638,15 +637,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<Link <Link
className="text-muted" className="text-muted"
title={i18n.t("number_of_comments", { title={i18n.t("number_of_comments", {
count: post_view.counts.comments, count: Number(post_view.counts.comments),
formattedCount: post_view.counts.comments, formattedCount: Number(post_view.counts.comments),
})} })}
to={`/post/${post_view.post.id}?scrollToComments=true`} to={`/post/${post_view.post.id}?scrollToComments=true`}
> >
<Icon icon="message-square" classes="mr-1" inline /> <Icon icon="message-square" classes="mr-1" inline />
<span className="mr-2"> <span className="mr-2">
{i18n.t("number_of_comments", { {i18n.t("number_of_comments", {
count: post_view.counts.comments, count: Number(post_view.counts.comments),
formattedCount: numToSI(post_view.counts.comments), formattedCount: numToSI(post_view.counts.comments),
})} })}
</span> </span>
@ -660,9 +659,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
); );
} }
get unreadCount(): number | undefined { get unreadCount(): bigint | undefined {
let pv = this.props.post_view; let pv = this.props.post_view;
return pv.unread_comments == pv.counts.comments || pv.unread_comments == 0 return pv.unread_comments == pv.counts.comments || pv.unread_comments == 0n
? undefined ? undefined
: pv.unread_comments; : pv.unread_comments;
} }
@ -699,7 +698,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{showScores() && ( {showScores() && (
<span <span
className={classNames("ml-2", { className={classNames("ml-2", {
invisible: this.state.downvotes === 0, invisible: this.state.downvotes === 0n,
})} })}
> >
{numToSI(this.state.downvotes)} {numToSI(this.state.downvotes)}
@ -1319,19 +1318,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (myVote == 1) { if (myVote == 1) {
this.setState({ this.setState({
score: this.state.score - 1, score: this.state.score - 1n,
upvotes: this.state.upvotes - 1, upvotes: this.state.upvotes - 1n,
}); });
} else if (myVote == -1) { } else if (myVote == -1) {
this.setState({ this.setState({
score: this.state.score + 2, score: this.state.score + 2n,
upvotes: this.state.upvotes + 1, upvotes: this.state.upvotes + 1n,
downvotes: this.state.downvotes - 1, downvotes: this.state.downvotes - 1n,
}); });
} else { } else {
this.setState({ this.setState({
score: this.state.score + 1, score: this.state.score + 1n,
upvotes: this.state.upvotes + 1, upvotes: this.state.upvotes + 1n,
}); });
} }
@ -1362,19 +1361,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (myVote == 1) { if (myVote == 1) {
this.setState({ this.setState({
score: this.state.score - 2, score: this.state.score - 2n,
upvotes: this.state.upvotes - 1, upvotes: this.state.upvotes - 1n,
downvotes: this.state.downvotes + 1, downvotes: this.state.downvotes + 1n,
}); });
} else if (myVote == -1) { } else if (myVote == -1) {
this.setState({ this.setState({
score: this.state.score + 1, score: this.state.score + 1n,
downvotes: this.state.downvotes - 1, downvotes: this.state.downvotes - 1n,
}); });
} else { } else {
this.setState({ this.setState({
score: this.state.score - 1, score: this.state.score - 1n,
downvotes: this.state.downvotes + 1, downvotes: this.state.downvotes + 1n,
}); });
} }
@ -1551,7 +1550,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (auth) { if (auth) {
let form: FeaturePost = { let form: FeaturePost = {
post_id: i.props.post_view.post.id, post_id: i.props.post_view.post.id,
feature_type: PostFeatureType.Local, feature_type: "Local",
featured: !i.props.post_view.post.featured_local, featured: !i.props.post_view.post.featured_local,
auth, auth,
}; };
@ -1564,7 +1563,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (auth) { if (auth) {
let form: FeaturePost = { let form: FeaturePost = {
post_id: i.props.post_view.post.id, post_id: i.props.post_view.post.id,
feature_type: PostFeatureType.Community, feature_type: "Community",
featured: !i.props.post_view.post.featured_community, featured: !i.props.post_view.post.featured_community,
auth, auth,
}; };
@ -1784,18 +1783,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get pointsTippy(): string { get pointsTippy(): string {
let points = i18n.t("number_of_points", { let points = i18n.t("number_of_points", {
count: this.state.score, count: Number(this.state.score),
formattedCount: this.state.score, formattedCount: Number(this.state.score),
}); });
let upvotes = i18n.t("number_of_upvotes", { let upvotes = i18n.t("number_of_upvotes", {
count: this.state.upvotes, count: Number(this.state.upvotes),
formattedCount: this.state.upvotes, formattedCount: Number(this.state.upvotes),
}); });
let downvotes = i18n.t("number_of_downvotes", { let downvotes = i18n.t("number_of_downvotes", {
count: this.state.downvotes, count: Number(this.state.downvotes),
formattedCount: this.state.downvotes, formattedCount: Number(this.state.downvotes),
}); });
return `${points}${upvotes}${downvotes}`; return `${points}${upvotes}${downvotes}`;

View file

@ -1,11 +1,6 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { import { PostReportView, PostView, ResolvePostReport } from "lemmy-js-client";
PostReportView,
PostView,
ResolvePostReport,
SubscribedType,
} from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { myAuth, wsClient } from "../../utils"; import { myAuth, wsClient } from "../../utils";
@ -40,12 +35,12 @@ export class PostReport extends Component<PostReportProps, any> {
community: r.community, community: r.community,
creator_banned_from_community: r.creator_banned_from_community, creator_banned_from_community: r.creator_banned_from_community,
counts: r.counts, counts: r.counts,
subscribed: SubscribedType.NotSubscribed, subscribed: "NotSubscribed",
saved: false, saved: false,
read: false, read: false,
creator_blocked: false, creator_blocked: false,
my_vote: r.my_vote, my_vote: r.my_vote,
unread_comments: 0, unread_comments: 0n,
}; };
return ( return (

View file

@ -6,7 +6,6 @@ import {
BanFromCommunityResponse, BanFromCommunityResponse,
BanPersonResponse, BanPersonResponse,
BlockPersonResponse, BlockPersonResponse,
CommentNode as CommentNodeI,
CommentReportResponse, CommentReportResponse,
CommentResponse, CommentResponse,
CommentSortType, CommentSortType,
@ -17,22 +16,23 @@ import {
GetPost, GetPost,
GetPostResponse, GetPostResponse,
GetSiteResponse, GetSiteResponse,
ListingType,
PostReportResponse, PostReportResponse,
PostResponse, PostResponse,
PostView, PostView,
PurgeItemResponse, PurgeItemResponse,
Search, Search,
SearchResponse, SearchResponse,
SearchType,
SortType,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { CommentViewType, InitialFetchRequest } from "../../interfaces"; import {
CommentNodeI,
CommentViewType,
InitialFetchRequest,
} from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
buildCommentsTree, buildCommentsTree,
@ -97,7 +97,7 @@ export class Post extends Component<any, PostState> {
postId: getIdFromProps(this.props), postId: getIdFromProps(this.props),
commentId: getCommentIdFromProps(this.props), commentId: getCommentIdFromProps(this.props),
commentTree: [], commentTree: [],
commentSort: CommentSortType[CommentSortType.Hot], commentSort: "Hot",
commentViewType: CommentViewType.Tree, commentViewType: CommentViewType.Tree,
scrolled: false, scrolled: false,
loading: true, loading: true,
@ -174,7 +174,7 @@ export class Post extends Component<any, PostState> {
parent_id: this.state.commentId, parent_id: this.state.commentId,
max_depth: commentTreeMaxDepth, max_depth: commentTreeMaxDepth,
sort: this.state.commentSort, sort: this.state.commentSort,
type_: ListingType.All, type_: "All",
saved_only: false, saved_only: false,
auth, auth,
}; };
@ -186,10 +186,10 @@ export class Post extends Component<any, PostState> {
if (q) { if (q) {
let form: Search = { let form: Search = {
q, q,
type_: SearchType.Url, type_: "Url",
sort: SortType.TopAll, sort: "TopAll",
listing_type: ListingType.All, listing_type: "All",
page: 1, page: 1n,
limit: trendingFetchLimit, limit: trendingFetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -211,8 +211,8 @@ export class Post extends Component<any, PostState> {
let commentsForm: GetComments = { let commentsForm: GetComments = {
max_depth: commentTreeMaxDepth, max_depth: commentTreeMaxDepth,
sort: CommentSortType.Hot, sort: "Hot",
type_: ListingType.All, type_: "All",
saved_only: false, saved_only: false,
auth, auth,
}; };
@ -373,57 +373,53 @@ export class Post extends Component<any, PostState> {
<div className="btn-group btn-group-toggle flex-wrap mr-3 mb-2"> <div className="btn-group btn-group-toggle flex-wrap mr-3 mb-2">
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
CommentSortType[this.state.commentSort] === CommentSortType.Hot && this.state.commentSort === "Hot" && "active"
"active"
}`} }`}
> >
{i18n.t("hot")} {i18n.t("hot")}
<input <input
type="radio" type="radio"
value={CommentSortType.Hot} value={"Hot"}
checked={this.state.commentSort === CommentSortType.Hot} checked={this.state.commentSort === "Hot"}
onChange={linkEvent(this, this.handleCommentSortChange)} onChange={linkEvent(this, this.handleCommentSortChange)}
/> />
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
CommentSortType[this.state.commentSort] === CommentSortType.Top && this.state.commentSort === "Top" && "active"
"active"
}`} }`}
> >
{i18n.t("top")} {i18n.t("top")}
<input <input
type="radio" type="radio"
value={CommentSortType.Top} value={"Top"}
checked={this.state.commentSort === CommentSortType.Top} checked={this.state.commentSort === "Top"}
onChange={linkEvent(this, this.handleCommentSortChange)} onChange={linkEvent(this, this.handleCommentSortChange)}
/> />
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
CommentSortType[this.state.commentSort] === CommentSortType.New && this.state.commentSort === "New" && "active"
"active"
}`} }`}
> >
{i18n.t("new")} {i18n.t("new")}
<input <input
type="radio" type="radio"
value={CommentSortType.New} value={"New"}
checked={this.state.commentSort === CommentSortType.New} checked={this.state.commentSort === "New"}
onChange={linkEvent(this, this.handleCommentSortChange)} onChange={linkEvent(this, this.handleCommentSortChange)}
/> />
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer ${ className={`btn btn-outline-secondary pointer ${
CommentSortType[this.state.commentSort] === CommentSortType.Old && this.state.commentSort === "Old" && "active"
"active"
}`} }`}
> >
{i18n.t("old")} {i18n.t("old")}
<input <input
type="radio" type="radio"
value={CommentSortType.Old} value={"Old"}
checked={this.state.commentSort === CommentSortType.Old} checked={this.state.commentSort === "Old"}
onChange={linkEvent(this, this.handleCommentSortChange)} onChange={linkEvent(this, this.handleCommentSortChange)}
/> />
</label> </label>
@ -495,7 +491,7 @@ export class Post extends Component<any, PostState> {
handleCommentSortChange(i: Post, event: any) { handleCommentSortChange(i: Post, event: any) {
i.setState({ i.setState({
commentSort: CommentSortType[event.target.value], commentSort: event.target.value as CommentSortType,
commentViewType: CommentViewType.Tree, commentViewType: CommentViewType.Tree,
commentsRes: undefined, commentsRes: undefined,
postRes: undefined, postRes: undefined,
@ -508,7 +504,7 @@ export class Post extends Component<any, PostState> {
if (comments) { if (comments) {
i.setState({ i.setState({
commentViewType: Number(event.target.value), commentViewType: Number(event.target.value),
commentSort: CommentSortType.New, commentSort: "New",
commentTree: buildCommentsTree(comments, !!i.state.commentId), commentTree: buildCommentsTree(comments, !!i.state.commentId),
}); });
} }

View file

@ -3,7 +3,6 @@ import {
GetPersonDetails, GetPersonDetails,
GetPersonDetailsResponse, GetPersonDetailsResponse,
GetSiteResponse, GetSiteResponse,
SortType,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -73,7 +72,7 @@ export class CreatePrivateMessage extends Component<
fetchPersonDetails() { fetchPersonDetails() {
let form: GetPersonDetails = { let form: GetPersonDetails = {
person_id: this.state.recipient_id, person_id: this.state.recipient_id,
sort: SortType.New, sort: "New",
saved_only: false, saved_only: false,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -84,7 +83,7 @@ export class CreatePrivateMessage extends Component<
let person_id = Number(req.path.split("/").pop()); let person_id = Number(req.path.split("/").pop());
let form: GetPersonDetails = { let form: GetPersonDetails = {
person_id, person_id,
sort: SortType.New, sort: "New",
saved_only: false, saved_only: false,
auth: req.auth, auth: req.auth,
}; };

View file

@ -4,7 +4,7 @@ import { Prompt } from "inferno-router";
import { import {
CreatePrivateMessage, CreatePrivateMessage,
EditPrivateMessage, EditPrivateMessage,
PersonSafe, Person,
PrivateMessageResponse, PrivateMessageResponse,
PrivateMessageView, PrivateMessageView,
UserOperation, UserOperation,
@ -29,7 +29,7 @@ import { MarkdownTextArea } from "../common/markdown-textarea";
import { PersonListing } from "../person/person-listing"; import { PersonListing } from "../person/person-listing";
interface PrivateMessageFormProps { interface PrivateMessageFormProps {
recipient: PersonSafe; recipient: Person;
privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit
onCancel?(): any; onCancel?(): any;
onCreate?(message: PrivateMessageView): any; onCreate?(message: PrivateMessageView): any;

View file

@ -3,7 +3,7 @@ import {
CreatePrivateMessageReport, CreatePrivateMessageReport,
DeletePrivateMessage, DeletePrivateMessage,
MarkPrivateMessageAsRead, MarkPrivateMessageAsRead,
PersonSafe, Person,
PrivateMessageView, PrivateMessageView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
@ -57,7 +57,7 @@ export class PrivateMessage extends Component<
render() { render() {
let message_view = this.props.private_message_view; let message_view = this.props.private_message_view;
let otherPerson: PersonSafe = this.mine let otherPerson: Person = this.mine
? message_view.recipient ? message_view.recipient
: message_view.creator; : message_view.creator;

View file

@ -12,7 +12,7 @@ import {
ListCommunities, ListCommunities,
ListCommunitiesResponse, ListCommunitiesResponse,
ListingType, ListingType,
PersonViewSafe, PersonView,
PostResponse, PostResponse,
PostView, PostView,
ResolveObject, ResolveObject,
@ -52,9 +52,6 @@ import {
numToSI, numToSI,
personToChoice, personToChoice,
restoreScrollPosition, restoreScrollPosition,
routeListingTypeToEnum,
routeSearchTypeToEnum,
routeSortTypeToEnum,
saveScrollPosition, saveScrollPosition,
setIsoData, setIsoData,
showLocal, showLocal,
@ -80,7 +77,7 @@ interface SearchProps {
listingType: ListingType; listingType: ListingType;
communityId?: number | null; communityId?: number | null;
creatorId?: number | null; creatorId?: number | null;
page: number; page: bigint;
} }
type FilterType = "creator" | "community"; type FilterType = "creator" | "community";
@ -101,22 +98,15 @@ interface SearchState {
interface Combined { interface Combined {
type_: string; type_: string;
data: CommentView | PostView | CommunityView | PersonViewSafe; data: CommentView | PostView | CommunityView | PersonView;
published: string; published: string;
} }
const defaultSearchType = SearchType.All; const defaultSearchType = "All";
const defaultSortType = SortType.TopAll; const defaultSortType = "TopAll";
const defaultListingType = ListingType.All; const defaultListingType = "All";
const searchTypes = [ const searchTypes = ["All", "Comments", "Posts", "Communities", "Users", "Url"];
SearchType.All,
SearchType.Comments,
SearchType.Posts,
SearchType.Communities,
SearchType.Users,
SearchType.Url,
];
const getSearchQueryParams = () => const getSearchQueryParams = () =>
getQueryParams<SearchProps>({ getQueryParams<SearchProps>({
@ -132,38 +122,49 @@ const getSearchQueryParams = () =>
const getSearchQueryFromQuery = (q?: string): string | undefined => const getSearchQueryFromQuery = (q?: string): string | undefined =>
q ? decodeURIComponent(q) : undefined; q ? decodeURIComponent(q) : undefined;
const getSearchTypeFromQuery = (type_?: string): SearchType => function getSearchTypeFromQuery(type_?: string): SearchType {
routeSearchTypeToEnum(type_ ?? "", defaultSearchType); return type_ ? (type_ as SearchType) : defaultSearchType;
}
const getSortTypeFromQuery = (sort?: string): SortType => function getSortTypeFromQuery(sort?: string): SortType {
routeSortTypeToEnum(sort ?? "", defaultSortType); return sort ? (sort as SortType) : defaultSortType;
}
const getListingTypeFromQuery = (listingType?: string): ListingType => function getListingTypeFromQuery(listingType?: string): ListingType {
routeListingTypeToEnum(listingType ?? "", defaultListingType); return listingType ? (listingType as ListingType) : defaultListingType;
}
const postViewToCombined = (data: PostView): Combined => ({ function postViewToCombined(data: PostView): Combined {
return {
type_: "posts", type_: "posts",
data, data,
published: data.post.published, published: data.post.published,
}); };
}
const commentViewToCombined = (data: CommentView): Combined => ({ function commentViewToCombined(data: CommentView): Combined {
return {
type_: "comments", type_: "comments",
data, data,
published: data.comment.published, published: data.comment.published,
}); };
}
const communityViewToCombined = (data: CommunityView): Combined => ({ function communityViewToCombined(data: CommunityView): Combined {
return {
type_: "communities", type_: "communities",
data, data,
published: data.community.published, published: data.community.published,
}); };
}
const personViewSafeToCombined = (data: PersonViewSafe): Combined => ({ function personViewSafeToCombined(data: PersonView): Combined {
return {
type_: "users", type_: "users",
data, data,
published: data.person.published, published: data.person.published,
}); };
}
const Filter = ({ const Filter = ({
filterType, filterType,
@ -212,26 +213,28 @@ const communityListing = ({
"number_of_subscribers" "number_of_subscribers"
); );
const personListing = ({ person, counts: { comment_count } }: PersonViewSafe) => const personListing = ({ person, counts: { comment_count } }: PersonView) =>
getListing( getListing(
<PersonListing person={person} showApubName />, <PersonListing person={person} showApubName />,
comment_count, comment_count,
"number_of_comments" "number_of_comments"
); );
const getListing = ( function getListing(
listing: JSX.ElementClass, listing: JSX.ElementClass,
count: number, count: bigint,
translationKey: "number_of_comments" | "number_of_subscribers" translationKey: "number_of_comments" | "number_of_subscribers"
) => ( ) {
return (
<> <>
<span>{listing}</span> <span>{listing}</span>
<span>{` - ${i18n.t(translationKey, { <span>{` - ${i18n.t(translationKey, {
count, count: Number(count),
formattedCount: numToSI(count), formattedCount: numToSI(count),
})}`}</span> })}`}</span>
</> </>
); );
}
export class Search extends Component<any, SearchState> { export class Search extends Component<any, SearchState> {
private isoData = setIsoData(this.context); private isoData = setIsoData(this.context);
@ -382,19 +385,20 @@ export class Search extends Component<any, SearchState> {
type_: getSearchTypeFromQuery(type), type_: getSearchTypeFromQuery(type),
sort: getSortTypeFromQuery(sort), sort: getSortTypeFromQuery(sort),
listing_type: getListingTypeFromQuery(listingType), listing_type: getListingTypeFromQuery(listingType),
page: getIdFromString(page), page: getPageFromString(page),
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
const resolveObjectForm: ResolveObject = {
q: query,
auth,
};
if (query !== "") { if (query !== "") {
promises.push(client.search(form)); promises.push(client.search(form));
if (auth) {
const resolveObjectForm: ResolveObject = {
q: query,
auth,
};
promises.push(client.resolveObject(resolveObjectForm)); promises.push(client.resolveObject(resolveObjectForm));
}
} else { } else {
promises.push(Promise.resolve()); promises.push(Promise.resolve());
promises.push(Promise.resolve()); promises.push(Promise.resolve());
@ -433,16 +437,16 @@ export class Search extends Component<any, SearchState> {
displayResults(type: SearchType) { displayResults(type: SearchType) {
switch (type) { switch (type) {
case SearchType.All: case "All":
return this.all; return this.all;
case SearchType.Comments: case "Comments":
return this.comments; return this.comments;
case SearchType.Posts: case "Posts":
case SearchType.Url: case "Url":
return this.posts; return this.posts;
case SearchType.Communities: case "Communities":
return this.communities; return this.communities;
case SearchType.Users: case "Users":
return this.users; return this.users;
default: default:
return <></>; return <></>;
@ -582,17 +586,18 @@ export class Search extends Component<any, SearchState> {
const { sort } = getSearchQueryParams(); const { sort } = getSearchQueryParams();
// Sort it // Sort it
if (sort === SortType.New) { if (sort === "New") {
combined.sort((a, b) => b.published.localeCompare(a.published)); combined.sort((a, b) => b.published.localeCompare(a.published));
} else { } else {
combined.sort( combined.sort((a, b) =>
(a, b) => Number(
((b.data as CommentView | PostView).counts.score | ((b.data as CommentView | PostView).counts.score |
(b.data as CommunityView).counts.subscribers | (b.data as CommunityView).counts.subscribers |
(b.data as PersonViewSafe).counts.comment_score) - (b.data as PersonView).counts.comment_score) -
((a.data as CommentView | PostView).counts.score | ((a.data as CommentView | PostView).counts.score |
(a.data as CommunityView).counts.subscribers | (a.data as CommunityView).counts.subscribers |
(a.data as PersonViewSafe).counts.comment_score) (a.data as PersonView).counts.comment_score)
)
); );
} }
@ -642,7 +647,7 @@ export class Search extends Component<any, SearchState> {
<div>{communityListing(i.data as CommunityView)}</div> <div>{communityListing(i.data as CommunityView)}</div>
)} )}
{i.type_ === "users" && ( {i.type_ === "users" && (
<div>{personListing(i.data as PersonViewSafe)}</div> <div>{personListing(i.data as PersonView)}</div>
)} )}
</div> </div>
</div> </div>
@ -781,10 +786,15 @@ export class Search extends Component<any, SearchState> {
auth, auth,
}; };
if (auth) {
const resolveObjectForm: ResolveObject = { const resolveObjectForm: ResolveObject = {
q, q,
auth, auth,
}; };
WebSocketService.Instance.send(
wsClient.resolveObject(resolveObjectForm)
);
}
this.setState({ this.setState({
searchResponse: undefined, searchResponse: undefined,
@ -793,7 +803,6 @@ export class Search extends Component<any, SearchState> {
}); });
WebSocketService.Instance.send(wsClient.search(form)); WebSocketService.Instance.send(wsClient.search(form));
WebSocketService.Instance.send(wsClient.resolveObject(resolveObjectForm));
} }
} }
@ -854,40 +863,40 @@ export class Search extends Component<any, SearchState> {
}); });
handleSortChange(sort: SortType) { handleSortChange(sort: SortType) {
this.updateUrl({ sort, page: 1 }); this.updateUrl({ sort, page: 1n });
} }
handleTypeChange(i: Search, event: any) { handleTypeChange(i: Search, event: any) {
const type = SearchType[event.target.value]; const type = event.target.value as SearchType;
i.updateUrl({ i.updateUrl({
type, type,
page: 1, page: 1n,
}); });
} }
handlePageChange(page: number) { handlePageChange(page: bigint) {
this.updateUrl({ page }); this.updateUrl({ page });
} }
handleListingTypeChange(listingType: ListingType) { handleListingTypeChange(listingType: ListingType) {
this.updateUrl({ this.updateUrl({
listingType, listingType,
page: 1, page: 1n,
}); });
} }
handleCommunityFilterChange({ value }: Choice) { handleCommunityFilterChange({ value }: Choice) {
this.updateUrl({ this.updateUrl({
communityId: getIdFromString(value) ?? null, communityId: getIdFromString(value) ?? null,
page: 1, page: 1n,
}); });
} }
handleCreatorFilterChange({ value }: Choice) { handleCreatorFilterChange({ value }: Choice) {
this.updateUrl({ this.updateUrl({
creatorId: getIdFromString(value) ?? null, creatorId: getIdFromString(value) ?? null,
page: 1, page: 1n,
}); });
} }
@ -896,7 +905,7 @@ export class Search extends Component<any, SearchState> {
i.updateUrl({ i.updateUrl({
q: i.state.searchText, q: i.state.searchText,
page: 1, page: 1n,
}); });
} }

View file

@ -1,4 +1,4 @@
import { GetSiteResponse, LemmyHttp } from "lemmy-js-client"; import { CommentView, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
import type { ParsedQs } from "qs"; import type { ParsedQs } from "qs";
/** /**
@ -63,3 +63,9 @@ export enum PurgeType {
Post, Post,
Comment, Comment,
} }
export interface CommentNodeI {
comment_view: CommentView;
children: Array<CommentNodeI>;
depth: number;
}

View file

@ -130,6 +130,10 @@ export const routes: IRoutePropsWithFetch[] = [
path: `/verify_email/:token`, path: `/verify_email/:token`,
component: VerifyEmail, component: VerifyEmail,
}, },
{ path: `/instances`, component: Instances }, {
path: `/instances`,
component: Instances,
fetchInitialData: Instances.fetchInitialData,
},
{ path: `/legal`, component: Legal }, { path: `/legal`, component: Legal },
]; ];

View file

@ -22,12 +22,12 @@ export class UserService {
private static _instance: UserService; private static _instance: UserService;
public myUserInfo?: MyUserInfo; public myUserInfo?: MyUserInfo;
public jwtInfo?: JwtInfo; public jwtInfo?: JwtInfo;
public unreadInboxCountSub: BehaviorSubject<number> = public unreadInboxCountSub: BehaviorSubject<bigint> =
new BehaviorSubject<number>(0); new BehaviorSubject<bigint>(0n);
public unreadReportCountSub: BehaviorSubject<number> = public unreadReportCountSub: BehaviorSubject<bigint> =
new BehaviorSubject<number>(0); new BehaviorSubject<bigint>(0n);
public unreadApplicationCountSub: BehaviorSubject<number> = public unreadApplicationCountSub: BehaviorSubject<bigint> =
new BehaviorSubject<number>(0); new BehaviorSubject<bigint>(0n);
private constructor() { private constructor() {
this.setJwtInfo(); this.setJwtInfo();

View file

@ -4,7 +4,6 @@ import {
BlockCommunityResponse, BlockCommunityResponse,
BlockPersonResponse, BlockPersonResponse,
Comment as CommentI, Comment as CommentI,
CommentNode as CommentNodeI,
CommentReportView, CommentReportView,
CommentSortType, CommentSortType,
CommentView, CommentView,
@ -16,16 +15,15 @@ import {
Language, Language,
LemmyHttp, LemmyHttp,
LemmyWebsocket, LemmyWebsocket,
ListingType, MyUserInfo,
PersonSafe, Person,
PersonViewSafe, PersonView,
PostReportView, PostReportView,
PostView, PostView,
PrivateMessageReportView, PrivateMessageReportView,
PrivateMessageView, PrivateMessageView,
RegistrationApplicationView, RegistrationApplicationView,
Search, Search,
SearchType,
SortType, SortType,
UploadImageResponse, UploadImageResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
@ -45,7 +43,7 @@ import tippy from "tippy.js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { httpBase } from "./env"; import { httpBase } from "./env";
import { i18n, languages } from "./i18next"; import { i18n, languages } from "./i18next";
import { DataType, IsoData } from "./interfaces"; import { CommentNodeI, DataType, IsoData } from "./interfaces";
import { UserService, WebSocketService } from "./services"; import { UserService, WebSocketService } from "./services";
var Tribute: any; var Tribute: any;
@ -72,12 +70,12 @@ export const webArchiveUrl = "https://web.archive.org";
export const elementUrl = "https://element.io"; export const elementUrl = "https://element.io";
export const postRefetchSeconds: number = 60 * 1000; export const postRefetchSeconds: number = 60 * 1000;
export const fetchLimit = 40; export const fetchLimit = 40n;
export const trendingFetchLimit = 6; export const trendingFetchLimit = 6n;
export const mentionDropdownFetchLimit = 10; export const mentionDropdownFetchLimit = 10;
export const commentTreeMaxDepth = 8; export const commentTreeMaxDepth = 8;
export const markdownFieldCharacterLimit = 50000; export const markdownFieldCharacterLimit = 50000;
export const maxUploadImages = 20; export const maxUploadImages = 20n;
export const concurrentImageUpload = 4; export const concurrentImageUpload = 4;
export const relTags = "noopener nofollow"; export const relTags = "noopener nofollow";
@ -124,8 +122,8 @@ export function getIdFromString(id?: string): number | undefined {
return id && id !== "0" && !Number.isNaN(Number(id)) ? Number(id) : undefined; return id && id !== "0" && !Number.isNaN(Number(id)) ? Number(id) : undefined;
} }
export function getPageFromString(page?: string): number { export function getPageFromString(page?: string): bigint {
return page && !Number.isNaN(Number(page)) ? Number(page) : 1; return page && !Number.isNaN(Number(page)) ? BigInt(page) : BigInt(1);
} }
export function randomStr( export function randomStr(
@ -187,14 +185,14 @@ export function hotRankPost(post_view: PostView): number {
return hotRank(post_view.counts.score, post_view.post.published); return hotRank(post_view.counts.score, post_view.post.published);
} }
export function hotRank(score: number, timeStr: string): number { export function hotRank(score: bigint, timeStr: string): number {
// Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity // Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity
let date: Date = new Date(timeStr + "Z"); // Add Z to convert from UTC date let date: Date = new Date(timeStr + "Z"); // Add Z to convert from UTC date
let now: Date = new Date(); let now: Date = new Date();
let hoursElapsed: number = (now.getTime() - date.getTime()) / 36e5; let hoursElapsed: number = (now.getTime() - date.getTime()) / 36e5;
let rank = let rank =
(10000 * Math.log10(Math.max(1, 3 + score))) / (10000 * Math.log10(Math.max(1, Number(3n + score)))) /
Math.pow(hoursElapsed + 2, 1.8); Math.pow(hoursElapsed + 2, 1.8);
// console.log(`Comment: ${comment.content}\nRank: ${rank}\nScore: ${comment.score}\nHours: ${hoursElapsed}`); // console.log(`Comment: ${comment.content}\nRank: ${rank}\nScore: ${comment.score}\nHours: ${hoursElapsed}`);
@ -214,22 +212,24 @@ export function mdToHtmlInline(text: string) {
return { __html: md.renderInline(text) }; return { __html: md.renderInline(text) };
} }
export function getUnixTime(text?: string): number | undefined { export function getUnixTime(text?: string): bigint | undefined {
return text ? new Date(text).getTime() / 1000 : undefined; return text ? BigInt(new Date(text).getTime() / 1000) : undefined;
} }
export function futureDaysToUnixTime(days?: number): number | undefined { export function futureDaysToUnixTime(days?: number): bigint | undefined {
return days return days
? Math.trunc( ? BigInt(
Math.trunc(
new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000 new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000
) )
)
: undefined; : undefined;
} }
export function canMod( export function canMod(
creator_id: number, creator_id: number,
mods?: CommunityModeratorView[], mods?: CommunityModeratorView[],
admins?: PersonViewSafe[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo = UserService.Instance.myUserInfo,
onSelf = false onSelf = false
): boolean { ): boolean {
@ -257,7 +257,7 @@ export function canMod(
export function canAdmin( export function canAdmin(
creatorId: number, creatorId: number,
admins?: PersonViewSafe[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo = UserService.Instance.myUserInfo,
onSelf = false onSelf = false
): boolean { ): boolean {
@ -278,7 +278,7 @@ export function amMod(
return myUserInfo ? isMod(myUserInfo.local_user_view.person.id, mods) : false; return myUserInfo ? isMod(myUserInfo.local_user_view.person.id, mods) : false;
} }
export function isAdmin(creatorId: number, admins?: PersonViewSafe[]): boolean { export function isAdmin(creatorId: number, admins?: PersonView[]): boolean {
return admins?.map(a => a.person.id).includes(creatorId) ?? false; return admins?.map(a => a.person.id).includes(creatorId) ?? false;
} }
@ -298,7 +298,7 @@ export function amCommunityCreator(
export function amSiteCreator( export function amSiteCreator(
creator_id: number, creator_id: number,
admins?: PersonViewSafe[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo myUserInfo = UserService.Instance.myUserInfo
): boolean { ): boolean {
let myId = myUserInfo?.local_user_view.person.id; let myId = myUserInfo?.local_user_view.person.id;
@ -342,42 +342,6 @@ export function capitalizeFirstLetter(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1); return str.charAt(0).toUpperCase() + str.slice(1);
} }
export function routeSortTypeToEnum(
sort: string,
defaultValue: SortType
): SortType {
return SortType[sort] ?? defaultValue;
}
export function listingTypeFromNum(type_: number): ListingType {
return Object.values(ListingType)[type_];
}
export function sortTypeFromNum(type_: number): SortType {
return Object.values(SortType)[type_];
}
export function routeListingTypeToEnum(
type: string,
defaultValue: ListingType
): ListingType {
return ListingType[type] ?? defaultValue;
}
export function routeDataTypeToEnum(
type: string,
defaultValue: DataType
): DataType {
return DataType[type] ?? defaultValue;
}
export function routeSearchTypeToEnum(
type: string,
defaultValue: SearchType
): SearchType {
return SearchType[type] ?? defaultValue;
}
export async function getSiteMetadata(url: string) { export async function getSiteMetadata(url: string) {
let form: GetSiteMetadata = { url }; let form: GetSiteMetadata = { url };
let client = new LemmyHttp(httpBase); let client = new LemmyHttp(httpBase);
@ -901,7 +865,7 @@ export function setupTippy() {
interface PersonTribute { interface PersonTribute {
key: string; key: string;
view: PersonViewSafe; view: PersonView;
} }
async function personSearch(text: string): Promise<PersonTribute[]> { async function personSearch(text: string): Promise<PersonTribute[]> {
@ -972,7 +936,7 @@ export function saveCommentRes(data: CommentView, comments?: CommentView[]) {
export function updatePersonBlock( export function updatePersonBlock(
data: BlockPersonResponse, data: BlockPersonResponse,
myUserInfo = UserService.Instance.myUserInfo myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
) { ) {
let mui = myUserInfo; let mui = myUserInfo;
if (mui) { if (mui) {
@ -993,7 +957,7 @@ export function updatePersonBlock(
export function updateCommunityBlock( export function updateCommunityBlock(
data: BlockCommunityResponse, data: BlockCommunityResponse,
myUserInfo = UserService.Instance.myUserInfo myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
) { ) {
let mui = myUserInfo; let mui = myUserInfo;
if (mui) { if (mui) {
@ -1124,19 +1088,19 @@ export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
export function convertCommentSortType(sort: SortType): CommentSortType { export function convertCommentSortType(sort: SortType): CommentSortType {
if ( if (
sort == SortType.TopAll || sort == "TopAll" ||
sort == SortType.TopDay || sort == "TopDay" ||
sort == SortType.TopWeek || sort == "TopWeek" ||
sort == SortType.TopMonth || sort == "TopMonth" ||
sort == SortType.TopYear sort == "TopYear"
) { ) {
return CommentSortType.Top; return "Top";
} else if (sort == SortType.New) { } else if (sort == "New") {
return CommentSortType.New; return "New";
} else if (sort == SortType.Hot || sort == SortType.Active) { } else if (sort == "Hot" || sort == "Active") {
return CommentSortType.Hot; return "Hot";
} else { } else {
return CommentSortType.Hot; return "Hot";
} }
} }
@ -1359,8 +1323,7 @@ export function restoreScrollPosition(context: any) {
} }
export function showLocal(isoData: IsoData): boolean { export function showLocal(isoData: IsoData): boolean {
let linked = isoData.site_res.federated_instances?.linked; return isoData.site_res.site_view.local_site.federation_enabled;
return linked ? linked.length > 0 : false;
} }
export interface Choice { export interface Choice {
@ -1382,7 +1345,7 @@ export function communityToChoice(cv: CommunityView): Choice {
}; };
} }
export function personToChoice(pvs: PersonViewSafe): Choice { export function personToChoice(pvs: PersonView): Choice {
return { return {
value: pvs.person.id.toString(), value: pvs.person.id.toString(),
label: personSelectName(pvs), label: personSelectName(pvs),
@ -1392,10 +1355,10 @@ export function personToChoice(pvs: PersonViewSafe): Choice {
export async function fetchCommunities(q: string) { export async function fetchCommunities(q: string) {
let form: Search = { let form: Search = {
q, q,
type_: SearchType.Communities, type_: "Communities",
sort: SortType.TopAll, sort: "TopAll",
listing_type: ListingType.All, listing_type: "All",
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -1406,10 +1369,10 @@ export async function fetchCommunities(q: string) {
export async function fetchUsers(q: string) { export async function fetchUsers(q: string) {
let form: Search = { let form: Search = {
q, q,
type_: SearchType.Users, type_: "Users",
sort: SortType.TopAll, sort: "TopAll",
listing_type: ListingType.All, listing_type: "All",
page: 1, page: 1n,
limit: fetchLimit, limit: fetchLimit,
auth: myAuth(false), auth: myAuth(false),
}; };
@ -1425,7 +1388,7 @@ export function communitySelectName(cv: CommunityView): string {
export function personSelectName({ export function personSelectName({
person: { display_name, name, local, actor_id }, person: { display_name, name, local, actor_id },
}: PersonViewSafe): string { }: PersonView): string {
const pName = display_name ?? name; const pName = display_name ?? name;
return local ? pName : `${hostname(actor_id)}/${pName}`; return local ? pName : `${hostname(actor_id)}/${pName}`;
} }
@ -1444,11 +1407,11 @@ const SHORTNUM_SI_FORMAT = new Intl.NumberFormat("en-US", {
compactDisplay: "short", compactDisplay: "short",
}); });
export function numToSI(value: number): string { export function numToSI(value: bigint): string {
return SHORTNUM_SI_FORMAT.format(value); return SHORTNUM_SI_FORMAT.format(value);
} }
export function isBanned(ps: PersonSafe): boolean { export function isBanned(ps: Person): boolean {
let expires = ps.ban_expires; let expires = ps.ban_expires;
// Add Z to convert from UTC date // Add Z to convert from UTC date
// TODO this check probably isn't necessary anymore // TODO this check probably isn't necessary anymore
@ -1477,16 +1440,16 @@ export function enableNsfw(siteRes: GetSiteResponse): boolean {
export function postToCommentSortType(sort: SortType): CommentSortType { export function postToCommentSortType(sort: SortType): CommentSortType {
switch (sort) { switch (sort) {
case SortType.Active: case "Active":
case SortType.Hot: case "Hot":
return CommentSortType.Hot; return "Hot";
case SortType.New: case "New":
case SortType.NewComments: case "NewComments":
return CommentSortType.New; return "New";
case SortType.Old: case "Old":
return CommentSortType.Old; return "Old";
default: default:
return CommentSortType.Top; return "Top";
} }
} }
@ -1515,7 +1478,7 @@ export function canCreateCommunity(
export function isPostBlocked( export function isPostBlocked(
pv: PostView, pv: PostView,
myUserInfo = UserService.Instance.myUserInfo myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
): boolean { ): boolean {
return ( return (
(myUserInfo?.community_blocks (myUserInfo?.community_blocks

View file

@ -5581,10 +5581,10 @@ leac@^0.6.0:
resolved "https://registry.yarnpkg.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912" resolved "https://registry.yarnpkg.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912"
integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg== integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==
lemmy-js-client@0.17.2-rc.5: lemmy-js-client@0.17.2-rc.14:
version "0.17.2-rc.5" version "0.17.2-rc.14"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.2-rc.5.tgz#8dbfa01fc293d63d72d8294d5584d4e71c9c08be" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.2-rc.14.tgz#2734c52a4216e4045c1b63ad0e4e302e72463d12"
integrity sha512-B2VibqJvevVDiYK7yfMPZrx0GdC4XgpN2bgouzMgXZsn+HENALIAm5K+sZhD40/NCd69MglWTlYtFYg9d4YxOA== integrity sha512-HERUQL3UChSjY1pLeyAJ/4dBS+YMEoq0MBUW3Q45s6GjcjSJyE3l5JKC6qlozyDX3oc462NNel/rP1/qNQRvZQ==
dependencies: dependencies:
cross-fetch "^3.1.5" cross-fetch "^3.1.5"
form-data "^4.0.0" form-data "^4.0.0"