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",
"isomorphic-cookie": "^1.2.4",
"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-container": "^3.0.0",
"markdown-it-emoji": "^2.0.2",

View file

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

View file

@ -40,9 +40,9 @@ interface NavbarProps {
interface NavbarState {
expanded: boolean;
unreadInboxCount: number;
unreadReportCount: number;
unreadApplicationCount: number;
unreadInboxCount: bigint;
unreadReportCount: bigint;
unreadApplicationCount: bigint;
showDropdown: boolean;
onSiteBanner?(url: string): any;
}
@ -54,9 +54,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
private unreadReportCountSub: Subscription;
private unreadApplicationCountSub: Subscription;
state: NavbarState = {
unreadInboxCount: 0,
unreadReportCount: 0,
unreadApplicationCount: 0,
unreadInboxCount: 0n,
unreadReportCount: 0n,
unreadApplicationCount: 0n,
expanded: false,
showDropdown: false,
};
@ -144,7 +144,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="p-1 navbar-toggler nav-link border-0"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_messages", {
count: this.state.unreadInboxCount,
count: Number(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"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_reports", {
count: this.state.unreadReportCount,
count: Number(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"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount,
count: Number(this.state.unreadApplicationCount),
formattedCount: numToSI(
this.state.unreadApplicationCount
),
@ -305,7 +305,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/inbox"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_messages", {
count: this.state.unreadInboxCount,
count: Number(this.state.unreadInboxCount),
formattedCount: numToSI(this.state.unreadInboxCount),
})}
>
@ -326,7 +326,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/reports"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_reports", {
count: this.state.unreadReportCount,
count: Number(this.state.unreadReportCount),
formattedCount: numToSI(this.state.unreadReportCount),
})}
>
@ -348,7 +348,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="nav-link"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount,
count: Number(this.state.unreadApplicationCount),
formattedCount: numToSI(
this.state.unreadApplicationCount
),
@ -512,7 +512,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
unreadReportCount:
data.post_reports +
data.comment_reports +
(data.private_message_reports ?? 0),
(data.private_message_reports ?? 0n),
});
this.sendReportUnread();
} 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)
) {
this.setState({
unreadInboxCount: this.state.unreadInboxCount + 1,
unreadInboxCount: this.state.unreadInboxCount + 1n,
});
this.sendUnreadCount();
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
) {
this.setState({
unreadInboxCount: this.state.unreadInboxCount + 1,
unreadInboxCount: this.state.unreadInboxCount + 1n,
});
this.sendUnreadCount();
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 { Link } from "inferno-router";
import {
CommentNode as CommentNodeI,
CommentResponse,
CreateComment,
EditComment,
@ -12,6 +11,7 @@ import {
wsUserOp,
} from "lemmy-js-client";
import { Subscription } from "rxjs";
import { CommentNodeI } from "shared/interfaces";
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
import {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,8 +2,8 @@ import { Component, linkEvent } from "inferno";
import { i18n } from "../../i18next";
interface PaginatorProps {
page: number;
onChange(val: number): any;
page: bigint;
onChange(val: bigint): any;
}
export class Paginator extends Component<PaginatorProps, any> {
@ -15,7 +15,7 @@ export class Paginator extends Component<PaginatorProps, any> {
<div className="my-2">
<button
className="btn btn-secondary mr-2"
disabled={this.props.page == 1}
disabled={this.props.page == 1n}
onClick={linkEvent(this, this.handlePrev)}
>
{i18n.t("prev")}
@ -31,10 +31,10 @@ export class Paginator extends Component<PaginatorProps, any> {
}
handlePrev(i: Paginator) {
i.props.onChange(i.props.page - 1);
i.props.onChange(i.props.page - 1n);
}
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")}
</option>
{!this.props.hideHot && [
<option key={SortType.Hot} value={SortType.Hot}>
<option key={"Hot"} value={"Hot"}>
{i18n.t("hot")}
</option>,
<option key={SortType.Active} value={SortType.Active}>
<option key={"Active"} value={"Active"}>
{i18n.t("active")}
</option>,
]}
<option value={SortType.New}>{i18n.t("new")}</option>
<option value={SortType.Old}>{i18n.t("old")}</option>
<option value={"New"}>{i18n.t("new")}</option>
<option value={"Old"}>{i18n.t("old")}</option>
{!this.props.hideMostComments && [
<option key={SortType.MostComments} value={SortType.MostComments}>
<option key={"MostComments"} value={"MostComments"}>
{i18n.t("most_comments")}
</option>,
<option key={SortType.NewComments} value={SortType.NewComments}>
<option key={"NewComments"} value={"NewComments"}>
{i18n.t("new_comments")}
</option>,
]}
<option disabled aria-hidden="true">
</option>
<option value={SortType.TopDay}>{i18n.t("top_day")}</option>
<option value={SortType.TopWeek}>{i18n.t("top_week")}</option>
<option value={SortType.TopMonth}>{i18n.t("top_month")}</option>
<option value={SortType.TopYear}>{i18n.t("top_year")}</option>
<option value={SortType.TopAll}>{i18n.t("top_all")}</option>
<option value={"TopDay"}>{i18n.t("top_day")}</option>
<option value={"TopWeek"}>{i18n.t("top_week")}</option>
<option value={"TopMonth"}>{i18n.t("top_month")}</option>
<option value={"TopYear"}>{i18n.t("top_year")}</option>
<option value={"TopAll"}>{i18n.t("top_all")}</option>
</select>
<a
className="text-muted"

View file

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

View file

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

View file

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

View file

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

View file

@ -3,8 +3,9 @@ import { Component, linkEvent } from "inferno";
import {
BannedPersonsResponse,
GetBannedPersons,
GetFederatedInstancesResponse,
GetSiteResponse,
PersonViewSafe,
PersonView,
SiteResponse,
UserOperation,
wsJsonToRes,
@ -34,7 +35,8 @@ import { TaglineForm } from "./tagline-form";
interface AdminSettingsState {
siteRes: GetSiteResponse;
banned: PersonViewSafe[];
instancesRes?: GetFederatedInstancesResponse;
banned: PersonView[];
loading: boolean;
leaveAdminTeamLoading: boolean;
currentTab: string;
@ -63,6 +65,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state = {
...this.state,
banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned,
instancesRes: this.isoData
.routeData[1] as GetFederatedInstancesResponse,
loading: false,
};
} else {
@ -73,6 +77,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
auth: cAuth,
})
);
WebSocketService.Instance.send(
wsClient.getFederatedInstances({ auth: cAuth })
);
}
}
}
@ -84,6 +91,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
if (auth) {
let bannedPersonsForm: GetBannedPersons = { auth };
promises.push(req.client.getBannedPersons(bannedPersonsForm));
promises.push(req.client.getFederatedInstances({ auth }));
}
return promises;
@ -167,6 +175,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<div className="col-12 col-md-6">
<SiteForm
siteRes={this.state.siteRes}
instancesRes={this.state.instancesRes}
showLocal={showLocal(this.isoData)}
/>
</div>
@ -269,9 +278,11 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState(s => ((s.siteRes.site_view = data.site_view), s));
this.setState({ leaveAdminTeamLoading: false });
toast(i18n.t("left_admin_team"));
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 {
GetSiteResponse,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "lemmy-js-client";
import {
CreateCustomEmoji,
CustomEmojiResponse,
DeleteCustomEmoji,
DeleteCustomEmojiResponse,
EditCustomEmoji,
} from "lemmy-js-client/dist/interfaces/api/custom_emoji";
GetSiteResponse,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "lemmy-js-client";
import { Subscription } from "rxjs";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
@ -37,7 +35,7 @@ interface EmojiFormState {
siteRes: GetSiteResponse;
customEmojis: CustomEmojiViewForm[];
loading: boolean;
page: number;
page: bigint;
}
interface CustomEmojiViewForm {
@ -48,7 +46,7 @@ interface CustomEmojiViewForm {
alt_text: string;
keywords: string;
changed: boolean;
page: number;
page: bigint;
}
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,
keywords: x.keywords.map(x => x.keyword).join(" "),
changed: false,
page: 1 + Math.floor(index / this.itemsPerPage),
page: BigInt(1 + Math.floor(index / this.itemsPerPage)),
})),
page: 1,
page: 1n,
};
state: EmojiFormState;
private scrollRef: any = {};
@ -127,8 +125,11 @@ export class EmojiForm extends Component<any, EmojiFormState> {
<tbody>
{this.state.customEmojis
.slice(
(this.state.page - 1) * this.itemsPerPage,
(this.state.page - 1) * this.itemsPerPage + this.itemsPerPage
Number((this.state.page - 1n) * BigInt(this.itemsPerPage)),
Number(
(this.state.page - 1n) * BigInt(this.itemsPerPage) +
BigInt(this.itemsPerPage)
)
)
.map((cv, index) => (
<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");
}
handlePageChange(page: number) {
handlePageChange(page: bigint) {
this.setState({ page: page });
}
@ -326,13 +327,14 @@ export class EmojiForm extends Component<any, EmojiFormState> {
) {
let custom_emojis = [...props.form.state.customEmojis];
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 = {
...props.form.state.customEmojis[pagedIndex],
...props.form.state.customEmojis[Number(pagedIndex)],
category: event.target.value,
changed: true,
};
custom_emojis[pagedIndex] = item;
custom_emojis[Number(pagedIndex)] = item;
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 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 = {
...props.form.state.customEmojis[pagedIndex],
...props.form.state.customEmojis[Number(pagedIndex)],
shortcode: event.target.value,
changed: true,
};
custom_emojis[pagedIndex] = item;
custom_emojis[Number(pagedIndex)] = item;
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 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 = {
...props.form.state.customEmojis[pagedIndex],
...props.form.state.customEmojis[Number(pagedIndex)],
image_url: props.overrideValue ?? event.target.value,
changed: true,
};
custom_emojis[pagedIndex] = item;
custom_emojis[Number(pagedIndex)] = item;
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 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 = {
...props.form.state.customEmojis[pagedIndex],
...props.form.state.customEmojis[Number(pagedIndex)],
alt_text: event.target.value,
changed: true,
};
custom_emojis[pagedIndex] = item;
custom_emojis[Number(pagedIndex)] = item;
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 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 = {
...props.form.state.customEmojis[pagedIndex],
...props.form.state.customEmojis[Number(pagedIndex)],
keywords: event.target.value,
changed: true,
};
custom_emojis[pagedIndex] = item;
custom_emojis[Number(pagedIndex)] = item;
props.form.setState({ customEmojis: custom_emojis });
}
@ -406,7 +412,8 @@ export class EmojiForm extends Component<any, EmojiFormState> {
cv: CustomEmojiViewForm;
}) {
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) {
const deleteForm: DeleteCustomEmoji = {
id: props.cv.id,
@ -415,7 +422,7 @@ export class EmojiForm extends Component<any, EmojiFormState> {
WebSocketService.Instance.send(wsClient.deleteCustomEmoji(deleteForm));
} else {
let custom_emojis = [...props.form.state.customEmojis];
custom_emojis.splice(pagedIndex, 1);
custom_emojis.splice(Number(pagedIndex), 1);
props.form.setState({ customEmojis: custom_emojis });
}
}
@ -451,8 +458,9 @@ export class EmojiForm extends Component<any, EmojiFormState> {
handleAddEmojiClick(form: EmojiForm, event: any) {
event.preventDefault();
let custom_emojis = [...form.state.customEmojis];
const page =
1 + Math.floor(form.state.customEmojis.length / form.itemsPerPage);
const page = BigInt(
1 + Math.floor(form.state.customEmojis.length / form.itemsPerPage)
);
let item: CustomEmojiViewForm = {
id: 0,
shortcode: "",

View file

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

View file

@ -1,29 +1,79 @@
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 { 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";
interface InstancesState {
siteRes: GetSiteResponse;
instancesRes?: GetFederatedInstancesResponse;
loading: boolean;
}
export class Instances extends Component<any, InstancesState> {
private isoData = setIsoData(this.context);
state: InstancesState = {
siteRes: this.isoData.site_res,
loading: true,
};
private subscription?: Subscription;
constructor(props: any, context: any) {
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 {
return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
}
componentWillUnmount() {
if (isBrowser()) {
this.subscription?.unsubscribe();
}
}
render() {
let federated_instances = this.state.siteRes.federated_instances;
let federated_instances = this.state.instancesRes?.federated_instances;
return federated_instances ? (
<div className="container-lg">
<HtmlTags
@ -56,20 +106,47 @@ export class Instances extends Component<any, InstancesState> {
);
}
itemList(items: string[]) {
let noneFound = <div>{i18n.t("none_found")}</div>;
itemList(items: Instance[]) {
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 => (
<li key={i}>
<a href={`https://${i}`} rel={relTags}>
{i}
<tr key={i.domain}>
<td>
<a href={`https://${i.domain}`} rel={relTags}>
{i.domain}
</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);
if (isBrowser()) {
WebSocketService.Instance.send(wsClient.getCaptcha());
WebSocketService.Instance.send(wsClient.getCaptcha({}));
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,12 +1,12 @@
import { Component } from "inferno";
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 { PictrsImage } from "../common/pictrs-image";
import { CakeDay } from "./cake-day";
interface PersonListingProps {
person: PersonSafe;
person: Person;
realLink?: boolean;
useApubName?: boolean;
muted?: boolean;

View file

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

View file

@ -37,7 +37,7 @@ interface RegistrationApplicationsState {
listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse;
siteRes: GetSiteResponse;
unreadOrAll: UnreadOrAll;
page: number;
page: bigint;
loading: boolean;
}
@ -50,7 +50,7 @@ export class RegistrationApplications extends Component<
state: RegistrationApplicationsState = {
siteRes: this.isoData.site_res,
unreadOrAll: UnreadOrAll.Unread,
page: 1,
page: 1n,
loading: true,
};
@ -188,11 +188,11 @@ export class RegistrationApplications extends Component<
}
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();
}
handlePageChange(page: number) {
handlePageChange(page: bigint) {
this.setState({ page });
this.refetch();
}
@ -204,7 +204,7 @@ export class RegistrationApplications extends Component<
if (auth) {
let form: ListRegistrationApplications = {
unread_only: true,
page: 1,
page: 1n,
limit: fetchLimit,
auth,
};
@ -254,7 +254,7 @@ export class RegistrationApplications extends Component<
);
let uacs = UserService.Instance.unreadApplicationCountSub;
// 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);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,6 @@ import {
BlockCommunityResponse,
BlockPersonResponse,
Comment as CommentI,
CommentNode as CommentNodeI,
CommentReportView,
CommentSortType,
CommentView,
@ -16,16 +15,15 @@ import {
Language,
LemmyHttp,
LemmyWebsocket,
ListingType,
PersonSafe,
PersonViewSafe,
MyUserInfo,
Person,
PersonView,
PostReportView,
PostView,
PrivateMessageReportView,
PrivateMessageView,
RegistrationApplicationView,
Search,
SearchType,
SortType,
UploadImageResponse,
} from "lemmy-js-client";
@ -45,7 +43,7 @@ import tippy from "tippy.js";
import Toastify from "toastify-js";
import { httpBase } from "./env";
import { i18n, languages } from "./i18next";
import { DataType, IsoData } from "./interfaces";
import { CommentNodeI, DataType, IsoData } from "./interfaces";
import { UserService, WebSocketService } from "./services";
var Tribute: any;
@ -72,12 +70,12 @@ export const webArchiveUrl = "https://web.archive.org";
export const elementUrl = "https://element.io";
export const postRefetchSeconds: number = 60 * 1000;
export const fetchLimit = 40;
export const trendingFetchLimit = 6;
export const fetchLimit = 40n;
export const trendingFetchLimit = 6n;
export const mentionDropdownFetchLimit = 10;
export const commentTreeMaxDepth = 8;
export const markdownFieldCharacterLimit = 50000;
export const maxUploadImages = 20;
export const maxUploadImages = 20n;
export const concurrentImageUpload = 4;
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;
}
export function getPageFromString(page?: string): number {
return page && !Number.isNaN(Number(page)) ? Number(page) : 1;
export function getPageFromString(page?: string): bigint {
return page && !Number.isNaN(Number(page)) ? BigInt(page) : BigInt(1);
}
export function randomStr(
@ -187,14 +185,14 @@ export function hotRankPost(post_view: PostView): number {
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
let date: Date = new Date(timeStr + "Z"); // Add Z to convert from UTC date
let now: Date = new Date();
let hoursElapsed: number = (now.getTime() - date.getTime()) / 36e5;
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);
// 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) };
}
export function getUnixTime(text?: string): number | undefined {
return text ? new Date(text).getTime() / 1000 : undefined;
export function getUnixTime(text?: string): bigint | 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
? Math.trunc(
? BigInt(
Math.trunc(
new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000
)
)
: undefined;
}
export function canMod(
creator_id: number,
mods?: CommunityModeratorView[],
admins?: PersonViewSafe[],
admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo,
onSelf = false
): boolean {
@ -257,7 +257,7 @@ export function canMod(
export function canAdmin(
creatorId: number,
admins?: PersonViewSafe[],
admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo,
onSelf = false
): boolean {
@ -278,7 +278,7 @@ export function amMod(
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;
}
@ -298,7 +298,7 @@ export function amCommunityCreator(
export function amSiteCreator(
creator_id: number,
admins?: PersonViewSafe[],
admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo
): boolean {
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);
}
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) {
let form: GetSiteMetadata = { url };
let client = new LemmyHttp(httpBase);
@ -901,7 +865,7 @@ export function setupTippy() {
interface PersonTribute {
key: string;
view: PersonViewSafe;
view: PersonView;
}
async function personSearch(text: string): Promise<PersonTribute[]> {
@ -972,7 +936,7 @@ export function saveCommentRes(data: CommentView, comments?: CommentView[]) {
export function updatePersonBlock(
data: BlockPersonResponse,
myUserInfo = UserService.Instance.myUserInfo
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
) {
let mui = myUserInfo;
if (mui) {
@ -993,7 +957,7 @@ export function updatePersonBlock(
export function updateCommunityBlock(
data: BlockCommunityResponse,
myUserInfo = UserService.Instance.myUserInfo
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
) {
let mui = myUserInfo;
if (mui) {
@ -1124,19 +1088,19 @@ export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
export function convertCommentSortType(sort: SortType): CommentSortType {
if (
sort == SortType.TopAll ||
sort == SortType.TopDay ||
sort == SortType.TopWeek ||
sort == SortType.TopMonth ||
sort == SortType.TopYear
sort == "TopAll" ||
sort == "TopDay" ||
sort == "TopWeek" ||
sort == "TopMonth" ||
sort == "TopYear"
) {
return CommentSortType.Top;
} else if (sort == SortType.New) {
return CommentSortType.New;
} else if (sort == SortType.Hot || sort == SortType.Active) {
return CommentSortType.Hot;
return "Top";
} else if (sort == "New") {
return "New";
} else if (sort == "Hot" || sort == "Active") {
return "Hot";
} else {
return CommentSortType.Hot;
return "Hot";
}
}
@ -1359,8 +1323,7 @@ export function restoreScrollPosition(context: any) {
}
export function showLocal(isoData: IsoData): boolean {
let linked = isoData.site_res.federated_instances?.linked;
return linked ? linked.length > 0 : false;
return isoData.site_res.site_view.local_site.federation_enabled;
}
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 {
value: pvs.person.id.toString(),
label: personSelectName(pvs),
@ -1392,10 +1355,10 @@ export function personToChoice(pvs: PersonViewSafe): Choice {
export async function fetchCommunities(q: string) {
let form: Search = {
q,
type_: SearchType.Communities,
sort: SortType.TopAll,
listing_type: ListingType.All,
page: 1,
type_: "Communities",
sort: "TopAll",
listing_type: "All",
page: 1n,
limit: fetchLimit,
auth: myAuth(false),
};
@ -1406,10 +1369,10 @@ export async function fetchCommunities(q: string) {
export async function fetchUsers(q: string) {
let form: Search = {
q,
type_: SearchType.Users,
sort: SortType.TopAll,
listing_type: ListingType.All,
page: 1,
type_: "Users",
sort: "TopAll",
listing_type: "All",
page: 1n,
limit: fetchLimit,
auth: myAuth(false),
};
@ -1425,7 +1388,7 @@ export function communitySelectName(cv: CommunityView): string {
export function personSelectName({
person: { display_name, name, local, actor_id },
}: PersonViewSafe): string {
}: PersonView): string {
const pName = display_name ?? name;
return local ? pName : `${hostname(actor_id)}/${pName}`;
}
@ -1444,11 +1407,11 @@ const SHORTNUM_SI_FORMAT = new Intl.NumberFormat("en-US", {
compactDisplay: "short",
});
export function numToSI(value: number): string {
export function numToSI(value: bigint): string {
return SHORTNUM_SI_FORMAT.format(value);
}
export function isBanned(ps: PersonSafe): boolean {
export function isBanned(ps: Person): boolean {
let expires = ps.ban_expires;
// Add Z to convert from UTC date
// TODO this check probably isn't necessary anymore
@ -1477,16 +1440,16 @@ export function enableNsfw(siteRes: GetSiteResponse): boolean {
export function postToCommentSortType(sort: SortType): CommentSortType {
switch (sort) {
case SortType.Active:
case SortType.Hot:
return CommentSortType.Hot;
case SortType.New:
case SortType.NewComments:
return CommentSortType.New;
case SortType.Old:
return CommentSortType.Old;
case "Active":
case "Hot":
return "Hot";
case "New":
case "NewComments":
return "New";
case "Old":
return "Old";
default:
return CommentSortType.Top;
return "Top";
}
}
@ -1515,7 +1478,7 @@ export function canCreateCommunity(
export function isPostBlocked(
pv: PostView,
myUserInfo = UserService.Instance.myUserInfo
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo
): boolean {
return (
(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"
integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==
lemmy-js-client@0.17.2-rc.5:
version "0.17.2-rc.5"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.2-rc.5.tgz#8dbfa01fc293d63d72d8294d5584d4e71c9c08be"
integrity sha512-B2VibqJvevVDiYK7yfMPZrx0GdC4XgpN2bgouzMgXZsn+HENALIAm5K+sZhD40/NCd69MglWTlYtFYg9d4YxOA==
lemmy-js-client@0.17.2-rc.14:
version "0.17.2-rc.14"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.2-rc.14.tgz#2734c52a4216e4045c1b63ad0e4e302e72463d12"
integrity sha512-HERUQL3UChSjY1pLeyAJ/4dBS+YMEoq0MBUW3Q45s6GjcjSJyE3l5JKC6qlozyDX3oc462NNel/rP1/qNQRvZQ==
dependencies:
cross-fetch "^3.1.5"
form-data "^4.0.0"