FROM node:14-alpine as builder\r
-RUN apk update && apk add yarn curl bash && rm -rf /var/cache/apk/*\r
+RUN apk add yarn curl bash --no-cache\r
\r
RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash -s -- -b /usr/local/bin\r
\r
\r
# Pruning\r
# RUN npm prune --production\r
-RUN /usr/local/bin/node-prune\r
+RUN node-prune\r
\r
FROM node:14-alpine as runner\r
COPY --from=builder /usr/src/app/dist /app/dist\r
},
"repository": "https://github.com/LemmyNet/lemmy-ui",
"dependencies": {
- "@typescript-eslint/parser": "^4.9.1",
+ "@typescript-eslint/parser": "^4.11.0",
"autosize": "^4.0.2",
"choices.js": "^9.0.1",
"emoji-short-name": "^1.0.0",
"inferno-server": "^7.4.6",
"isomorphic-cookie": "^1.2.4",
"jwt-decode": "^3.1.2",
- "markdown-it": "^12.0.3",
+ "markdown-it": "^12.0.4",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"moment": "^2.29.1",
"reconnecting-websocket": "^4.4.0",
- "register-service-worker": "^1.7.1",
+ "register-service-worker": "^1.7.2",
"rxjs": "^6.6.3",
"serialize-javascript": "^5.0.1",
"tippy.js": "^6.2.7",
"ws": "^7.4.1"
},
"devDependencies": {
- "@babel/core": "^7.12.9",
- "@babel/plugin-transform-runtime": "^7.12.1",
+ "@babel/core": "^7.12.10",
+ "@babel/plugin-transform-runtime": "^7.12.10",
"@babel/plugin-transform-typescript": "^7.12.1",
- "@babel/preset-env": "7.12.7",
+ "@babel/preset-env": "7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@types/autosize": "^3.0.6",
"@types/express": "^4.17.9",
- "@types/node": "^14.14.11",
+ "@types/node": "^14.14.16",
"@types/node-fetch": "^2.5.7",
"@types/serialize-javascript": "^5.0.0",
"babel-loader": "^8.2.2",
"bootstrap": "^4.5.3",
"bootswatch": "^4.5.3",
"clean-webpack-plugin": "^3.0.0",
- "copy-webpack-plugin": "^6.4.0",
+ "copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
- "eslint": "^7.15.0",
- "eslint-plugin-jane": "^9.0.4",
- "husky": "^4.3.5",
- "lemmy-js-client": "^1.0.16",
+ "eslint": "^7.16.0",
+ "eslint-plugin-jane": "^9.0.6",
+ "husky": "^4.3.6",
+ "lemmy-js-client": "1.0.17-beta6",
"lint-staged": "^10.5.3",
- "mini-css-extract-plugin": "^1.3.2",
+ "mini-css-extract-plugin": "^1.3.3",
"node-fetch": "^2.6.1",
"node-sass": "^5.0.0",
"prettier": "^2.2.1",
"rimraf": "^3.0.2",
"run-node-webpack-plugin": "^1.3.0",
"sass-loader": "^10.1.0",
- "sortpack": "^2.1.10",
+ "sortpack": "^2.1.11",
"style-loader": "^2.0.0",
"terser": "^5.5.1",
- "typescript": "^4.1.2",
- "webpack": "5.10.0",
+ "typescript": "^4.1.3",
+ "webpack": "5.11.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "3.11.0",
"webpack-node-externals": "^2.5.2"
import { initializeSite } from '../shared/initialize';
import { App } from '../shared/components/app';
-const site = window.isoData.site;
+const site = window.isoData.site_res;
initializeSite(site);
const wrapper = (
<BrowserRouter>
- <App site={window.isoData.site} />
+ <App siteRes={window.isoData.site_res} />
</BrowserRouter>
);
import { InitialFetchRequest, IsoData } from '../shared/interfaces';
import { routes } from '../shared/routes';
import IsomorphicCookie from 'isomorphic-cookie';
-import { setAuth } from '../shared/utils';
-import { GetSiteForm, LemmyHttp } from 'lemmy-js-client';
+import { GetSite, LemmyHttp } from 'lemmy-js-client';
import process from 'process';
import { Helmet } from 'inferno-helmet';
import { initializeSite } from '../shared/initialize';
import { httpUri } from '../shared/env';
import { IncomingHttpHeaders } from 'http';
+import { setOptionalAuth } from '../shared/utils';
const server = express();
const port = 1234;
const context = {} as any;
let auth: string = IsomorphicCookie.load('jwt', req);
- let getSiteForm: GetSiteForm = {};
- setAuth(getSiteForm, auth);
+ let getSiteForm: GetSite = {};
+ setOptionalAuth(getSiteForm, auth);
let promises: Promise<any>[] = [];
let isoData: IsoData = {
path: req.path,
- site,
+ site_res: site,
routeData,
lang,
};
const wrapper = (
<StaticRouter location={req.url} context={isoData}>
- <App site={isoData.site} />
+ <App siteRes={isoData.site_res} />
</StaticRouter>
);
if (context.url) {
UserOperation,
SiteResponse,
GetSiteResponse,
- SiteConfigForm,
+ SaveSiteConfig,
GetSiteConfigResponse,
- WebSocketJsonResponse,
GetSiteConfig,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
setIsoData,
wsSubscribe,
isBrowser,
- setAuth,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import autosize from 'autosize';
import { SiteForm } from './site-form';
interface AdminSettingsState {
siteRes: GetSiteResponse;
siteConfigRes: GetSiteConfigResponse;
- siteConfigForm: SiteConfigForm;
+ siteConfigForm: SaveSiteConfig;
loading: boolean;
siteConfigLoading: boolean;
}
private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: AdminSettingsState = {
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
siteConfigForm: {
config_hjson: null,
- auth: null,
+ auth: authField(),
},
siteConfigRes: {
config_hjson: null,
this.state.siteConfigLoading = false;
this.state.loading = false;
} else {
- WebSocketService.Instance.getSiteConfig();
+ WebSocketService.Instance.send(
+ wsClient.getSiteConfig({
+ auth: authField(),
+ })
+ );
}
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
- let form: GetSiteConfig = {};
- setAuth(form, req.auth);
+ let form: GetSiteConfig = { auth: req.auth };
return [req.client.getSiteConfig(form)];
}
}
get documentTitle(): string {
- return `${i18n.t('admin_settings')} - ${this.state.siteRes.site.name}`;
+ return `${i18n.t('admin_settings')} - ${
+ this.state.siteRes.site_view.site.name
+ }`;
}
render() {
) : (
<div class="row">
<div class="col-12 col-md-6">
- {this.state.siteRes.site.id && (
- <SiteForm site={this.state.siteRes.site} />
+ {this.state.siteRes.site_view.site.id && (
+ <SiteForm site={this.state.siteRes.site_view.site} />
)}
{this.admins()}
{this.bannedUsers()}
<ul class="list-unstyled">
{this.state.siteRes.admins.map(admin => (
<li class="list-inline-item">
- <UserListing
- user={{
- name: admin.name,
- preferred_username: admin.preferred_username,
- avatar: admin.avatar,
- id: admin.id,
- local: admin.local,
- actor_id: admin.actor_id,
- }}
- />
+ <UserListing user={admin.user} />
</li>
))}
</ul>
<ul class="list-unstyled">
{this.state.siteRes.banned.map(banned => (
<li class="list-inline-item">
- <UserListing
- user={{
- name: banned.name,
- preferred_username: banned.preferred_username,
- avatar: banned.avatar,
- id: banned.id,
- local: banned.local,
- actor_id: banned.actor_id,
- }}
- />
+ <UserListing user={banned.user} />
</li>
))}
</ul>
handleSiteConfigSubmit(i: AdminSettings, event: any) {
event.preventDefault();
i.state.siteConfigLoading = true;
- WebSocketService.Instance.saveSiteConfig(i.state.siteConfigForm);
+ WebSocketService.Instance.send(
+ wsClient.saveSiteConfig(i.state.siteConfigForm)
+ );
i.setState(i.state);
}
i.setState(i.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.context.router.history.push('/');
this.setState(this.state);
return;
} else if (msg.reconnect) {
- } else if (res.op == UserOperation.EditSite) {
- let data = res.data as SiteResponse;
- this.state.siteRes.site = data.site;
+ } else if (op == UserOperation.EditSite) {
+ let data = wsJsonToRes<SiteResponse>(msg).data;
+ this.state.siteRes.site_view = data.site_view;
this.setState(this.state);
toast(i18n.t('site_saved'));
- } else if (res.op == UserOperation.GetSiteConfig) {
- let data = res.data as GetSiteConfigResponse;
+ } else if (op == UserOperation.GetSiteConfig) {
+ let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
this.state.siteConfigRes = data;
this.state.loading = false;
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
this.setState(this.state);
var textarea: any = document.getElementById(this.siteConfigTextAreaId);
autosize(textarea);
- } else if (res.op == UserOperation.SaveSiteConfig) {
- let data = res.data as GetSiteConfigResponse;
+ } else if (op == UserOperation.SaveSiteConfig) {
+ let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
this.state.siteConfigRes = data;
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
this.state.siteConfigLoading = false;
import './styles.scss';
export interface AppProps {
- site: GetSiteResponse;
+ siteRes: GetSiteResponse;
}
export class App extends Component<AppProps, any> {
super(props, context);
}
render() {
+ let siteRes = this.props.siteRes;
return (
<>
<Provider i18next={i18n}>
<div>
- <Theme user={this.props.site.my_user} />
- {this.props.site &&
- this.props.site.site &&
- this.props.site.site.icon && (
+ <Theme user={siteRes.my_user} />
+ {siteRes &&
+ siteRes.site_view &&
+ this.props.siteRes.site_view.site.icon && (
<Helmet>
<link
id="favicon"
rel="icon"
type="image/x-icon"
- href={this.props.site.site.icon}
+ href={this.props.siteRes.site_view.site.icon}
/>
</Helmet>
)}
- <Navbar site={this.props.site} />
+ <Navbar site_res={this.props.siteRes} />
<div class="mt-4 p-0 fl-1">
<Switch>
{routes.map(({ path, exact, component: C, ...rest }) => (
</Switch>
<Symbols />
</div>
- <Footer site={this.props.site} />
+ <Footer site={this.props.siteRes} />
</div>
</Provider>
</>
import { Link } from 'inferno-router';
import { Subscription } from 'rxjs';
import {
- CommentNode as CommentNodeI,
- CommentForm as CommentFormI,
- WebSocketJsonResponse,
+ CreateComment,
+ EditComment,
UserOperation,
CommentResponse,
} from 'lemmy-js-client';
-import { capitalizeFirstLetter, wsJsonToRes, wsSubscribe } from '../utils';
+import { CommentNode as CommentNodeI } from '../interfaces';
+import {
+ authField,
+ capitalizeFirstLetter,
+ wsClient,
+ wsJsonToRes,
+ wsSubscribe,
+ wsUserOp,
+} from '../utils';
import { WebSocketService, UserService } from '../services';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
interface CommentFormProps {
postId?: number;
- node?: CommentNodeI;
- onReplyCancel?(): any;
+ node?: CommentNodeI; // Can either be the parent, or the editable comment
edit?: boolean;
disabled?: boolean;
focus?: boolean;
+ onReplyCancel?(): any;
}
interface CommentFormState {
- commentForm: CommentFormI;
buttonTitle: string;
finished: boolean;
+ formId: string;
}
export class CommentForm extends Component<CommentFormProps, CommentFormState> {
private subscription: Subscription;
private emptyState: CommentFormState = {
- commentForm: {
- auth: null,
- content: null,
- post_id: this.props.node
- ? this.props.node.comment.post_id
- : this.props.postId,
- creator_id: UserService.Instance.user
- ? UserService.Instance.user.id
- : null,
- },
buttonTitle: !this.props.node
? capitalizeFirstLetter(i18n.t('post'))
: this.props.edit
? capitalizeFirstLetter(i18n.t('save'))
: capitalizeFirstLetter(i18n.t('reply')),
finished: false,
+ formId: null,
};
constructor(props: any, context: any) {
this.state = this.emptyState;
- if (this.props.node) {
- if (this.props.edit) {
- this.state.commentForm.edit_id = this.props.node.comment.id;
- this.state.commentForm.parent_id = this.props.node.comment.parent_id;
- this.state.commentForm.content = this.props.node.comment.content;
- this.state.commentForm.creator_id = this.props.node.comment.creator_id;
- } else {
- // A reply gets a new parent id
- this.state.commentForm.parent_id = this.props.node.comment.id;
- }
- }
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
}
<div class="mb-3">
{UserService.Instance.user ? (
<MarkdownTextArea
- initialContent={this.state.commentForm.content}
+ initialContent={
+ this.props.edit
+ ? this.props.node.comment_view.comment.content
+ : null
+ }
buttonTitle={this.state.buttonTitle}
finished={this.state.finished}
replyType={!!this.props.node}
}
handleCommentSubmit(msg: { val: string; formId: string }) {
- this.state.commentForm.content = msg.val;
- this.state.commentForm.form_id = msg.formId;
+ let content = msg.val;
+ this.state.formId = msg.formId;
+
+ let node = this.props.node;
+
if (this.props.edit) {
- WebSocketService.Instance.editComment(this.state.commentForm);
+ let form: EditComment = {
+ content,
+ form_id: this.state.formId,
+ edit_id: node.comment_view.comment.id,
+ auth: authField(),
+ };
+ WebSocketService.Instance.send(wsClient.editComment(form));
} else {
- WebSocketService.Instance.createComment(this.state.commentForm);
+ let form: CreateComment = {
+ content,
+ form_id: this.state.formId,
+ post_id: node ? node.comment_view.post.id : this.props.postId,
+ parent_id: node ? node.comment_view.comment.id : null,
+ auth: authField(),
+ };
+ WebSocketService.Instance.send(wsClient.createComment(form));
}
this.setState(this.state);
}
this.props.onReplyCancel();
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
// Only do the showing and hiding if logged in
if (UserService.Instance.user) {
if (
- res.op == UserOperation.CreateComment ||
- res.op == UserOperation.EditComment
+ op == UserOperation.CreateComment ||
+ op == UserOperation.EditComment
) {
- let data = res.data as CommentResponse;
+ let data = wsJsonToRes<CommentResponse>(msg).data;
// This only finishes this form, if the randomly generated form_id matches the one received
- if (this.state.commentForm.form_id == data.form_id) {
+ if (this.state.formId == data.form_id) {
this.setState({ finished: true });
- // Necessary because it broke tribute for some reaso
+ // Necessary because it broke tribute for some reason
this.setState({ finished: false });
}
}
import { Component, linkEvent } from 'inferno';
import { Link } from 'inferno-router';
import {
- CommentNode as CommentNodeI,
- CommentLikeForm,
- DeleteCommentForm,
- RemoveCommentForm,
- MarkCommentAsReadForm,
- MarkUserMentionAsReadForm,
- SaveCommentForm,
- BanFromCommunityForm,
- BanUserForm,
- CommunityUser,
- UserView,
- AddModToCommunityForm,
- AddAdminForm,
- TransferCommunityForm,
- TransferSiteForm,
+ CreateCommentLike,
+ DeleteComment,
+ RemoveComment,
+ MarkCommentAsRead,
+ MarkUserMentionAsRead,
+ SaveComment,
+ BanFromCommunity,
+ BanUser,
+ CommunityModeratorView,
+ UserViewSafe,
+ AddModToCommunity,
+ AddAdmin,
+ TransferCommunity,
+ TransferSite,
SortType,
+ CommentView,
+ UserMentionView,
} from 'lemmy-js-client';
-import { CommentSortType, BanType } from '../interfaces';
+import {
+ CommentSortType,
+ CommentNode as CommentNodeI,
+ BanType,
+} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import {
mdToHtml,
isMod,
setupTippy,
colorList,
+ wsClient,
+ authField,
} from '../utils';
import moment from 'moment';
import { MomentTime } from './moment-time';
locked?: boolean;
markable?: boolean;
showContext?: boolean;
- moderators: CommunityUser[];
- admins: UserView[];
+ moderators: CommunityModeratorView[];
+ admins: UserViewSafe[];
// TODO is this necessary, can't I get it from the node itself?
postCreatorId?: number;
showCommunity?: boolean;
showConfirmTransferCommunity: false,
showConfirmAppointAsMod: false,
showConfirmAppointAsAdmin: false,
- my_vote: this.props.node.comment.my_vote,
- score: this.props.node.comment.score,
- upvotes: this.props.node.comment.upvotes,
- downvotes: this.props.node.comment.downvotes,
- borderColor: this.props.node.comment.depth
- ? colorList[this.props.node.comment.depth % colorList.length]
+ my_vote: this.props.node.comment_view.my_vote,
+ score: this.props.node.comment_view.counts.score,
+ upvotes: this.props.node.comment_view.counts.upvotes,
+ downvotes: this.props.node.comment_view.counts.downvotes,
+ borderColor: this.props.node.depth
+ ? colorList[this.props.node.depth % colorList.length]
: colorList[0],
readLoading: false,
saveLoading: false,
this.handleCommentDownvote = this.handleCommentDownvote.bind(this);
}
+ // TODO see if there's a better way to do this, and all willReceiveProps
componentWillReceiveProps(nextProps: CommentNodeProps) {
- this.state.my_vote = nextProps.node.comment.my_vote;
- this.state.upvotes = nextProps.node.comment.upvotes;
- this.state.downvotes = nextProps.node.comment.downvotes;
- this.state.score = nextProps.node.comment.score;
+ let cv = nextProps.node.comment_view;
+ this.state.my_vote = cv.my_vote;
+ this.state.upvotes = cv.counts.upvotes;
+ this.state.downvotes = cv.counts.downvotes;
+ this.state.score = cv.counts.score;
this.state.readLoading = false;
this.state.saveLoading = false;
this.setState(this.state);
render() {
let node = this.props.node;
+ let cv = this.props.node.comment_view;
return (
<div
className={`comment ${
- node.comment.parent_id && !this.props.noIndent ? 'ml-1' : ''
+ cv.comment.parent_id && !this.props.noIndent ? 'ml-1' : ''
}`}
>
<div
- id={`comment-${node.comment.id}`}
+ id={`comment-${cv.comment.id}`}
className={`details comment-node py-2 ${
!this.props.noBorder ? 'border-top border-light' : ''
} ${this.isCommentNew ? 'mark' : ''}`}
style={
!this.props.noIndent &&
- this.props.node.comment.parent_id &&
+ cv.comment.parent_id &&
`border-left: 2px ${this.state.borderColor} solid !important`
}
>
<div
- class={`${
- !this.props.noIndent &&
- this.props.node.comment.parent_id &&
- 'ml-2'
- }`}
+ class={`${!this.props.noIndent && cv.comment.parent_id && 'ml-2'}`}
>
<div class="d-flex flex-wrap align-items-center text-muted small">
<span class="mr-2">
- <UserListing
- user={{
- name: node.comment.creator_name,
- preferred_username: node.comment.creator_preferred_username,
- avatar: node.comment.creator_avatar,
- id: node.comment.creator_id,
- local: node.comment.creator_local,
- actor_id: node.comment.creator_actor_id,
- published: node.comment.creator_published,
- }}
- />
+ <UserListing user={cv.creator} />
</span>
{this.isMod && (
{i18n.t('creator')}
</div>
)}
- {(node.comment.banned_from_community || node.comment.banned) && (
+ {(cv.creator_banned_from_community || cv.creator.banned) && (
<div className="badge badge-danger mr-2">
{i18n.t('banned')}
</div>
{this.props.showCommunity && (
<>
<span class="mx-1">{i18n.t('to')}</span>
- <CommunityLink
- community={{
- name: node.comment.community_name,
- id: node.comment.community_id,
- local: node.comment.community_local,
- actor_id: node.comment.community_actor_id,
- icon: node.comment.community_icon,
- }}
- />
+ <CommunityLink community={cv.community} />
<span class="mx-2">•</span>
- <Link className="mr-2" to={`/post/${node.comment.post_id}`}>
- {node.comment.post_name}
+ <Link className="mr-2" to={`/post/${cv.post.id}`}>
+ {cv.post.name}
</Link>
</>
)}
</a>
<span className="mr-1">•</span>
<span>
- <MomentTime data={node.comment} />
+ <MomentTime data={cv.comment} />
</span>
</div>
{/* end of user row */}
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={
- node.comment.read
+ cv.comment.read
? i18n.t('mark_as_unread')
: i18n.t('mark_as_read')
}
) : (
<svg
class={`icon icon-inline ${
- node.comment.read && 'text-success'
+ cv.comment.read && 'text-success'
}`}
>
<use xlinkHref="#icon-check"></use>
<button class="btn btn-link btn-animate">
<Link
className="text-muted"
- to={`/create_private_message/recipient/${node.comment.creator_id}`}
+ to={`/create_private_message/recipient/${cv.creator.id}`}
title={i18n.t('message').toLowerCase()}
>
<svg class="icon">
this.handleSaveCommentClick
)}
data-tippy-content={
- node.comment.saved
- ? i18n.t('unsave')
- : i18n.t('save')
+ cv.saved ? i18n.t('unsave') : i18n.t('save')
}
>
{this.state.saveLoading ? (
) : (
<svg
class={`icon icon-inline ${
- node.comment.saved && 'text-warning'
+ cv.saved && 'text-warning'
}`}
>
<use xlinkHref="#icon-star"></use>
this.handleDeleteClick
)}
data-tippy-content={
- !node.comment.deleted
+ !cv.comment.deleted
? i18n.t('delete')
: i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
- node.comment.deleted && 'text-danger'
+ cv.comment.deleted && 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
{/* Admins and mods can remove comments */}
{(this.canMod || this.canAdmin) && (
<>
- {!node.comment.removed ? (
+ {!cv.comment.removed ? (
<button
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
{this.canMod && (
<>
{!this.isMod &&
- (!node.comment.banned_from_community ? (
+ (!cv.creator_banned_from_community ? (
<button
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
{i18n.t('unban')}
</button>
))}
- {!node.comment.banned_from_community &&
- node.comment.creator_local &&
+ {!cv.creator_banned_from_community &&
+ cv.creator.local &&
(!this.state.showConfirmAppointAsMod ? (
<button
class="btn btn-link btn-animate text-muted"
{/* Community creators and admins can transfer community to another mod */}
{(this.amCommunityCreator || this.canAdmin) &&
this.isMod &&
- node.comment.creator_local &&
+ cv.creator.local &&
(!this.state.showConfirmTransferCommunity ? (
<button
class="btn btn-link btn-animate text-muted"
{this.canAdmin && (
<>
{!this.isAdmin &&
- (!node.comment.banned ? (
+ (!cv.creator.banned ? (
<button
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(
{i18n.t('unban_from_site')}
</button>
))}
- {!node.comment.banned &&
- node.comment.creator_local &&
+ {!cv.creator.banned &&
+ cv.creator.local &&
(!this.state.showConfirmAppointAsAdmin ? (
<button
class="btn btn-link btn-animate text-muted"
{/* Site Creator can transfer to another admin */}
{this.amSiteCreator &&
this.isAdmin &&
- node.comment.creator_local &&
+ cv.creator.local &&
(!this.state.showConfirmTransferSite ? (
<button
class="btn btn-link btn-animate text-muted"
{/* </div> */}
<div class="form-group row">
<button type="submit" class="btn btn-secondary">
- {i18n.t('ban')} {node.comment.creator_name}
+ {i18n.t('ban')} {cv.creator.name}
</button>
</div>
</form>
}
get linkBtn() {
- let node = this.props.node;
+ let cv = this.props.node.comment_view;
return (
<Link
className="btn btn-link btn-animate text-muted"
- to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
+ to={`/post/${cv.post.id}/comment/${cv.comment.id}`}
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')}
>
<svg class="icon icon-inline">
get myComment(): boolean {
return (
UserService.Instance.user &&
- this.props.node.comment.creator_id == UserService.Instance.user.id
+ this.props.node.comment_view.creator.id == UserService.Instance.user.id
);
}
return (
this.props.moderators &&
isMod(
- this.props.moderators.map(m => m.user_id),
- this.props.node.comment.creator_id
+ this.props.moderators.map(m => m.moderator.id),
+ this.props.node.comment_view.creator.id
)
);
}
return (
this.props.admins &&
isMod(
- this.props.admins.map(a => a.id),
- this.props.node.comment.creator_id
+ this.props.admins.map(a => a.user.id),
+ this.props.node.comment_view.creator.id
)
);
}
get isPostCreator(): boolean {
- return this.props.node.comment.creator_id == this.props.postCreatorId;
+ return this.props.node.comment_view.creator.id == this.props.postCreatorId;
}
get canMod(): boolean {
if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins
- .map(a => a.id)
- .concat(this.props.moderators.map(m => m.user_id));
+ .map(a => a.user.id)
+ .concat(this.props.moderators.map(m => m.moderator.id));
return canMod(
UserService.Instance.user,
adminsThenMods,
- this.props.node.comment.creator_id
+ this.props.node.comment_view.creator.id
);
} else {
return false;
this.props.admins &&
canMod(
UserService.Instance.user,
- this.props.admins.map(a => a.id),
- this.props.node.comment.creator_id
+ this.props.admins.map(a => a.user.id),
+ this.props.node.comment_view.creator.id
)
);
}
return (
this.props.moderators &&
UserService.Instance.user &&
- this.props.node.comment.creator_id != UserService.Instance.user.id &&
- UserService.Instance.user.id == this.props.moderators[0].user_id
+ this.props.node.comment_view.creator.id != UserService.Instance.user.id &&
+ UserService.Instance.user.id == this.props.moderators[0].moderator.id
);
}
return (
this.props.admins &&
UserService.Instance.user &&
- this.props.node.comment.creator_id != UserService.Instance.user.id &&
- UserService.Instance.user.id == this.props.admins[0].id
+ this.props.node.comment_view.creator.id != UserService.Instance.user.id &&
+ UserService.Instance.user.id == this.props.admins[0].user.id
);
}
get commentUnlessRemoved(): string {
- let node = this.props.node;
- return node.comment.removed
+ let comment = this.props.node.comment_view.comment;
+ return comment.removed
? `*${i18n.t('removed')}*`
- : node.comment.deleted
+ : comment.deleted
? `*${i18n.t('deleted')}*`
- : node.comment.content;
+ : comment.content;
}
handleReplyClick(i: CommentNode) {
}
handleDeleteClick(i: CommentNode) {
- let deleteForm: DeleteCommentForm = {
- edit_id: i.props.node.comment.id,
- deleted: !i.props.node.comment.deleted,
- auth: null,
+ let comment = i.props.node.comment_view.comment;
+ let deleteForm: DeleteComment = {
+ edit_id: comment.id,
+ deleted: !comment.deleted,
+ auth: authField(),
};
- WebSocketService.Instance.deleteComment(deleteForm);
+ WebSocketService.Instance.send(wsClient.deleteComment(deleteForm));
}
handleSaveCommentClick(i: CommentNode) {
- let saved =
- i.props.node.comment.saved == undefined
- ? true
- : !i.props.node.comment.saved;
- let form: SaveCommentForm = {
- comment_id: i.props.node.comment.id,
- save: saved,
+ let cv = i.props.node.comment_view;
+ let save = cv.saved == undefined ? true : !cv.saved;
+ let form: SaveComment = {
+ comment_id: cv.comment.id,
+ save,
+ auth: authField(),
};
- WebSocketService.Instance.saveComment(form);
+ WebSocketService.Instance.send(wsClient.saveComment(form));
i.state.saveLoading = true;
i.setState(this.state);
this.state.my_vote = new_vote;
- let form: CommentLikeForm = {
- comment_id: i.comment.id,
+ let form: CreateCommentLike = {
+ comment_id: i.comment_view.comment.id,
score: this.state.my_vote,
+ auth: authField(),
};
- WebSocketService.Instance.likeComment(form);
+ WebSocketService.Instance.send(wsClient.likeComment(form));
this.setState(this.state);
setupTippy();
}
this.state.my_vote = new_vote;
- let form: CommentLikeForm = {
- comment_id: i.comment.id,
+ let form: CreateCommentLike = {
+ comment_id: i.comment_view.comment.id,
score: this.state.my_vote,
+ auth: authField(),
};
- WebSocketService.Instance.likeComment(form);
+ WebSocketService.Instance.send(wsClient.likeComment(form));
this.setState(this.state);
setupTippy();
}
}
handleModRemoveSubmit(i: CommentNode) {
- event.preventDefault();
- let form: RemoveCommentForm = {
- edit_id: i.props.node.comment.id,
- removed: !i.props.node.comment.removed,
+ let comment = i.props.node.comment_view.comment;
+ let form: RemoveComment = {
+ edit_id: comment.id,
+ removed: !comment.removed,
reason: i.state.removeReason,
- auth: null,
+ auth: authField(),
};
- WebSocketService.Instance.removeComment(form);
+ WebSocketService.Instance.send(wsClient.removeComment(form));
i.state.showRemoveDialog = false;
i.setState(i.state);
}
+ isUserMentionType(
+ item: CommentView | UserMentionView
+ ): item is UserMentionView {
+ return (item as UserMentionView).user_mention.id !== undefined;
+ }
+
handleMarkRead(i: CommentNode) {
- // if it has a user_mention_id field, then its a mention
- if (i.props.node.comment.user_mention_id) {
- let form: MarkUserMentionAsReadForm = {
- user_mention_id: i.props.node.comment.user_mention_id,
- read: !i.props.node.comment.read,
+ if (i.isUserMentionType(i.props.node.comment_view)) {
+ let form: MarkUserMentionAsRead = {
+ user_mention_id: i.props.node.comment_view.user_mention.id,
+ read: !i.props.node.comment_view.user_mention.read,
+ auth: authField(),
};
- WebSocketService.Instance.markUserMentionAsRead(form);
+ WebSocketService.Instance.send(wsClient.markUserMentionAsRead(form));
} else {
- let form: MarkCommentAsReadForm = {
- edit_id: i.props.node.comment.id,
- read: !i.props.node.comment.read,
- auth: null,
+ let form: MarkCommentAsRead = {
+ comment_id: i.props.node.comment_view.comment.id,
+ read: !i.props.node.comment_view.comment.read,
+ auth: authField(),
};
- WebSocketService.Instance.markCommentAsRead(form);
+ WebSocketService.Instance.send(wsClient.markCommentAsRead(form));
}
i.state.readLoading = true;
}
handleModBanBothSubmit(i: CommentNode) {
- event.preventDefault();
+ let cv = i.props.node.comment_view;
if (i.state.banType == BanType.Community) {
// If its an unban, restore all their data
- let ban = !i.props.node.comment.banned_from_community;
+ let ban = !cv.creator_banned_from_community;
if (ban == false) {
i.state.removeData = false;
}
- let form: BanFromCommunityForm = {
- user_id: i.props.node.comment.creator_id,
- community_id: i.props.node.comment.community_id,
+ let form: BanFromCommunity = {
+ user_id: cv.creator.id,
+ community_id: cv.community.id,
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
+ auth: authField(),
};
- WebSocketService.Instance.banFromCommunity(form);
+ WebSocketService.Instance.send(wsClient.banFromCommunity(form));
} else {
// If its an unban, restore all their data
- let ban = !i.props.node.comment.banned;
+ let ban = !cv.creator.banned;
if (ban == false) {
i.state.removeData = false;
}
- let form: BanUserForm = {
- user_id: i.props.node.comment.creator_id,
+ let form: BanUser = {
+ user_id: cv.creator.id,
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
+ auth: authField(),
};
- WebSocketService.Instance.banUser(form);
+ WebSocketService.Instance.send(wsClient.banUser(form));
}
i.state.showBanDialog = false;
}
handleAddModToCommunity(i: CommentNode) {
- let form: AddModToCommunityForm = {
- user_id: i.props.node.comment.creator_id,
- community_id: i.props.node.comment.community_id,
+ let cv = i.props.node.comment_view;
+ let form: AddModToCommunity = {
+ user_id: cv.creator.id,
+ community_id: cv.community.id,
added: !i.isMod,
+ auth: authField(),
};
- WebSocketService.Instance.addModToCommunity(form);
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
i.state.showConfirmAppointAsMod = false;
i.setState(i.state);
}
}
handleAddAdmin(i: CommentNode) {
- let form: AddAdminForm = {
- user_id: i.props.node.comment.creator_id,
+ let form: AddAdmin = {
+ user_id: i.props.node.comment_view.creator.id,
added: !i.isAdmin,
+ auth: authField(),
};
- WebSocketService.Instance.addAdmin(form);
+ WebSocketService.Instance.send(wsClient.addAdmin(form));
i.state.showConfirmAppointAsAdmin = false;
i.setState(i.state);
}
}
handleTransferCommunity(i: CommentNode) {
- let form: TransferCommunityForm = {
- community_id: i.props.node.comment.community_id,
- user_id: i.props.node.comment.creator_id,
+ let cv = i.props.node.comment_view;
+ let form: TransferCommunity = {
+ community_id: cv.community.id,
+ user_id: cv.creator.id,
+ auth: authField(),
};
- WebSocketService.Instance.transferCommunity(form);
+ WebSocketService.Instance.send(wsClient.transferCommunity(form));
i.state.showConfirmTransferCommunity = false;
i.setState(i.state);
}
}
handleTransferSite(i: CommentNode) {
- let form: TransferSiteForm = {
- user_id: i.props.node.comment.creator_id,
+ let form: TransferSite = {
+ user_id: i.props.node.comment_view.creator.id,
+ auth: authField(),
};
- WebSocketService.Instance.transferSite(form);
+ WebSocketService.Instance.send(wsClient.transferSite(form));
i.state.showConfirmTransferSite = false;
i.setState(i.state);
}
get isCommentNew(): boolean {
let now = moment.utc().subtract(10, 'minutes');
- let then = moment.utc(this.props.node.comment.published);
+ let then = moment.utc(this.props.node.comment_view.comment.published);
return now.isBefore(then);
}
import { Component } from 'inferno';
-import { CommentSortType } from '../interfaces';
+import { CommentSortType, CommentNode as CommentNodeI } from '../interfaces';
import {
- CommentNode as CommentNodeI,
- CommunityUser,
- UserView,
+ CommunityModeratorView,
+ UserViewSafe,
SortType,
} from 'lemmy-js-client';
import { commentSort, commentSortSortType } from '../utils';
interface CommentNodesProps {
nodes: CommentNodeI[];
- moderators?: CommunityUser[];
- admins?: UserView[];
+ moderators?: CommunityModeratorView[];
+ admins?: UserViewSafe[];
postCreatorId?: number;
noBorder?: boolean;
noIndent?: boolean;
<div className="comments">
{this.sorter().map(node => (
<CommentNode
- key={node.comment.id}
+ key={node.comment_view.comment.id}
node={node}
noBorder={this.props.noBorder}
noIndent={this.props.noIndent}
import { Subscription } from 'rxjs';
import {
UserOperation,
- Community,
+ CommunityView,
ListCommunitiesResponse,
CommunityResponse,
- FollowCommunityForm,
- ListCommunitiesForm,
+ FollowCommunity,
+ ListCommunities,
SortType,
- WebSocketJsonResponse,
- Site,
+ SiteView,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
import {
toast,
getPageFromProps,
isBrowser,
- setAuth,
setIsoData,
wsSubscribe,
+ wsUserOp,
+ wsClient,
+ authField,
+ setOptionalAuth,
} from '../utils';
import { CommunityLink } from './community-link';
import { i18n } from '../i18next';
const communityLimit = 100;
interface CommunitiesState {
- communities: Community[];
+ communities: CommunityView[];
page: number;
loading: boolean;
- site: Site;
+ site_view: SiteView;
}
interface CommunitiesProps {
communities: [],
loading: true,
page: getPageFromProps(this.props),
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
};
constructor(props: any, context: any) {
if (this.isoData.path == this.context.router.route.match.url) {
this.state.communities = this.isoData.routeData[0].communities;
this.state.communities.sort(
- (a, b) => b.number_of_subscribers - a.number_of_subscribers
+ (a, b) => b.counts.subscribers - a.counts.subscribers
);
this.state.loading = false;
} else {
}
get documentTitle(): string {
- return `${i18n.t('communities')} - ${this.state.site.name}`;
+ return `${i18n.t('communities')} - ${this.state.site_view.site.name}`;
}
render() {
</tr>
</thead>
<tbody>
- {this.state.communities.map(community => (
+ {this.state.communities.map(cv => (
<tr>
<td>
- <CommunityLink community={community} />
- </td>
- <td>{community.category_name}</td>
- <td class="text-right">
- {community.number_of_subscribers}
+ <CommunityLink community={cv.community} />
</td>
+ <td>{cv.category.name}</td>
+ <td class="text-right">{cv.counts.subscribers}</td>
<td class="text-right d-none d-lg-table-cell">
- {community.number_of_posts}
+ {cv.counts.posts}
</td>
<td class="text-right d-none d-lg-table-cell">
- {community.number_of_comments}
+ {cv.counts.comments}
</td>
<td class="text-right">
- {community.subscribed ? (
+ {cv.subscribed ? (
<span
class="pointer btn-link"
onClick={linkEvent(
- community.id,
+ cv.community.id,
this.handleUnsubscribe
)}
>
<span
class="pointer btn-link"
onClick={linkEvent(
- community.id,
+ cv.community.id,
this.handleSubscribe
)}
>
}
handleUnsubscribe(communityId: number) {
- let form: FollowCommunityForm = {
+ let form: FollowCommunity = {
community_id: communityId,
follow: false,
+ auth: authField(),
};
- WebSocketService.Instance.followCommunity(form);
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
}
handleSubscribe(communityId: number) {
- let form: FollowCommunityForm = {
+ let form: FollowCommunity = {
community_id: communityId,
follow: true,
+ auth: authField(),
};
- WebSocketService.Instance.followCommunity(form);
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
}
refetch() {
- let listCommunitiesForm: ListCommunitiesForm = {
+ let listCommunitiesForm: ListCommunities = {
sort: SortType.TopAll,
limit: communityLimit,
page: this.state.page,
+ auth: authField(false),
};
- WebSocketService.Instance.listCommunities(listCommunitiesForm);
+ WebSocketService.Instance.send(
+ wsClient.listCommunities(listCommunitiesForm)
+ );
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split('/');
let page = pathSplit[3] ? Number(pathSplit[3]) : 1;
- let listCommunitiesForm: ListCommunitiesForm = {
+ let listCommunitiesForm: ListCommunities = {
sort: SortType.TopAll,
limit: communityLimit,
page,
};
- setAuth(listCommunitiesForm, req.auth);
+ setOptionalAuth(listCommunitiesForm, req.auth);
return [req.client.listCommunities(listCommunitiesForm)];
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
- } else if (res.op == UserOperation.ListCommunities) {
- let data = res.data as ListCommunitiesResponse;
+ } else if (op == UserOperation.ListCommunities) {
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
this.state.communities = data.communities;
this.state.communities.sort(
- (a, b) => b.number_of_subscribers - a.number_of_subscribers
+ (a, b) => b.counts.subscribers - a.counts.subscribers
);
this.state.loading = false;
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (res.op == UserOperation.FollowCommunity) {
- let data = res.data as CommunityResponse;
- let found = this.state.communities.find(c => c.id == data.community.id);
- found.subscribed = data.community.subscribed;
- found.number_of_subscribers = data.community.number_of_subscribers;
+ } else if (op == UserOperation.FollowCommunity) {
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
+ let found = this.state.communities.find(
+ c => c.community.id == data.community_view.community.id
+ );
+ found.subscribed = data.community_view.subscribed;
+ found.counts.subscribers = data.community_view.counts.subscribers;
this.setState(this.state);
}
}
import { Prompt } from 'inferno-router';
import { Subscription } from 'rxjs';
import {
- CommunityForm as CommunityFormI,
+ EditCommunity,
+ CreateCommunity,
UserOperation,
Category,
CommunityResponse,
- WebSocketJsonResponse,
- Community,
+ CommunityView,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
import {
toast,
randomStr,
wsSubscribe,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import { i18n } from '../i18next';
import { ImageUploadForm } from './image-upload-form';
interface CommunityFormProps {
- community?: Community; // If a community is given, that means this is an edit
+ community_view?: CommunityView; // If a community is given, that means this is an edit
categories: Category[];
onCancel?(): any;
- onCreate?(community: Community): any;
- onEdit?(community: Community): any;
+ onCreate?(community: CommunityView): any;
+ onEdit?(community: CommunityView): any;
enableNsfw: boolean;
}
interface CommunityFormState {
- communityForm: CommunityFormI;
+ communityForm: CreateCommunity;
loading: boolean;
}
nsfw: false,
icon: null,
banner: null,
+ auth: authField(false),
},
loading: false,
};
this.handleBannerUpload = this.handleBannerUpload.bind(this);
this.handleBannerRemove = this.handleBannerRemove.bind(this);
- if (this.props.community) {
+ let cv = this.props.community_view;
+ if (cv) {
this.state.communityForm = {
- name: this.props.community.name,
- title: this.props.community.title,
- category_id: this.props.community.category_id,
- description: this.props.community.description,
- edit_id: this.props.community.id,
- nsfw: this.props.community.nsfw,
- icon: this.props.community.icon,
- banner: this.props.community.banner,
- auth: null,
+ name: cv.community.name,
+ title: cv.community.title,
+ category_id: cv.category.id,
+ description: cv.community.description,
+ nsfw: cv.community.nsfw,
+ icon: cv.community.icon,
+ banner: cv.community.banner,
+ auth: authField(),
};
}
this.subscription = wsSubscribe(this.parseMessage);
}
+ // TODO this should be checked out
componentDidUpdate() {
if (
!this.state.loading &&
message={i18n.t('block_leaving')}
/>
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
- {!this.props.community && (
+ {!this.props.community_view && (
<div class="form-group row">
<label class="col-12 col-form-label" htmlFor="community-name">
{i18n.t('name')}
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
- ) : this.props.community ? (
+ ) : this.props.community_view ? (
capitalizeFirstLetter(i18n.t('save'))
) : (
capitalizeFirstLetter(i18n.t('create'))
)}
</button>
- {this.props.community && (
+ {this.props.community_view && (
<button
type="button"
class="btn btn-secondary"
handleCreateCommunitySubmit(i: CommunityForm, event: any) {
event.preventDefault();
i.state.loading = true;
- if (i.props.community) {
- WebSocketService.Instance.editCommunity(i.state.communityForm);
+ if (i.props.community_view) {
+ let form: EditCommunity = {
+ ...i.state.communityForm,
+ edit_id: i.props.community_view.community.id,
+ };
+ WebSocketService.Instance.send(wsClient.editCommunity(form));
} else {
- WebSocketService.Instance.createCommunity(i.state.communityForm);
+ WebSocketService.Instance.send(
+ wsClient.createCommunity(i.state.communityForm)
+ );
}
i.setState(i.state);
}
this.setState(this.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
- console.log(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
- } else if (res.op == UserOperation.CreateCommunity) {
- let data = res.data as CommunityResponse;
+ } else if (op == UserOperation.CreateCommunity) {
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
this.state.loading = false;
- this.props.onCreate(data.community);
- } else if (res.op == UserOperation.EditCommunity) {
- let data = res.data as CommunityResponse;
+ this.props.onCreate(data.community_view);
+ } else if (op == UserOperation.EditCommunity) {
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
this.state.loading = false;
- this.props.onEdit(data.community);
+ this.props.onEdit(data.community_view);
}
}
}
import { Component } from 'inferno';
import { Link } from 'inferno-router';
-import { Community } from 'lemmy-js-client';
+import { CommunitySafe } from 'lemmy-js-client';
import { hostname, showAvatars } from '../utils';
import { PictrsImage } from './pictrs-image';
-interface CommunityOther {
- name: string;
- id?: number; // Necessary if its federated
- icon?: string;
- local?: boolean;
- actor_id?: string;
-}
-
interface CommunityLinkProps {
- community: Community | CommunityOther;
+ // TODO figure this out better
+ community: CommunitySafe;
realLink?: boolean;
useApubName?: boolean;
muted?: boolean;
GetCommunityResponse,
CommunityResponse,
SortType,
- Post,
- GetPostsForm,
- GetCommunityForm,
+ PostView,
+ GetPosts,
+ GetCommunity,
ListingType,
GetPostsResponse,
PostResponse,
AddModToCommunityResponse,
BanFromCommunityResponse,
- Comment,
- GetCommentsForm,
+ CommentView,
+ GetComments,
GetCommentsResponse,
CommentResponse,
- WebSocketJsonResponse,
GetSiteResponse,
Category,
ListCategoriesResponse,
setIsoData,
wsSubscribe,
isBrowser,
- setAuth,
communityRSSUrl,
+ wsUserOp,
+ wsClient,
+ authField,
+ setOptionalAuth,
} from '../utils';
import { i18n } from '../i18next';
communityLoading: boolean;
postsLoading: boolean;
commentsLoading: boolean;
- posts: Post[];
- comments: Comment[];
+ posts: PostView[];
+ comments: CommentView[];
dataType: DataType;
sort: SortType;
page: number;
dataType: getDataTypeFromProps(this.props),
sort: getSortTypeFromProps(this.props),
page: getPageFromProps(this.props),
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
categories: [],
};
} else {
this.fetchCommunity();
this.fetchData();
- WebSocketService.Instance.listCategories();
+ WebSocketService.Instance.send(wsClient.listCategories());
}
setupTippy();
}
fetchCommunity() {
- let form: GetCommunityForm = {
+ let form: GetCommunity = {
id: this.state.communityId ? this.state.communityId : null,
name: this.state.communityName ? this.state.communityName : null,
+ auth: authField(false),
};
- WebSocketService.Instance.getCommunity(form);
+ WebSocketService.Instance.send(wsClient.getCommunity(form));
}
componentWillUnmount() {
id = Number(idOrName);
}
- let communityForm: GetCommunityForm = id ? { id } : { name: name_ };
- setAuth(communityForm, req.auth);
+ let communityForm: GetCommunity = id ? { id } : { name: name_ };
+ setOptionalAuth(communityForm, req.auth);
promises.push(req.client.getCommunity(communityForm));
let dataType: DataType = pathSplit[4]
let page = pathSplit[8] ? Number(pathSplit[8]) : 1;
if (dataType == DataType.Post) {
- let getPostsForm: GetPostsForm = {
+ let getPostsForm: GetPosts = {
page,
limit: fetchLimit,
sort,
type_: ListingType.Community,
};
+ setOptionalAuth(getPostsForm, req.auth);
this.setIdOrName(getPostsForm, id, name_);
- setAuth(getPostsForm, req.auth);
promises.push(req.client.getPosts(getPostsForm));
} else {
- let getCommentsForm: GetCommentsForm = {
+ let getCommentsForm: GetComments = {
page,
limit: fetchLimit,
sort,
type_: ListingType.Community,
};
+ setOptionalAuth(getCommentsForm, req.auth);
this.setIdOrName(getCommentsForm, id, name_);
- setAuth(getCommentsForm, req.auth);
promises.push(req.client.getComments(getCommentsForm));
}
}
get documentTitle(): string {
- return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`;
+ return `${this.state.communityRes.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`;
}
render() {
+ let cv = this.state.communityRes?.community_view;
return (
<div class="container">
{this.state.communityLoading ? (
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={this.state.communityRes.community.description}
- image={this.state.communityRes.community.icon}
+ description={cv.community.description}
+ image={cv.community.icon}
/>
{this.communityInfo()}
{this.selects()}
</div>
<div class="col-12 col-md-4">
<Sidebar
- community={this.state.communityRes.community}
+ community_view={cv}
moderators={this.state.communityRes.moderators}
admins={this.state.siteRes.admins}
online={this.state.communityRes.online}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
categories={this.state.categories}
/>
</div>
}
listings() {
+ let site = this.state.siteRes.site_view.site;
return this.state.dataType == DataType.Post ? (
this.state.postsLoading ? (
<h5>
posts={this.state.posts}
removeDuplicates
sort={this.state.sort}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableDownvotes={site.enable_downvotes}
+ enableNsfw={site.enable_nsfw}
/>
)
) : this.state.commentsLoading ? (
noIndent
sortType={this.state.sort}
showContext
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
+ enableDownvotes={site.enable_downvotes}
/>
);
}
communityInfo() {
+ let community = this.state.communityRes.community_view.community;
return (
<div>
- <BannerIconHeader
- banner={this.state.communityRes.community.banner}
- icon={this.state.communityRes.community.icon}
- />
- <h5 class="mb-0">{this.state.communityRes.community.title}</h5>
+ <BannerIconHeader banner={community.banner} icon={community.icon} />
+ <h5 class="mb-0">{community.title}</h5>
<CommunityLink
- community={this.state.communityRes.community}
+ community={community}
realLink
useApubName
muted
</span>
<a
href={communityRSSUrl(
- this.state.communityRes.community.actor_id,
+ this.state.communityRes.community_view.community.actor_id,
this.state.sort
)}
target="_blank"
const sortStr = paramUpdates.sort || this.state.sort;
const page = paramUpdates.page || this.state.page;
this.props.history.push(
- `/c/${this.state.communityRes.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}`
+ `/c/${this.state.communityRes.community_view.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}`
);
}
fetchData() {
if (this.state.dataType == DataType.Post) {
- let getPostsForm: GetPostsForm = {
+ let form: GetPosts = {
page: this.state.page,
limit: fetchLimit,
sort: this.state.sort,
type_: ListingType.Community,
community_id: this.state.communityId,
community_name: this.state.communityName,
+ auth: authField(false),
};
- WebSocketService.Instance.getPosts(getPostsForm);
+ WebSocketService.Instance.send(wsClient.getPosts(form));
} else {
- let getCommentsForm: GetCommentsForm = {
+ let form: GetComments = {
page: this.state.page,
limit: fetchLimit,
sort: this.state.sort,
type_: ListingType.Community,
community_id: this.state.communityId,
community_name: this.state.communityName,
+ auth: authField(false),
};
- WebSocketService.Instance.getComments(getCommentsForm);
+ WebSocketService.Instance.send(wsClient.getComments(form));
}
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.context.router.history.push('/');
return;
} else if (msg.reconnect) {
- WebSocketService.Instance.communityJoin({
- community_id: this.state.communityRes.community.id,
- });
+ WebSocketService.Instance.send(
+ wsClient.communityJoin({
+ community_id: this.state.communityRes.community_view.community.id,
+ })
+ );
this.fetchData();
- } else if (res.op == UserOperation.GetCommunity) {
- let data = res.data as GetCommunityResponse;
+ } else if (op == UserOperation.GetCommunity) {
+ let data = wsJsonToRes<GetCommunityResponse>(msg).data;
this.state.communityRes = data;
this.state.communityLoading = false;
this.setState(this.state);
- WebSocketService.Instance.communityJoin({
- community_id: data.community.id,
- });
+ // TODO why is there no auth in this form?
+ WebSocketService.Instance.send(
+ wsClient.communityJoin({
+ community_id: data.community_view.community.id,
+ })
+ );
} else if (
- res.op == UserOperation.EditCommunity ||
- res.op == UserOperation.DeleteCommunity ||
- res.op == UserOperation.RemoveCommunity
+ op == UserOperation.EditCommunity ||
+ op == UserOperation.DeleteCommunity ||
+ op == UserOperation.RemoveCommunity
) {
- let data = res.data as CommunityResponse;
- this.state.communityRes.community = data.community;
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
+ this.state.communityRes.community_view = data.community_view;
this.setState(this.state);
- } else if (res.op == UserOperation.FollowCommunity) {
- let data = res.data as CommunityResponse;
- this.state.communityRes.community.subscribed = data.community.subscribed;
- this.state.communityRes.community.number_of_subscribers =
- data.community.number_of_subscribers;
+ } else if (op == UserOperation.FollowCommunity) {
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
+ this.state.communityRes.community_view.subscribed =
+ data.community_view.subscribed;
+ this.state.communityRes.community_view.counts.subscribers =
+ data.community_view.counts.subscribers;
this.setState(this.state);
- } else if (res.op == UserOperation.GetPosts) {
- let data = res.data as GetPostsResponse;
+ } else if (op == UserOperation.GetPosts) {
+ let data = wsJsonToRes<GetPostsResponse>(msg).data;
this.state.posts = data.posts;
this.state.postsLoading = false;
this.setState(this.state);
setupTippy();
} else if (
- res.op == UserOperation.EditPost ||
- res.op == UserOperation.DeletePost ||
- res.op == UserOperation.RemovePost ||
- res.op == UserOperation.LockPost ||
- res.op == UserOperation.StickyPost ||
- res.op == UserOperation.SavePost
+ op == UserOperation.EditPost ||
+ op == UserOperation.DeletePost ||
+ op == UserOperation.RemovePost ||
+ op == UserOperation.LockPost ||
+ op == UserOperation.StickyPost ||
+ op == UserOperation.SavePost
) {
- let data = res.data as PostResponse;
- editPostFindRes(data, this.state.posts);
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ editPostFindRes(data.post_view, this.state.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePost) {
- let data = res.data as PostResponse;
- this.state.posts.unshift(data.post);
- notifyPost(data.post, this.context.router);
+ } else if (op == UserOperation.CreatePost) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ this.state.posts.unshift(data.post_view);
+ notifyPost(data.post_view, this.context.router);
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePostLike) {
- let data = res.data as PostResponse;
- createPostLikeFindRes(data, this.state.posts);
+ } else if (op == UserOperation.CreatePostLike) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ createPostLikeFindRes(data.post_view, this.state.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.AddModToCommunity) {
- let data = res.data as AddModToCommunityResponse;
+ } else if (op == UserOperation.AddModToCommunity) {
+ let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
this.state.communityRes.moderators = data.moderators;
this.setState(this.state);
- } else if (res.op == UserOperation.BanFromCommunity) {
- let data = res.data as BanFromCommunityResponse;
+ } else if (op == UserOperation.BanFromCommunity) {
+ let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
+ // TODO this might be incorrect
this.state.posts
- .filter(p => p.creator_id == data.user.id)
- .forEach(p => (p.banned = data.banned));
+ .filter(p => p.creator.id == data.user_view.user.id)
+ .forEach(p => (p.creator_banned_from_community = data.banned));
this.setState(this.state);
- } else if (res.op == UserOperation.GetComments) {
- let data = res.data as GetCommentsResponse;
+ } else if (op == UserOperation.GetComments) {
+ let data = wsJsonToRes<GetCommentsResponse>(msg).data;
this.state.comments = data.comments;
this.state.commentsLoading = false;
this.setState(this.state);
} else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
+ op == UserOperation.EditComment ||
+ op == UserOperation.DeleteComment ||
+ op == UserOperation.RemoveComment
) {
- let data = res.data as CommentResponse;
- editCommentRes(data, this.state.comments);
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ editCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateComment) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
// Necessary since it might be a user reply
if (data.recipient_ids.length == 0) {
- this.state.comments.unshift(data.comment);
+ this.state.comments.unshift(data.comment_view);
this.setState(this.state);
}
- } else if (res.op == UserOperation.SaveComment) {
- let data = res.data as CommentResponse;
- saveCommentRes(data, this.state.comments);
+ } else if (op == UserOperation.SaveComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ saveCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateCommentLike) {
- let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.comments);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(data.comment_view, this.state.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.ListCategories) {
- let data = res.data as ListCategoriesResponse;
+ } else if (op == UserOperation.ListCategories) {
+ let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
this.state.categories = data.categories;
this.setState(this.state);
}
import { CommunityForm } from './community-form';
import { HtmlTags } from './html-tags';
import {
- Community,
+ CommunityView,
UserOperation,
- WebSocketJsonResponse,
- Site,
+ SiteView,
ListCategoriesResponse,
Category,
} from 'lemmy-js-client';
wsJsonToRes,
wsSubscribe,
isBrowser,
+ wsUserOp,
+ wsClient,
} from '../utils';
import { WebSocketService, UserService } from '../services';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
interface CreateCommunityState {
- site: Site;
+ site_view: SiteView;
categories: Category[];
loading: boolean;
}
private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: CreateCommunityState = {
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
categories: [],
loading: true,
};
this.state.categories = this.isoData.routeData[0].categories;
this.state.loading = false;
} else {
- WebSocketService.Instance.listCategories();
+ WebSocketService.Instance.send(wsClient.listCategories());
}
}
}
get documentTitle(): string {
- return `${i18n.t('create_community')} - ${this.state.site.name}`;
+ return `${i18n.t('create_community')} - ${this.state.site_view.site.name}`;
}
render() {
<CommunityForm
categories={this.state.categories}
onCreate={this.handleCommunityCreate}
- enableNsfw={this.state.site.enable_nsfw}
+ enableNsfw={this.state.site_view.site.enable_nsfw}
/>
</div>
</div>
);
}
- handleCommunityCreate(community: Community) {
- this.props.history.push(`/c/${community.name}`);
+ handleCommunityCreate(cv: CommunityView) {
+ this.props.history.push(`/c/${cv.community.name}`);
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
return [req.client.listCategories()];
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
// Toast errors are already handled by community-form
return;
- } else if (res.op == UserOperation.ListCategories) {
- let data = res.data as ListCategoriesResponse;
+ } else if (op == UserOperation.ListCategories) {
+ let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
this.state.categories = data.categories;
this.state.loading = false;
this.setState(this.state);
import { PostForm } from './post-form';
import { HtmlTags } from './html-tags';
import {
+ authField,
isBrowser,
- setAuth,
setIsoData,
+ setOptionalAuth,
toast,
+ wsClient,
wsJsonToRes,
wsSubscribe,
+ wsUserOp,
} from '../utils';
import { UserService, WebSocketService } from '../services';
import {
UserOperation,
- PostFormParams,
- WebSocketJsonResponse,
ListCommunitiesResponse,
- Community,
- Site,
- ListCommunitiesForm,
+ CommunityView,
+ SiteView,
+ ListCommunities,
SortType,
+ PostView,
} from 'lemmy-js-client';
import { i18n } from '../i18next';
-import { InitialFetchRequest } from 'shared/interfaces';
+import { InitialFetchRequest, PostFormParams } from 'shared/interfaces';
interface CreatePostState {
- site: Site;
- communities: Community[];
+ site_view: SiteView;
+ communities: CommunityView[];
loading: boolean;
}
private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: CreatePostState = {
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
communities: [],
loading: true,
};
}
refetch() {
- let listCommunitiesForm: ListCommunitiesForm = {
+ let listCommunitiesForm: ListCommunities = {
sort: SortType.TopAll,
limit: 9999,
+ auth: authField(false),
};
- WebSocketService.Instance.listCommunities(listCommunitiesForm);
+ WebSocketService.Instance.send(
+ wsClient.listCommunities(listCommunitiesForm)
+ );
}
componentWillUnmount() {
}
get documentTitle(): string {
- return `${i18n.t('create_post')} - ${this.state.site.name}`;
+ return `${i18n.t('create_post')} - ${this.state.site_view.site.name}`;
}
render() {
communities={this.state.communities}
onCreate={this.handlePostCreate}
params={this.params}
- enableDownvotes={this.state.site.enable_downvotes}
- enableNsfw={this.state.site.enable_nsfw}
+ enableDownvotes={this.state.site_view.site.enable_downvotes}
+ enableNsfw={this.state.site_view.site.enable_nsfw}
/>
</div>
</div>
return null;
}
- handlePostCreate(id: number) {
- this.props.history.push(`/post/${id}`);
+ handlePostCreate(post_view: PostView) {
+ this.props.history.push(`/post/${post_view.post.id}`);
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
- let listCommunitiesForm: ListCommunitiesForm = {
+ let listCommunitiesForm: ListCommunities = {
sort: SortType.TopAll,
limit: 9999,
};
- setAuth(listCommunitiesForm, req.auth);
+ setOptionalAuth(listCommunitiesForm, req.auth);
return [req.client.listCommunities(listCommunitiesForm)];
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
- } else if (res.op == UserOperation.ListCommunities) {
- let data = res.data as ListCommunitiesResponse;
+ } else if (op == UserOperation.ListCommunities) {
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
this.state.communities = data.communities;
this.state.loading = false;
this.setState(this.state);
import { HtmlTags } from './html-tags';
import { UserService, WebSocketService } from '../services';
import {
- Site,
- WebSocketJsonResponse,
+ SiteView,
UserOperation,
- UserDetailsResponse,
- UserView,
+ GetUserDetailsResponse,
+ UserViewSafe,
SortType,
- GetUserDetailsForm,
+ GetUserDetails,
} from 'lemmy-js-client';
import {
+ authField,
getRecipientIdFromProps,
isBrowser,
- setAuth,
setIsoData,
toast,
+ wsClient,
wsJsonToRes,
wsSubscribe,
+ wsUserOp,
} from '../utils';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
interface CreatePrivateMessageProps {}
interface CreatePrivateMessageState {
- site: Site;
- recipient: UserView;
+ site_view: SiteView;
+ recipient: UserViewSafe;
recipient_id: number;
loading: boolean;
}
private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: CreatePrivateMessageState = {
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
recipient: undefined,
recipient_id: getRecipientIdFromProps(this.props),
loading: true,
}
fetchUserDetails() {
- let form: GetUserDetailsForm = {
+ let form: GetUserDetails = {
user_id: this.state.recipient_id,
sort: SortType.New,
saved_only: false,
+ auth: authField(false),
};
- WebSocketService.Instance.getUserDetails(form);
+ WebSocketService.Instance.send(wsClient.getUserDetails(form));
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let user_id = Number(req.path.split('/').pop());
- let form: GetUserDetailsForm = {
+ let form: GetUserDetails = {
user_id,
sort: SortType.New,
saved_only: false,
+ auth: req.auth,
};
- setAuth(form, req.auth);
return [req.client.getUserDetails(form)];
}
get documentTitle(): string {
- return `${i18n.t('create_private_message')} - ${this.state.site.name}`;
+ return `${i18n.t('create_private_message')} - ${
+ this.state.site_view.site.name
+ }`;
}
componentWillUnmount() {
<h5>{i18n.t('create_private_message')}</h5>
<PrivateMessageForm
onCreate={this.handlePrivateMessageCreate}
- recipient={this.state.recipient}
+ recipient={this.state.recipient.user}
/>
</div>
</div>
this.context.router.history.push(`/`);
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
- } else if (res.op == UserOperation.GetUserDetails) {
- let data = res.data as UserDetailsResponse;
- this.state.recipient = data.user;
+ } else if (op == UserOperation.GetUserDetails) {
+ let data = wsJsonToRes<GetUserDetailsResponse>(msg).data;
+ this.state.recipient = data.user_view;
this.state.loading = false;
this.setState(this.state);
}
import { Subscription } from 'rxjs';
import {
UserOperation,
- Comment,
+ CommentView,
SortType,
- GetRepliesForm,
+ GetReplies,
GetRepliesResponse,
- GetUserMentionsForm,
+ GetUserMentions,
GetUserMentionsResponse,
UserMentionResponse,
CommentResponse,
- WebSocketJsonResponse,
- PrivateMessage as PrivateMessageI,
- GetPrivateMessagesForm,
+ PrivateMessageView,
+ GetPrivateMessages,
PrivateMessagesResponse,
PrivateMessageResponse,
- Site,
+ SiteView,
+ UserMentionView,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
import {
wsJsonToRes,
fetchLimit,
- isCommentType,
toast,
editCommentRes,
saveCommentRes,
setupTippy,
setIsoData,
wsSubscribe,
- setAuth,
isBrowser,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import { CommentNodes } from './comment-nodes';
import { PrivateMessage } from './private-message';
Messages,
}
-type ReplyType = Comment | PrivateMessageI;
+enum ReplyEnum {
+ Reply,
+ Mention,
+ Message,
+}
+type ReplyType = {
+ id: number;
+ type_: ReplyEnum;
+ view: CommentView | PrivateMessageView | UserMentionView;
+ published: string;
+};
interface InboxState {
unreadOrAll: UnreadOrAll;
messageType: MessageType;
- replies: Comment[];
- mentions: Comment[];
- messages: PrivateMessageI[];
+ replies: CommentView[];
+ mentions: UserMentionView[];
+ messages: PrivateMessageView[];
sort: SortType;
page: number;
- site: Site;
+ site_view: SiteView;
loading: boolean;
}
messages: [],
sort: SortType.New,
page: 1,
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
loading: true,
};
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
- this.state.replies = this.isoData.routeData[0].replies;
- this.state.mentions = this.isoData.routeData[1].mentions;
- this.state.messages = this.isoData.routeData[2].messages;
- this.sendUnreadCount();
+ this.state.replies = this.isoData.routeData[0].replies || [];
+ this.state.mentions = this.isoData.routeData[1].mentions || [];
+ this.state.messages = this.isoData.routeData[2].messages || [];
this.state.loading = false;
} else {
this.refetch();
get documentTitle(): string {
return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
- this.state.site.name
+ this.state.site_view.site.name
}`;
}
}
combined(): ReplyType[] {
- return [
- ...this.state.replies,
- ...this.state.mentions,
- ...this.state.messages,
- ].sort((a, b) => b.published.localeCompare(a.published));
+ let id = 0;
+ let replies: ReplyType[] = this.state.replies.map(r => ({
+ id: id++,
+ type_: ReplyEnum.Reply,
+ view: r,
+ published: r.comment.published,
+ }));
+ let mentions: ReplyType[] = this.state.mentions.map(r => ({
+ id: id++,
+ type_: ReplyEnum.Mention,
+ view: r,
+ published: r.comment.published,
+ }));
+ let messages: ReplyType[] = this.state.messages.map(r => ({
+ id: id++,
+ type_: ReplyEnum.Message,
+ view: r,
+ published: r.private_message.published,
+ }));
+
+ return [...replies, ...mentions, ...messages].sort((a, b) =>
+ b.published.localeCompare(a.published)
+ );
+ }
+
+ renderReplyType(i: ReplyType) {
+ switch (i.type_) {
+ case ReplyEnum.Reply:
+ return (
+ <CommentNodes
+ key={i.id}
+ nodes={[{ comment_view: i.view as CommentView }]}
+ noIndent
+ markable
+ showCommunity
+ showContext
+ enableDownvotes={this.state.site_view.site.enable_downvotes}
+ />
+ );
+ case ReplyEnum.Mention:
+ return (
+ <CommentNodes
+ key={i.id}
+ nodes={[{ comment_view: i.view as UserMentionView }]}
+ noIndent
+ markable
+ showCommunity
+ showContext
+ enableDownvotes={this.state.site_view.site.enable_downvotes}
+ />
+ );
+ case ReplyEnum.Message:
+ return (
+ <PrivateMessage
+ key={i.id}
+ private_message_view={i.view as PrivateMessageView}
+ />
+ );
+ default:
+ return <div />;
+ }
}
all() {
- return (
- <div>
- {this.combined().map(i =>
- isCommentType(i) ? (
- <CommentNodes
- key={i.id}
- nodes={[{ comment: i }]}
- noIndent
- markable
- showCommunity
- showContext
- enableDownvotes={this.state.site.enable_downvotes}
- />
- ) : (
- <PrivateMessage key={i.id} privateMessage={i} />
- )
- )}
- </div>
- );
+ return <div>{this.combined().map(i => this.renderReplyType(i))}</div>;
}
replies() {
markable
showCommunity
showContext
- enableDownvotes={this.state.site.enable_downvotes}
+ enableDownvotes={this.state.site_view.site.enable_downvotes}
/>
</div>
);
mentions() {
return (
<div>
- {this.state.mentions.map(mention => (
+ {this.state.mentions.map(umv => (
<CommentNodes
- key={mention.id}
- nodes={[{ comment: mention }]}
+ key={umv.user_mention.id}
+ nodes={[{ comment_view: umv }]}
noIndent
markable
showCommunity
showContext
- enableDownvotes={this.state.site.enable_downvotes}
+ enableDownvotes={this.state.site_view.site.enable_downvotes}
/>
))}
</div>
messages() {
return (
<div>
- {this.state.messages.map(message => (
- <PrivateMessage key={message.id} privateMessage={message} />
+ {this.state.messages.map(pmv => (
+ <PrivateMessage
+ key={pmv.private_message.id}
+ private_message_view={pmv}
+ />
))}
</div>
);
let promises: Promise<any>[] = [];
// It can be /u/me, or /username/1
- let repliesForm: GetRepliesForm = {
+ let repliesForm: GetReplies = {
sort: SortType.New,
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: req.auth,
};
- setAuth(repliesForm, req.auth);
promises.push(req.client.getReplies(repliesForm));
- let userMentionsForm: GetUserMentionsForm = {
+ let userMentionsForm: GetUserMentions = {
sort: SortType.New,
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: req.auth,
};
- setAuth(userMentionsForm, req.auth);
promises.push(req.client.getUserMentions(userMentionsForm));
- let privateMessagesForm: GetPrivateMessagesForm = {
+ let privateMessagesForm: GetPrivateMessages = {
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: req.auth,
};
- setAuth(privateMessagesForm, req.auth);
promises.push(req.client.getPrivateMessages(privateMessagesForm));
return promises;
}
refetch() {
- let repliesForm: GetRepliesForm = {
+ let repliesForm: GetReplies = {
sort: this.state.sort,
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
page: this.state.page,
limit: fetchLimit,
+ auth: authField(),
};
- WebSocketService.Instance.getReplies(repliesForm);
+ WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
- let userMentionsForm: GetUserMentionsForm = {
+ let userMentionsForm: GetUserMentions = {
sort: this.state.sort,
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
page: this.state.page,
limit: fetchLimit,
+ auth: authField(),
};
- WebSocketService.Instance.getUserMentions(userMentionsForm);
+ WebSocketService.Instance.send(wsClient.getUserMentions(userMentionsForm));
- let privateMessagesForm: GetPrivateMessagesForm = {
+ let privateMessagesForm: GetPrivateMessages = {
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
page: this.state.page,
limit: fetchLimit,
+ auth: authField(),
};
- WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
+ WebSocketService.Instance.send(
+ wsClient.getPrivateMessages(privateMessagesForm)
+ );
}
handleSortChange(val: SortType) {
}
markAllAsRead(i: Inbox) {
- WebSocketService.Instance.markAllAsRead();
+ WebSocketService.Instance.send(
+ wsClient.markAllAsRead({
+ auth: authField(),
+ })
+ );
i.state.replies = [];
i.state.mentions = [];
i.state.messages = [];
i.setState(i.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
} else if (msg.reconnect) {
this.refetch();
- } else if (res.op == UserOperation.GetReplies) {
- let data = res.data as GetRepliesResponse;
+ } else if (op == UserOperation.GetReplies) {
+ let data = wsJsonToRes<GetRepliesResponse>(msg).data;
this.state.replies = data.replies;
this.state.loading = false;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.GetUserMentions) {
- let data = res.data as GetUserMentionsResponse;
+ } else if (op == UserOperation.GetUserMentions) {
+ let data = wsJsonToRes<GetUserMentionsResponse>(msg).data;
this.state.mentions = data.mentions;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.GetPrivateMessages) {
- let data = res.data as PrivateMessagesResponse;
- this.state.messages = data.messages;
+ } else if (op == UserOperation.GetPrivateMessages) {
+ let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
+ this.state.messages = data.private_messages;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.EditPrivateMessage) {
- let data = res.data as PrivateMessageResponse;
- let found: PrivateMessageI = this.state.messages.find(
- m => m.id === data.message.id
+ } else if (op == UserOperation.EditPrivateMessage) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+ let found: PrivateMessageView = this.state.messages.find(
+ m =>
+ m.private_message.id === data.private_message_view.private_message.id
);
if (found) {
- found.content = data.message.content;
- found.updated = data.message.updated;
+ found.private_message.content =
+ data.private_message_view.private_message.content;
+ found.private_message.updated =
+ data.private_message_view.private_message.updated;
}
this.setState(this.state);
- } else if (res.op == UserOperation.DeletePrivateMessage) {
- let data = res.data as PrivateMessageResponse;
- let found: PrivateMessageI = this.state.messages.find(
- m => m.id === data.message.id
+ } else if (op == UserOperation.DeletePrivateMessage) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+ let found: PrivateMessageView = this.state.messages.find(
+ m =>
+ m.private_message.id === data.private_message_view.private_message.id
);
if (found) {
- found.deleted = data.message.deleted;
- found.updated = data.message.updated;
+ found.private_message.deleted =
+ data.private_message_view.private_message.deleted;
+ found.private_message.updated =
+ data.private_message_view.private_message.updated;
}
this.setState(this.state);
- } else if (res.op == UserOperation.MarkPrivateMessageAsRead) {
- let data = res.data as PrivateMessageResponse;
- let found: PrivateMessageI = this.state.messages.find(
- m => m.id === data.message.id
+ } else if (op == UserOperation.MarkPrivateMessageAsRead) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+ let found: PrivateMessageView = this.state.messages.find(
+ m =>
+ m.private_message.id === data.private_message_view.private_message.id
);
if (found) {
- found.updated = data.message.updated;
+ found.private_message.updated =
+ data.private_message_view.private_message.updated;
// If youre in the unread view, just remove it from the list
- if (this.state.unreadOrAll == UnreadOrAll.Unread && data.message.read) {
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.private_message_view.private_message.read
+ ) {
this.state.messages = this.state.messages.filter(
- r => r.id !== data.message.id
+ r =>
+ r.private_message.id !==
+ data.private_message_view.private_message.id
);
} else {
- let found = this.state.messages.find(c => c.id == data.message.id);
- found.read = data.message.read;
+ let found = this.state.messages.find(
+ c =>
+ c.private_message.id ==
+ data.private_message_view.private_message.id
+ );
+ found.private_message.read =
+ data.private_message_view.private_message.read;
}
}
this.sendUnreadCount();
this.setState(this.state);
- } else if (res.op == UserOperation.MarkAllAsRead) {
+ } else if (op == UserOperation.MarkAllAsRead) {
// Moved to be instant
} else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
+ op == UserOperation.EditComment ||
+ op == UserOperation.DeleteComment ||
+ op == UserOperation.RemoveComment
) {
- let data = res.data as CommentResponse;
- editCommentRes(data, this.state.replies);
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ editCommentRes(data.comment_view, this.state.replies);
this.setState(this.state);
- } else if (res.op == UserOperation.MarkCommentAsRead) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.MarkCommentAsRead) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
// If youre in the unread view, just remove it from the list
- if (this.state.unreadOrAll == UnreadOrAll.Unread && data.comment.read) {
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.comment_view.comment.read
+ ) {
this.state.replies = this.state.replies.filter(
- r => r.id !== data.comment.id
+ r => r.comment.id !== data.comment_view.comment.id
);
} else {
- let found = this.state.replies.find(c => c.id == data.comment.id);
- found.read = data.comment.read;
+ let found = this.state.replies.find(
+ c => c.comment.id == data.comment_view.comment.id
+ );
+ found.comment.read = data.comment_view.comment.read;
}
this.sendUnreadCount();
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.MarkUserMentionAsRead) {
- let data = res.data as UserMentionResponse;
-
- let found = this.state.mentions.find(c => c.id == data.mention.id);
- found.content = data.mention.content;
- found.updated = data.mention.updated;
- found.removed = data.mention.removed;
- found.deleted = data.mention.deleted;
- found.upvotes = data.mention.upvotes;
- found.downvotes = data.mention.downvotes;
- found.score = data.mention.score;
+ } else if (op == UserOperation.MarkUserMentionAsRead) {
+ let data = wsJsonToRes<UserMentionResponse>(msg).data;
+
+ // TODO this might not be correct, it might need to use the comment id
+ let found = this.state.mentions.find(
+ c => c.user_mention.id == data.user_mention_view.user_mention.id
+ );
+ found.comment.content = data.user_mention_view.comment.content;
+ found.comment.updated = data.user_mention_view.comment.updated;
+ found.comment.removed = data.user_mention_view.comment.removed;
+ found.comment.deleted = data.user_mention_view.comment.deleted;
+ found.counts.upvotes = data.user_mention_view.counts.upvotes;
+ found.counts.downvotes = data.user_mention_view.counts.downvotes;
+ found.counts.score = data.user_mention_view.counts.score;
// If youre in the unread view, just remove it from the list
- if (this.state.unreadOrAll == UnreadOrAll.Unread && data.mention.read) {
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.user_mention_view.user_mention.read
+ ) {
this.state.mentions = this.state.mentions.filter(
- r => r.id !== data.mention.id
+ r => r.user_mention.id !== data.user_mention_view.user_mention.id
);
} else {
- let found = this.state.mentions.find(c => c.id == data.mention.id);
- found.read = data.mention.read;
+ let found = this.state.mentions.find(
+ c => c.user_mention.id == data.user_mention_view.user_mention.id
+ );
+ // TODO test to make sure these mentions are getting marked as read
+ found.user_mention.read = data.user_mention_view.user_mention.read;
}
this.sendUnreadCount();
this.setState(this.state);
- } else if (res.op == UserOperation.CreateComment) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
if (data.recipient_ids.includes(UserService.Instance.user.id)) {
- this.state.replies.unshift(data.comment);
+ this.state.replies.unshift(data.comment_view);
this.setState(this.state);
- } else if (data.comment.creator_id == UserService.Instance.user.id) {
+ } else if (data.comment_view.creator.id == UserService.Instance.user.id) {
+ // TODO this seems wrong, you should be using form_id
toast(i18n.t('reply_sent'));
}
- } else if (res.op == UserOperation.CreatePrivateMessage) {
- let data = res.data as PrivateMessageResponse;
- if (data.message.recipient_id == UserService.Instance.user.id) {
- this.state.messages.unshift(data.message);
+ } else if (op == UserOperation.CreatePrivateMessage) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+ if (
+ data.private_message_view.recipient.id == UserService.Instance.user.id
+ ) {
+ this.state.messages.unshift(data.private_message_view);
this.setState(this.state);
}
- } else if (res.op == UserOperation.SaveComment) {
- let data = res.data as CommentResponse;
- saveCommentRes(data, this.state.replies);
+ } else if (op == UserOperation.SaveComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ saveCommentRes(data.comment_view, this.state.replies);
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.CreateCommentLike) {
- let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.replies);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(data.comment_view, this.state.replies);
this.setState(this.state);
}
}
unreadCount(): number {
return (
- this.state.replies.filter(r => !r.read).length +
- this.state.mentions.filter(r => !r.read).length +
+ this.state.replies.filter(r => !r.comment.read).length +
+ this.state.mentions.filter(r => !r.user_mention.read).length +
this.state.messages.filter(
r =>
UserService.Instance.user &&
- !r.read &&
- r.creator_id !== UserService.Instance.user.id
+ !r.private_message.read &&
+ // TODO also seems very strang and wrong
+ r.creator.id !== UserService.Instance.user.id
).length
);
}
export class Instances extends Component<any, InstancesState> {
private isoData = setIsoData(this.context);
private emptyState: InstancesState = {
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
}
get documentTitle(): string {
- return `${i18n.t('instances')} - ${this.state.siteRes.site.name}`;
+ return `${i18n.t('instances')} - ${this.state.siteRes.site_view.site.name}`;
}
render() {
import { Component, linkEvent } from 'inferno';
import { Subscription } from 'rxjs';
import {
- LoginForm,
- RegisterForm,
+ Login as LoginForm,
+ Register,
LoginResponse,
UserOperation,
- PasswordResetForm,
+ PasswordReset,
GetSiteResponse,
GetCaptchaResponse,
- WebSocketJsonResponse,
- Site,
+ SiteView,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
import {
wsSubscribe,
isBrowser,
setIsoData,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
interface State {
loginForm: LoginForm;
- registerForm: RegisterForm;
+ registerForm: Register;
loginLoading: boolean;
registerLoading: boolean;
captcha: GetCaptchaResponse;
captchaPlaying: boolean;
- site: Site;
+ site_view: SiteView;
}
export class Login extends Component<any, State> {
registerLoading: false,
captcha: undefined,
captchaPlaying: false,
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
};
constructor(props: any, context: any) {
this.subscription = wsSubscribe(this.parseMessage);
if (isBrowser()) {
- WebSocketService.Instance.getCaptcha();
+ WebSocketService.Instance.send(wsClient.getCaptcha());
}
}
}
get documentTitle(): string {
- return `${i18n.t('login')} - ${this.state.site.name}`;
+ return `${i18n.t('login')} - ${this.state.site_view.site.name}`;
}
render() {
</div>
</div>
)}
- {this.state.site.enable_nsfw && (
+ {this.state.site_view.site.enable_nsfw && (
<div class="form-group row">
<div class="col-sm-10">
<div class="form-check">
event.preventDefault();
i.state.loginLoading = true;
i.setState(i.state);
- WebSocketService.Instance.login(i.state.loginForm);
+ WebSocketService.Instance.send(wsClient.login(i.state.loginForm));
}
handleLoginUsernameChange(i: Login, event: any) {
event.preventDefault();
i.state.registerLoading = true;
i.setState(i.state);
- WebSocketService.Instance.register(i.state.registerForm);
+ WebSocketService.Instance.send(wsClient.register(i.state.registerForm));
}
handleRegisterUsernameChange(i: Login, event: any) {
handleRegenCaptcha(_i: Login, event: any) {
event.preventDefault();
- WebSocketService.Instance.getCaptcha();
+ WebSocketService.Instance.send(wsClient.getCaptcha());
}
handlePasswordReset(i: Login, event: any) {
event.preventDefault();
- let resetForm: PasswordResetForm = {
+ let resetForm: PasswordReset = {
email: i.state.loginForm.username_or_email,
};
- WebSocketService.Instance.passwordReset(resetForm);
+ WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
}
handleCaptchaPlay(i: Login, event: any) {
return `data:image/png;base64,${this.state.captcha.ok.png}`;
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state = this.emptyState;
this.state.registerForm.captcha_answer = undefined;
// Refetch another captcha
- WebSocketService.Instance.getCaptcha();
+ WebSocketService.Instance.send(wsClient.getCaptcha());
this.setState(this.state);
return;
} else {
- if (res.op == UserOperation.Login) {
- let data = res.data as LoginResponse;
+ if (op == UserOperation.Login) {
+ let data = wsJsonToRes<LoginResponse>(msg).data;
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
- WebSocketService.Instance.userJoin();
+ WebSocketService.Instance.send(
+ wsClient.userJoin({
+ auth: authField(),
+ })
+ );
toast(i18n.t('logged_in'));
this.props.history.push('/');
- } else if (res.op == UserOperation.Register) {
- let data = res.data as LoginResponse;
+ } else if (op == UserOperation.Register) {
+ let data = wsJsonToRes<LoginResponse>(msg).data;
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
- WebSocketService.Instance.userJoin();
+ WebSocketService.Instance.send(
+ wsClient.userJoin({
+ auth: authField(),
+ })
+ );
this.props.history.push('/communities');
- } else if (res.op == UserOperation.GetCaptcha) {
- let data = res.data as GetCaptchaResponse;
+ } else if (op == UserOperation.GetCaptcha) {
+ let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
if (data.ok) {
this.state.captcha = data;
this.state.registerForm.captcha_uuid = data.ok.uuid;
this.setState(this.state);
}
- } else if (res.op == UserOperation.PasswordReset) {
+ } else if (op == UserOperation.PasswordReset) {
toast(i18n.t('reset_password_mail_sent'));
- } else if (res.op == UserOperation.GetSite) {
- let data = res.data as GetSiteResponse;
- this.state.site = data.site;
+ } else if (op == UserOperation.GetSite) {
+ let data = wsJsonToRes<GetSiteResponse>(msg).data;
+ this.state.site_view = data.site_view;
this.setState(this.state);
}
}
import { Subscription } from 'rxjs';
import {
UserOperation,
- CommunityUser,
+ CommunityFollowerView,
GetFollowedCommunitiesResponse,
- ListCommunitiesForm,
+ ListCommunities,
ListCommunitiesResponse,
- Community,
+ CommunityView,
SortType,
GetSiteResponse,
ListingType,
SiteResponse,
GetPostsResponse,
PostResponse,
- Post,
- GetPostsForm,
- Comment,
- GetCommentsForm,
+ PostView,
+ GetPosts,
+ CommentView,
+ GetComments,
GetCommentsResponse,
CommentResponse,
AddAdminResponse,
BanUserResponse,
- WebSocketJsonResponse,
} from 'lemmy-js-client';
import { DataType, InitialFetchRequest } from '../interfaces';
import { WebSocketService, UserService } from '../services';
setIsoData,
wsSubscribe,
isBrowser,
- setAuth,
+ wsUserOp,
+ setOptionalAuth,
+ wsClient,
+ authField,
} from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
import { HtmlTags } from './html-tags';
interface MainState {
- subscribedCommunities: CommunityUser[];
- trendingCommunities: Community[];
+ subscribedCommunities: CommunityFollowerView[];
+ trendingCommunities: CommunityView[];
siteRes: GetSiteResponse;
showEditSite: boolean;
loading: boolean;
- posts: Post[];
- comments: Comment[];
+ posts: PostView[];
+ comments: CommentView[];
listingType: ListingType;
dataType: DataType;
sort: SortType;
private emptyState: MainState = {
subscribedCommunities: [],
trendingCommunities: [],
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
showEditSite: false,
loading: true,
posts: [],
this.fetchTrendingCommunities();
this.fetchData();
if (UserService.Instance.user) {
- WebSocketService.Instance.getFollowedCommunities();
+ WebSocketService.Instance.send(
+ wsClient.getFollowedCommunities({
+ auth: authField(),
+ })
+ );
}
}
}
fetchTrendingCommunities() {
- let listCommunitiesForm: ListCommunitiesForm = {
+ let listCommunitiesForm: ListCommunities = {
sort: SortType.Hot,
limit: 6,
+ auth: authField(false),
};
- WebSocketService.Instance.listCommunities(listCommunitiesForm);
+ WebSocketService.Instance.send(
+ wsClient.listCommunities(listCommunitiesForm)
+ );
}
componentDidMount() {
// This means it hasn't been set up yet
- if (!this.state.siteRes.site) {
+ if (!this.state.siteRes.site_view) {
this.context.router.history.push('/setup');
}
- WebSocketService.Instance.communityJoin({ community_id: 0 });
+ WebSocketService.Instance.send(wsClient.communityJoin({ community_id: 0 }));
}
componentWillUnmount() {
let promises: Promise<any>[] = [];
if (dataType == DataType.Post) {
- let getPostsForm: GetPostsForm = {
+ let getPostsForm: GetPosts = {
page,
limit: fetchLimit,
sort,
type_,
};
- setAuth(getPostsForm, req.auth);
+ setOptionalAuth(getPostsForm, req.auth);
promises.push(req.client.getPosts(getPostsForm));
} else {
- let getCommentsForm: GetCommentsForm = {
+ let getCommentsForm: GetComments = {
page,
limit: fetchLimit,
sort,
type_,
};
- setAuth(getCommentsForm, req.auth);
+ setOptionalAuth(getCommentsForm, req.auth);
promises.push(req.client.getComments(getCommentsForm));
}
- let trendingCommunitiesForm: ListCommunitiesForm = {
+ let trendingCommunitiesForm: ListCommunities = {
sort: SortType.Hot,
limit: 6,
};
get documentTitle(): string {
return `${
- this.state.siteRes.site ? this.state.siteRes.site.name : 'Lemmy'
+ this.state.siteRes.site_view
+ ? this.state.siteRes.site_view.site.name
+ : 'Lemmy'
}`;
}
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
- {this.state.siteRes.site && (
+ {this.state.siteRes.site_view.site && (
<div class="row">
<main role="main" class="col-12 col-md-8">
{this.posts()}
</T>
</h5>
<ul class="list-inline">
- {this.state.trendingCommunities.map(community => (
+ {this.state.trendingCommunities.map(cv => (
<li class="list-inline-item d-inline">
- <CommunityLink community={community} />
+ <CommunityLink community={cv.community} />
</li>
))}
</ul>
</T>
</h5>
<ul class="list-inline mb-0">
- {this.state.subscribedCommunities.map(community => (
+ {this.state.subscribedCommunities.map(cfv => (
<li class="list-inline-item d-inline">
- <CommunityLink
- community={{
- name: community.community_name,
- id: community.community_id,
- local: community.community_local,
- actor_id: community.community_actor_id,
- icon: community.community_icon,
- }}
- />
+ <CommunityLink community={cfv.community} />
</li>
))}
</ul>
}
sidebar() {
+ let site = this.state.siteRes.site_view.site;
return (
<div>
{!this.state.showEditSite ? (
{this.siteName()}
{this.adminButtons()}
</div>
- <BannerIconHeader banner={this.state.siteRes.site.banner} />
+ <BannerIconHeader banner={site.banner} />
{this.siteInfo()}
</div>
) : (
- <SiteForm
- site={this.state.siteRes.site}
- onCancel={this.handleEditCancel}
- />
+ <SiteForm site={site} onCancel={this.handleEditCancel} />
)}
</div>
);
siteInfo() {
return (
<div>
- {this.state.siteRes.site.description && this.siteDescription()}
+ {this.state.siteRes.site_view.site.description &&
+ this.siteDescription()}
{this.badges()}
{this.admins()}
</div>
return (
<ul class="mt-1 list-inline small mb-0">
<li class="list-inline-item">{i18n.t('admins')}:</li>
- {this.state.siteRes.admins.map(admin => (
+ {this.state.siteRes.admins.map(av => (
<li class="list-inline-item">
- <UserListing
- user={{
- name: admin.name,
- preferred_username: admin.preferred_username,
- avatar: admin.avatar,
- local: admin.local,
- actor_id: admin.actor_id,
- id: admin.id,
- }}
- />
+ <UserListing user={av.user} />
</li>
))}
</ul>
}
badges() {
+ let site_view = this.state.siteRes.site_view;
return (
<ul class="my-2 list-inline">
<li className="list-inline-item badge badge-secondary">
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_users', {
- count: this.state.siteRes.site.number_of_users,
+ count: site_view.counts.users,
})}
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_communities', {
- count: this.state.siteRes.site.number_of_communities,
+ count: site_view.counts.communities,
})}
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_posts', {
- count: this.state.siteRes.site.number_of_posts,
+ count: site_view.counts.posts,
})}
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_comments', {
- count: this.state.siteRes.site.number_of_comments,
+ count: site_view.counts.comments,
})}
</li>
<li className="list-inline-item">
return (
<div
className="md-div"
- dangerouslySetInnerHTML={mdToHtml(this.state.siteRes.site.description)}
+ dangerouslySetInnerHTML={mdToHtml(
+ this.state.siteRes.site_view.site.description
+ )}
/>
);
}
}
listings() {
+ let site = this.state.siteRes.site_view.site;
return this.state.dataType == DataType.Post ? (
<PostListings
posts={this.state.posts}
showCommunity
removeDuplicates
sort={this.state.sort}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableDownvotes={site.enable_downvotes}
+ enableNsfw={site.enable_nsfw}
/>
) : (
<CommentNodes
showCommunity
sortType={this.state.sort}
showContext
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
+ enableDownvotes={site.enable_downvotes}
/>
);
}
get showLocal(): boolean {
return (
- this.isoData.site.federated_instances !== null &&
- this.isoData.site.federated_instances.length > 0
+ this.isoData.site_res.federated_instances !== null &&
+ this.isoData.site_res.federated_instances.length > 0
);
}
return (
UserService.Instance.user &&
this.state.siteRes.admins
- .map(a => a.id)
+ .map(a => a.user.id)
.includes(UserService.Instance.user.id)
);
}
fetchData() {
if (this.state.dataType == DataType.Post) {
- let getPostsForm: GetPostsForm = {
+ let getPostsForm: GetPosts = {
page: this.state.page,
limit: fetchLimit,
sort: this.state.sort,
type_: this.state.listingType,
+ auth: authField(false),
};
- WebSocketService.Instance.getPosts(getPostsForm);
+ WebSocketService.Instance.send(wsClient.getPosts(getPostsForm));
} else {
- let getCommentsForm: GetCommentsForm = {
+ let getCommentsForm: GetComments = {
page: this.state.page,
limit: fetchLimit,
sort: this.state.sort,
type_: this.state.listingType,
+ auth: authField(false),
};
- WebSocketService.Instance.getComments(getCommentsForm);
+ WebSocketService.Instance.send(wsClient.getComments(getCommentsForm));
}
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
} else if (msg.reconnect) {
- WebSocketService.Instance.communityJoin({ community_id: 0 });
+ WebSocketService.Instance.send(
+ wsClient.communityJoin({ community_id: 0 })
+ );
this.fetchData();
- } else if (res.op == UserOperation.GetFollowedCommunities) {
- let data = res.data as GetFollowedCommunitiesResponse;
+ } else if (op == UserOperation.GetFollowedCommunities) {
+ let data = wsJsonToRes<GetFollowedCommunitiesResponse>(msg).data;
this.state.subscribedCommunities = data.communities;
this.setState(this.state);
- } else if (res.op == UserOperation.ListCommunities) {
- let data = res.data as ListCommunitiesResponse;
+ } else if (op == UserOperation.ListCommunities) {
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
this.state.trendingCommunities = data.communities;
this.setState(this.state);
- } else if (res.op == UserOperation.EditSite) {
- let data = res.data as SiteResponse;
- this.state.siteRes.site = data.site;
+ } else if (op == UserOperation.EditSite) {
+ let data = wsJsonToRes<SiteResponse>(msg).data;
+ this.state.siteRes.site_view = data.site_view;
this.state.showEditSite = false;
this.setState(this.state);
toast(i18n.t('site_saved'));
- } else if (res.op == UserOperation.GetPosts) {
- let data = res.data as GetPostsResponse;
+ } else if (op == UserOperation.GetPosts) {
+ let data = wsJsonToRes<GetPostsResponse>(msg).data;
this.state.posts = data.posts;
this.state.loading = false;
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.CreatePost) {
- let data = res.data as PostResponse;
+ } else if (op == UserOperation.CreatePost) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
// If you're on subscribed, only push it if you're subscribed.
if (this.state.listingType == ListingType.Subscribed) {
if (
this.state.subscribedCommunities
- .map(c => c.community_id)
- .includes(data.post.community_id)
+ .map(c => c.community.id)
+ .includes(data.post_view.community.id)
) {
- this.state.posts.unshift(data.post);
- notifyPost(data.post, this.context.router);
+ this.state.posts.unshift(data.post_view);
+ notifyPost(data.post_view, this.context.router);
}
} else {
// NSFW posts
- let nsfw = data.post.nsfw || data.post.community_nsfw;
+ let nsfw = data.post_view.post.nsfw || data.post_view.community.nsfw;
// Don't push the post if its nsfw, and don't have that setting on
if (
UserService.Instance.user &&
UserService.Instance.user.show_nsfw)
) {
- this.state.posts.unshift(data.post);
- notifyPost(data.post, this.context.router);
+ this.state.posts.unshift(data.post_view);
+ notifyPost(data.post_view, this.context.router);
}
}
this.setState(this.state);
} else if (
- res.op == UserOperation.EditPost ||
- res.op == UserOperation.DeletePost ||
- res.op == UserOperation.RemovePost ||
- res.op == UserOperation.LockPost ||
- res.op == UserOperation.StickyPost ||
- res.op == UserOperation.SavePost
+ op == UserOperation.EditPost ||
+ op == UserOperation.DeletePost ||
+ op == UserOperation.RemovePost ||
+ op == UserOperation.LockPost ||
+ op == UserOperation.StickyPost ||
+ op == UserOperation.SavePost
) {
- let data = res.data as PostResponse;
- editPostFindRes(data, this.state.posts);
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ editPostFindRes(data.post_view, this.state.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePostLike) {
- let data = res.data as PostResponse;
- createPostLikeFindRes(data, this.state.posts);
+ } else if (op == UserOperation.CreatePostLike) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ createPostLikeFindRes(data.post_view, this.state.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.AddAdmin) {
- let data = res.data as AddAdminResponse;
+ } else if (op == UserOperation.AddAdmin) {
+ let data = wsJsonToRes<AddAdminResponse>(msg).data;
this.state.siteRes.admins = data.admins;
this.setState(this.state);
- } else if (res.op == UserOperation.BanUser) {
- let data = res.data as BanUserResponse;
- let found = this.state.siteRes.banned.find(u => (u.id = data.user.id));
+ } else if (op == UserOperation.BanUser) {
+ let data = wsJsonToRes<BanUserResponse>(msg).data;
+ let found = this.state.siteRes.banned.find(
+ u => (u.user.id = data.user_view.user.id)
+ );
// Remove the banned if its found in the list, and the action is an unban
if (found && !data.banned) {
this.state.siteRes.banned = this.state.siteRes.banned.filter(
- i => i.id !== data.user.id
+ i => i.user.id !== data.user_view.user.id
);
} else {
- this.state.siteRes.banned.push(data.user);
+ this.state.siteRes.banned.push(data.user_view);
}
this.state.posts
- .filter(p => p.creator_id == data.user.id)
- .forEach(p => (p.banned = data.banned));
+ .filter(p => p.creator.id == data.user_view.user.id)
+ .forEach(p => (p.creator.banned = data.banned));
this.setState(this.state);
- } else if (res.op == UserOperation.GetComments) {
- let data = res.data as GetCommentsResponse;
+ } else if (op == UserOperation.GetComments) {
+ let data = wsJsonToRes<GetCommentsResponse>(msg).data;
this.state.comments = data.comments;
this.state.loading = false;
this.setState(this.state);
} else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
+ op == UserOperation.EditComment ||
+ op == UserOperation.DeleteComment ||
+ op == UserOperation.RemoveComment
) {
- let data = res.data as CommentResponse;
- editCommentRes(data, this.state.comments);
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ editCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateComment) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
// Necessary since it might be a user reply
if (data.recipient_ids.length == 0) {
if (this.state.listingType == ListingType.Subscribed) {
if (
this.state.subscribedCommunities
- .map(c => c.community_id)
- .includes(data.comment.community_id)
+ .map(c => c.community.id)
+ .includes(data.comment_view.community.id)
) {
- this.state.comments.unshift(data.comment);
+ this.state.comments.unshift(data.comment_view);
}
} else {
- this.state.comments.unshift(data.comment);
+ this.state.comments.unshift(data.comment_view);
}
this.setState(this.state);
}
- } else if (res.op == UserOperation.SaveComment) {
- let data = res.data as CommentResponse;
- saveCommentRes(data, this.state.comments);
+ } else if (op == UserOperation.SaveComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ saveCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateCommentLike) {
- let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.comments);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(data.comment_view, this.state.comments);
this.setState(this.state);
}
}
import { Subscription } from 'rxjs';
import {
UserOperation,
- GetModlogForm,
+ GetModlog,
GetModlogResponse,
- ModRemovePost,
- ModLockPost,
- ModStickyPost,
- ModRemoveComment,
- ModRemoveCommunity,
- ModBanFromCommunity,
- ModBan,
- ModAddCommunity,
- ModAdd,
- WebSocketJsonResponse,
- Site,
+ SiteView,
+ ModRemovePostView,
+ ModLockPostView,
+ ModStickyPostView,
+ ModRemoveCommentView,
+ ModRemoveCommunityView,
+ ModBanFromCommunityView,
+ ModBanView,
+ ModAddCommunityView,
+ ModAddView,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
import {
wsJsonToRes,
- addTypeInfo,
fetchLimit,
toast,
setIsoData,
wsSubscribe,
isBrowser,
+ wsUserOp,
+ wsClient,
} from '../utils';
import { MomentTime } from './moment-time';
import { HtmlTags } from './html-tags';
import moment from 'moment';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
+import { UserListing } from './user-listing';
+import { CommunityLink } from './community-link';
+
+enum ModlogEnum {
+ ModRemovePost,
+ ModLockPost,
+ ModStickyPost,
+ ModRemoveComment,
+ ModRemoveCommunity,
+ ModBanFromCommunity,
+ ModAddCommunity,
+ ModAdd,
+ ModBan,
+}
+
+type ModlogType = {
+ id: number;
+ type_: ModlogEnum;
+ view:
+ | ModRemovePostView
+ | ModLockPostView
+ | ModStickyPostView
+ | ModRemoveCommentView
+ | ModRemoveCommunityView
+ | ModBanFromCommunityView
+ | ModBanView
+ | ModAddCommunityView
+ | ModAddView;
+ when_: string;
+};
interface ModlogState {
- combined: {
- type_: string;
- data:
- | ModRemovePost
- | ModLockPost
- | ModStickyPost
- | ModRemoveCommunity
- | ModAdd
- | ModBan;
- }[];
+ res: GetModlogResponse;
communityId?: number;
communityName?: string;
page: number;
- site: Site;
+ site_view: SiteView;
loading: boolean;
}
private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: ModlogState = {
- combined: [],
+ res: {
+ removed_posts: [],
+ locked_posts: [],
+ stickied_posts: [],
+ removed_comments: [],
+ removed_communities: [],
+ banned_from_community: [],
+ banned: [],
+ added_to_community: [],
+ added: [],
+ },
page: 1,
loading: true,
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
};
constructor(props: any, context: any) {
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
let data = this.isoData.routeData[0];
- this.setCombined(data);
+ this.state.res = data;
this.state.loading = false;
} else {
this.refetch();
}
}
- setCombined(res: GetModlogResponse) {
- let removed_posts = addTypeInfo(res.removed_posts, 'removed_posts');
- let locked_posts = addTypeInfo(res.locked_posts, 'locked_posts');
- let stickied_posts = addTypeInfo(res.stickied_posts, 'stickied_posts');
- let removed_comments = addTypeInfo(
- res.removed_comments,
- 'removed_comments'
- );
- let removed_communities = addTypeInfo(
- res.removed_communities,
- 'removed_communities'
- );
- let banned_from_community = addTypeInfo(
- res.banned_from_community,
- 'banned_from_community'
- );
- let added_to_community = addTypeInfo(
- res.added_to_community,
- 'added_to_community'
+ buildCombined(res: GetModlogResponse): ModlogType[] {
+ let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
+ id: r.mod_remove_post.id,
+ type_: ModlogEnum.ModRemovePost,
+ view: r,
+ when_: r.mod_remove_post.when_,
+ }));
+
+ let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
+ id: r.mod_lock_post.id,
+ type_: ModlogEnum.ModLockPost,
+ view: r,
+ when_: r.mod_lock_post.when_,
+ }));
+
+ let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
+ id: r.mod_sticky_post.id,
+ type_: ModlogEnum.ModStickyPost,
+ view: r,
+ when_: r.mod_sticky_post.when_,
+ }));
+
+ let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
+ id: r.mod_remove_comment.id,
+ type_: ModlogEnum.ModRemoveComment,
+ view: r,
+ when_: r.mod_remove_comment.when_,
+ }));
+
+ let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
+ id: r.mod_remove_community.id,
+ type_: ModlogEnum.ModRemoveCommunity,
+ view: r,
+ when_: r.mod_remove_community.when_,
+ }));
+
+ let banned_from_community: ModlogType[] = res.banned_from_community.map(
+ r => ({
+ id: r.mod_ban_from_community.id,
+ type_: ModlogEnum.ModBanFromCommunity,
+ view: r,
+ when_: r.mod_ban_from_community.when_,
+ })
);
- let added = addTypeInfo(res.added, 'added');
- let banned = addTypeInfo(res.banned, 'banned');
- this.state.combined = [];
-
- this.state.combined.push(...removed_posts);
- this.state.combined.push(...locked_posts);
- this.state.combined.push(...stickied_posts);
- this.state.combined.push(...removed_comments);
- this.state.combined.push(...removed_communities);
- this.state.combined.push(...banned_from_community);
- this.state.combined.push(...added_to_community);
- this.state.combined.push(...added);
- this.state.combined.push(...banned);
-
- if (this.state.communityId && this.state.combined.length > 0) {
- this.state.communityName = (this.state.combined[0]
- .data as ModRemovePost).community_name;
+
+ let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
+ id: r.mod_add_community.id,
+ type_: ModlogEnum.ModAddCommunity,
+ view: r,
+ when_: r.mod_add_community.when_,
+ }));
+
+ let added: ModlogType[] = res.added.map(r => ({
+ id: r.mod_add.id,
+ type_: ModlogEnum.ModAdd,
+ view: r,
+ when_: r.mod_add.when_,
+ }));
+
+ let banned: ModlogType[] = res.banned.map(r => ({
+ id: r.mod_ban.id,
+ type_: ModlogEnum.ModBan,
+ view: r,
+ when_: r.mod_ban.when_,
+ }));
+
+ let combined: ModlogType[] = [];
+
+ combined.push(...removed_posts);
+ combined.push(...locked_posts);
+ combined.push(...stickied_posts);
+ combined.push(...removed_comments);
+ combined.push(...removed_communities);
+ combined.push(...banned_from_community);
+ combined.push(...added_to_community);
+ combined.push(...added);
+ combined.push(...banned);
+
+ if (this.state.communityId && combined.length > 0) {
+ this.state.communityName = (combined[0]
+ .view as ModRemovePostView).community.name;
}
// Sort them by time
- this.state.combined.sort((a, b) =>
- b.data.when_.localeCompare(a.data.when_)
- );
+ combined.sort((a, b) => b.when_.localeCompare(a.when_));
+
+ return combined;
+ }
+
+ renderModlogType(i: ModlogType) {
+ switch (i.type_) {
+ case ModlogEnum.ModRemovePost:
+ let mrpv = i.view as ModRemovePostView;
+ return [
+ mrpv.mod_remove_post.removed ? 'Removed ' : 'Restored ',
+ <span>
+ Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
+ </span>,
+ mrpv.mod_remove_post.reason &&
+ ` reason: ${mrpv.mod_remove_post.reason}`,
+ ];
+ case ModlogEnum.ModLockPost:
+ let mlpv = i.view as ModLockPostView;
+ return [
+ mlpv.mod_lock_post.locked ? 'Locked ' : 'Unlocked ',
+ <span>
+ Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
+ </span>,
+ ];
+ case ModlogEnum.ModStickyPost:
+ let mspv = i.view as ModStickyPostView;
+ return [
+ mspv.mod_sticky_post.stickied ? 'Stickied ' : 'Unstickied ',
+ <span>
+ Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
+ </span>,
+ ];
+ case ModlogEnum.ModRemoveComment:
+ let mrc = i.view as ModRemoveCommentView;
+ return [
+ mrc.mod_remove_comment.removed ? 'Removed ' : 'Restored ',
+ <span>
+ Comment{' '}
+ <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
+ {mrc.comment.content}
+ </Link>
+ </span>,
+ <span>
+ {' '}
+ by <UserListing user={mrc.commenter} />
+ </span>,
+ mrc.mod_remove_comment.reason &&
+ ` reason: ${mrc.mod_remove_comment.reason}`,
+ ];
+ case ModlogEnum.ModRemoveCommunity:
+ let mrco = i.view as ModRemoveCommunityView;
+ return [
+ mrco.mod_remove_community.removed ? 'Removed ' : 'Restored ',
+ <span>
+ Community <CommunityLink community={mrco.community} />
+ </span>,
+ mrco.mod_remove_community.reason &&
+ ` reason: ${mrco.mod_remove_community.reason}`,
+ mrco.mod_remove_community.expires &&
+ ` expires: ${moment
+ .utc(mrco.mod_remove_community.expires)
+ .fromNow()}`,
+ ];
+ case ModlogEnum.ModBanFromCommunity:
+ let mbfc = i.view as ModBanFromCommunityView;
+ return [
+ <span>
+ {mbfc.mod_ban_from_community.banned ? 'Banned ' : 'Unbanned '}{' '}
+ </span>,
+ <span>
+ <UserListing user={mbfc.banned_user} />
+ </span>,
+ <span> from the community </span>,
+ <span>
+ <CommunityLink community={mbfc.community} />
+ </span>,
+ <div>
+ {mbfc.mod_ban_from_community.reason &&
+ ` reason: ${mbfc.mod_ban_from_community.reason}`}
+ </div>,
+ <div>
+ {mbfc.mod_ban_from_community.expires &&
+ ` expires: ${moment
+ .utc(mbfc.mod_ban_from_community.expires)
+ .fromNow()}`}
+ </div>,
+ ];
+ case ModlogEnum.ModAddCommunity:
+ let mac = i.view as ModAddCommunityView;
+ return [
+ <span>
+ {mac.mod_add_community.removed ? 'Removed ' : 'Appointed '}{' '}
+ </span>,
+ <span>
+ <UserListing user={mac.modded_user} />
+ </span>,
+ <span> as a mod to the community </span>,
+ <span>
+ <CommunityLink community={mac.community} />
+ </span>,
+ ];
+ case ModlogEnum.ModBan:
+ let mb = i.view as ModBanView;
+ return [
+ <span>{mb.mod_ban.banned ? 'Banned ' : 'Unbanned '} </span>,
+ <span>
+ <UserListing user={mb.banned_user} />
+ </span>,
+ <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
+ <div>
+ {mb.mod_ban.expires &&
+ ` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
+ </div>,
+ ];
+ case ModlogEnum.ModAdd:
+ let ma = i.view as ModAddView;
+ return [
+ <span>{ma.mod_add.removed ? 'Removed ' : 'Appointed '} </span>,
+ <span>
+ <UserListing user={ma.modded_user} />
+ </span>,
+ <span> as an admin </span>,
+ ];
+ default:
+ return <div />;
+ }
}
combined() {
+ let combined = this.buildCombined(this.state.res);
+
return (
<tbody>
- {this.state.combined.map(i => (
+ {combined.map(i => (
<tr>
<td>
- <MomentTime data={i.data} />
- </td>
- <td>
- <Link to={`/u/${i.data.mod_user_name}`}>
- {i.data.mod_user_name}
- </Link>
+ <MomentTime data={i} />
</td>
<td>
- {i.type_ == 'removed_posts' && (
- <>
- {(i.data as ModRemovePost).removed ? 'Removed' : 'Restored'}
- <span>
- {' '}
- Post{' '}
- <Link to={`/post/${(i.data as ModRemovePost).post_id}`}>
- {(i.data as ModRemovePost).post_name}
- </Link>
- </span>
- <div>
- {(i.data as ModRemovePost).reason &&
- ` reason: ${(i.data as ModRemovePost).reason}`}
- </div>
- </>
- )}
- {i.type_ == 'locked_posts' && (
- <>
- {(i.data as ModLockPost).locked ? 'Locked' : 'Unlocked'}
- <span>
- {' '}
- Post{' '}
- <Link to={`/post/${(i.data as ModLockPost).post_id}`}>
- {(i.data as ModLockPost).post_name}
- </Link>
- </span>
- </>
- )}
- {i.type_ == 'stickied_posts' && (
- <>
- {(i.data as ModStickyPost).stickied
- ? 'Stickied'
- : 'Unstickied'}
- <span>
- {' '}
- Post{' '}
- <Link to={`/post/${(i.data as ModStickyPost).post_id}`}>
- {(i.data as ModStickyPost).post_name}
- </Link>
- </span>
- </>
- )}
- {i.type_ == 'removed_comments' && (
- <>
- {(i.data as ModRemoveComment).removed
- ? 'Removed'
- : 'Restored'}
- <span>
- {' '}
- Comment{' '}
- <Link
- to={`/post/${
- (i.data as ModRemoveComment).post_id
- }/comment/${(i.data as ModRemoveComment).comment_id}`}
- >
- {(i.data as ModRemoveComment).comment_content}
- </Link>
- </span>
- <span>
- {' '}
- by{' '}
- <Link
- to={`/u/${
- (i.data as ModRemoveComment).comment_user_name
- }`}
- >
- {(i.data as ModRemoveComment).comment_user_name}
- </Link>
- </span>
- <div>
- {(i.data as ModRemoveComment).reason &&
- ` reason: ${(i.data as ModRemoveComment).reason}`}
- </div>
- </>
- )}
- {i.type_ == 'removed_communities' && (
- <>
- {(i.data as ModRemoveCommunity).removed
- ? 'Removed'
- : 'Restored'}
- <span>
- {' '}
- Community{' '}
- <Link
- to={`/c/${(i.data as ModRemoveCommunity).community_name}`}
- >
- {(i.data as ModRemoveCommunity).community_name}
- </Link>
- </span>
- <div>
- {(i.data as ModRemoveCommunity).reason &&
- ` reason: ${(i.data as ModRemoveCommunity).reason}`}
- </div>
- <div>
- {(i.data as ModRemoveCommunity).expires &&
- ` expires: ${moment
- .utc((i.data as ModRemoveCommunity).expires)
- .fromNow()}`}
- </div>
- </>
- )}
- {i.type_ == 'banned_from_community' && (
- <>
- <span>
- {(i.data as ModBanFromCommunity).banned
- ? 'Banned '
- : 'Unbanned '}{' '}
- </span>
- <span>
- <Link
- to={`/u/${
- (i.data as ModBanFromCommunity).other_user_name
- }`}
- >
- {(i.data as ModBanFromCommunity).other_user_name}
- </Link>
- </span>
- <span> from the community </span>
- <span>
- <Link
- to={`/c/${
- (i.data as ModBanFromCommunity).community_name
- }`}
- >
- {(i.data as ModBanFromCommunity).community_name}
- </Link>
- </span>
- <div>
- {(i.data as ModBanFromCommunity).reason &&
- ` reason: ${(i.data as ModBanFromCommunity).reason}`}
- </div>
- <div>
- {(i.data as ModBanFromCommunity).expires &&
- ` expires: ${moment
- .utc((i.data as ModBanFromCommunity).expires)
- .fromNow()}`}
- </div>
- </>
- )}
- {i.type_ == 'added_to_community' && (
- <>
- <span>
- {(i.data as ModAddCommunity).removed
- ? 'Removed '
- : 'Appointed '}{' '}
- </span>
- <span>
- <Link
- to={`/u/${(i.data as ModAddCommunity).other_user_name}`}
- >
- {(i.data as ModAddCommunity).other_user_name}
- </Link>
- </span>
- <span> as a mod to the community </span>
- <span>
- <Link
- to={`/c/${(i.data as ModAddCommunity).community_name}`}
- >
- {(i.data as ModAddCommunity).community_name}
- </Link>
- </span>
- </>
- )}
- {i.type_ == 'banned' && (
- <>
- <span>
- {(i.data as ModBan).banned ? 'Banned ' : 'Unbanned '}{' '}
- </span>
- <span>
- <Link to={`/u/${(i.data as ModBan).other_user_name}`}>
- {(i.data as ModBan).other_user_name}
- </Link>
- </span>
- <div>
- {(i.data as ModBan).reason &&
- ` reason: ${(i.data as ModBan).reason}`}
- </div>
- <div>
- {(i.data as ModBan).expires &&
- ` expires: ${moment
- .utc((i.data as ModBan).expires)
- .fromNow()}`}
- </div>
- </>
- )}
- {i.type_ == 'added' && (
- <>
- <span>
- {(i.data as ModAdd).removed ? 'Removed ' : 'Appointed '}{' '}
- </span>
- <span>
- <Link to={`/u/${(i.data as ModAdd).other_user_name}`}>
- {(i.data as ModAdd).other_user_name}
- </Link>
- </span>
- <span> as an admin </span>
- </>
- )}
+ <UserListing user={i.view.moderator} />
</td>
+ <td>{this.renderModlogType(i)}</td>
</tr>
))}
</tbody>
}
get documentTitle(): string {
- return `Modlog - ${this.state.site.name}`;
+ return `Modlog - ${this.state.site_view.site.name}`;
}
render() {
}
refetch() {
- let modlogForm: GetModlogForm = {
+ let modlogForm: GetModlog = {
community_id: this.state.communityId,
page: this.state.page,
limit: fetchLimit,
};
- WebSocketService.Instance.getModlog(modlogForm);
+ WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let communityId = pathSplit[3];
let promises: Promise<any>[] = [];
- let modlogForm: GetModlogForm = {
+ let modlogForm: GetModlog = {
page: 1,
limit: fetchLimit,
};
return promises;
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
- } else if (res.op == UserOperation.GetModlog) {
- let data = res.data as GetModlogResponse;
+ } else if (op == UserOperation.GetModlog) {
+ let data = wsJsonToRes<GetModlogResponse>(msg).data;
this.state.loading = false;
window.scrollTo(0, 0);
- this.setCombined(data);
+ this.state.res = data;
this.setState(this.state);
}
}
import { WebSocketService, UserService } from '../services';
import {
UserOperation,
- GetRepliesForm,
+ GetReplies,
GetRepliesResponse,
- GetUserMentionsForm,
+ GetUserMentions,
GetUserMentionsResponse,
- GetPrivateMessagesForm,
+ GetPrivateMessages,
PrivateMessagesResponse,
SortType,
GetSiteResponse,
- Comment,
+ CommentView,
CommentResponse,
- PrivateMessage,
PrivateMessageResponse,
- WebSocketJsonResponse,
+ PrivateMessageView,
} from 'lemmy-js-client';
import {
wsJsonToRes,
isBrowser,
wsSubscribe,
supportLemmyUrl,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import { i18n } from '../i18next';
import { PictrsImage } from './pictrs-image';
interface NavbarProps {
- site: GetSiteResponse;
+ site_res: GetSiteResponse;
}
interface NavbarState {
isLoggedIn: boolean;
expanded: boolean;
- replies: Comment[];
- mentions: Comment[];
- messages: PrivateMessage[];
+ replies: CommentView[];
+ mentions: CommentView[];
+ messages: PrivateMessageView[];
unreadCount: number;
searchParam: string;
toggleSearch: boolean;
private unreadCountSub: Subscription;
private searchTextField: RefObject<HTMLInputElement>;
emptyState: NavbarState = {
- isLoggedIn: !!this.props.site.my_user,
+ isLoggedIn: !!this.props.site_res.my_user,
unreadCount: 0,
replies: [],
mentions: [],
// i18n.changeLanguage('de');
} else {
this.requestNotificationPermission();
- WebSocketService.Instance.userJoin();
+ WebSocketService.Instance.send(
+ wsClient.userJoin({
+ auth: authField(),
+ })
+ );
this.fetchUnreads();
}
// A login
if (res !== undefined) {
this.requestNotificationPermission();
- WebSocketService.Instance.getSite();
+ WebSocketService.Instance.send(
+ wsClient.getSite({ auth: authField() })
+ );
} else {
this.setState({ isLoggedIn: false });
}
// TODO class active corresponding to current page
navbar() {
- let user = this.props.site.my_user;
+ let user = this.props.site_res.my_user || UserService.Instance.user;
return (
<nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
<div class="container">
- {this.props.site.site && (
+ {this.props.site_res.site_view && (
<Link
- title={this.props.site.version}
+ title={this.props.site_res.version}
className="d-flex align-items-center navbar-brand mr-md-3"
to="/"
>
- {this.props.site.site.icon && showAvatars() && (
- <PictrsImage src={this.props.site.site.icon} icon />
+ {this.props.site_res.site_view.site.icon && showAvatars() && (
+ <PictrsImage
+ src={this.props.site_res.site_view.site.icon}
+ icon
+ />
)}
- {this.props.site.site.name}
+ {this.props.site_res.site_view.site.name}
</Link>
)}
{this.state.isLoggedIn && (
i.setState(i.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
if (msg.error == 'not_logged_in') {
UserService.Instance.logout();
}
return;
} else if (msg.reconnect) {
- WebSocketService.Instance.userJoin();
+ WebSocketService.Instance.send(
+ wsClient.userJoin({
+ auth: authField(),
+ })
+ );
this.fetchUnreads();
- } else if (res.op == UserOperation.GetReplies) {
- let data = res.data as GetRepliesResponse;
- let unreadReplies = data.replies.filter(r => !r.read);
+ } else if (op == UserOperation.GetReplies) {
+ let data = wsJsonToRes<GetRepliesResponse>(msg).data;
+ let unreadReplies = data.replies.filter(r => !r.comment.read);
this.state.replies = unreadReplies;
this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
- } else if (res.op == UserOperation.GetUserMentions) {
- let data = res.data as GetUserMentionsResponse;
- let unreadMentions = data.mentions.filter(r => !r.read);
+ } else if (op == UserOperation.GetUserMentions) {
+ let data = wsJsonToRes<GetUserMentionsResponse>(msg).data;
+ let unreadMentions = data.mentions.filter(r => !r.comment.read);
this.state.mentions = unreadMentions;
this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
- } else if (res.op == UserOperation.GetPrivateMessages) {
- let data = res.data as PrivateMessagesResponse;
- let unreadMessages = data.messages.filter(r => !r.read);
+ } else if (op == UserOperation.GetPrivateMessages) {
+ let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
+ let unreadMessages = data.private_messages.filter(
+ r => !r.private_message.read
+ );
this.state.messages = unreadMessages;
this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state);
this.sendUnreadCount();
- } else if (res.op == UserOperation.GetSite) {
+ } else if (op == UserOperation.GetSite) {
// This is only called on a successful login
- let data = res.data as GetSiteResponse;
+ let data = wsJsonToRes<GetSiteResponse>(msg).data;
+ console.log(data.my_user);
UserService.Instance.user = data.my_user;
setTheme(UserService.Instance.user.theme);
i18n.changeLanguage(getLanguage());
this.state.isLoggedIn = true;
this.setState(this.state);
- } else if (res.op == UserOperation.CreateComment) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
if (this.state.isLoggedIn) {
if (data.recipient_ids.includes(UserService.Instance.user.id)) {
- this.state.replies.push(data.comment);
+ this.state.replies.push(data.comment_view);
this.state.unreadCount++;
this.setState(this.state);
this.sendUnreadCount();
- notifyComment(data.comment, this.context.router);
+ notifyComment(data.comment_view, this.context.router);
}
}
- } else if (res.op == UserOperation.CreatePrivateMessage) {
- let data = res.data as PrivateMessageResponse;
+ } else if (op == UserOperation.CreatePrivateMessage) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
if (this.state.isLoggedIn) {
- if (data.message.recipient_id == UserService.Instance.user.id) {
- this.state.messages.push(data.message);
+ if (
+ data.private_message_view.recipient.id == UserService.Instance.user.id
+ ) {
+ this.state.messages.push(data.private_message_view);
this.state.unreadCount++;
this.setState(this.state);
this.sendUnreadCount();
- notifyPrivateMessage(data.message, this.context.router);
+ notifyPrivateMessage(data.private_message_view, this.context.router);
}
}
}
fetchUnreads() {
console.log('Fetching unreads...');
- let repliesForm: GetRepliesForm = {
+ let repliesForm: GetReplies = {
sort: SortType.New,
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: authField(),
};
- let userMentionsForm: GetUserMentionsForm = {
+ let userMentionsForm: GetUserMentions = {
sort: SortType.New,
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: authField(),
};
- let privateMessagesForm: GetPrivateMessagesForm = {
+ let privateMessagesForm: GetPrivateMessages = {
unread_only: true,
page: 1,
limit: fetchLimit,
+ auth: authField(),
};
if (this.currentLocation !== '/inbox') {
- WebSocketService.Instance.getReplies(repliesForm);
- WebSocketService.Instance.getUserMentions(userMentionsForm);
- WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
+ WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
+ WebSocketService.Instance.send(
+ wsClient.getUserMentions(userMentionsForm)
+ );
+ WebSocketService.Instance.send(
+ wsClient.getPrivateMessages(privateMessagesForm)
+ );
}
}
calculateUnreadCount(): number {
return (
- this.state.replies.filter(r => !r.read).length +
- this.state.mentions.filter(r => !r.read).length +
- this.state.messages.filter(r => !r.read).length
+ this.state.replies.filter(r => !r.comment.read).length +
+ this.state.mentions.filter(r => !r.comment.read).length +
+ this.state.messages.filter(r => !r.private_message.read).length
);
}
get canAdmin(): boolean {
return (
UserService.Instance.user &&
- this.props.site.admins
- .map(a => a.id)
+ this.props.site_res.admins
+ .map(a => a.user.id)
.includes(UserService.Instance.user.id)
);
}
import {
UserOperation,
LoginResponse,
- PasswordChangeForm,
- WebSocketJsonResponse,
- Site,
+ PasswordChange as PasswordChangeForm,
+ SiteView,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
import {
setIsoData,
isBrowser,
wsSubscribe,
+ wsUserOp,
+ wsClient,
} from '../utils';
import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
interface State {
passwordChangeForm: PasswordChangeForm;
loading: boolean;
- site: Site;
+ site_view: SiteView;
}
export class PasswordChange extends Component<any, State> {
password_verify: undefined,
},
loading: false,
- site: this.isoData.site.site,
+ site_view: this.isoData.site_res.site_view,
};
constructor(props: any, context: any) {
}
get documentTitle(): string {
- return `${i18n.t('password_change')} - ${this.state.site.name}`;
+ return `${i18n.t('password_change')} - ${this.state.site_view.site.name}`;
}
render() {
i.state.loading = true;
i.setState(i.state);
- WebSocketService.Instance.passwordChange(i.state.passwordChangeForm);
+ WebSocketService.Instance.send(
+ wsClient.passwordChange(i.state.passwordChangeForm)
+ );
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
- } else if (res.op == UserOperation.PasswordChange) {
- let data = res.data as LoginResponse;
+ } else if (op == UserOperation.PasswordChange) {
+ let data = wsJsonToRes<LoginResponse>(msg).data;
this.state = this.emptyState;
this.setState(this.state);
UserService.Instance.login(data);
import { MarkdownTextArea } from './markdown-textarea';
import { Subscription } from 'rxjs';
import {
- PostForm as PostFormI,
- PostFormParams,
- Post,
+ CreatePost,
+ EditPost,
+ PostView,
PostResponse,
UserOperation,
- Community,
+ CommunityView,
SortType,
- SearchForm,
+ Search,
SearchType,
SearchResponse,
- WebSocketJsonResponse,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
+import { PostFormParams } from '../interfaces';
import {
wsJsonToRes,
getPageTitle,
validTitle,
wsSubscribe,
isBrowser,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
var Choices;
const MAX_POST_TITLE_LENGTH = 200;
interface PostFormProps {
- post?: Post; // If a post is given, that means this is an edit
- communities?: Community[];
+ post_view?: PostView; // If a post is given, that means this is an edit
+ communities?: CommunityView[];
params?: PostFormParams;
onCancel?(): any;
- onCreate?(id: number): any;
- onEdit?(post: Post): any;
+ onCreate?(post: PostView): any;
+ onEdit?(post: PostView): any;
enableNsfw: boolean;
enableDownvotes: boolean;
}
interface PostFormState {
- postForm: PostFormI;
+ postForm: CreatePost;
loading: boolean;
imageLoading: boolean;
previewMode: boolean;
suggestedTitle: string;
- suggestedPosts: Post[];
- crossPosts: Post[];
+ suggestedPosts: PostView[];
+ crossPosts: PostView[];
}
export class PostForm extends Component<PostFormProps, PostFormState> {
private choices: any;
private emptyState: PostFormState = {
postForm: {
+ community_id: null,
name: null,
nsfw: false,
- auth: null,
- community_id: null,
+ auth: authField(false),
},
loading: false,
imageLoading: false,
this.state = this.emptyState;
- if (this.props.post) {
+ // Means its an edit
+ if (this.props.post_view) {
this.state.postForm = {
- body: this.props.post.body,
- // NOTE: debouncing breaks both these for some reason, unless you use defaultValue
- name: this.props.post.name,
- community_id: this.props.post.community_id,
- edit_id: this.props.post.id,
- url: this.props.post.url,
- nsfw: this.props.post.nsfw,
- auth: null,
+ body: this.props.post_view.post.body,
+ name: this.props.post_view.post.name,
+ community_id: this.props.post_view.community.id,
+ url: this.props.post_view.post.url,
+ nsfw: this.props.post_view.post.nsfw,
+ auth: authField(),
};
}
/>
</div>
</div>
- {!this.props.post && (
+ {!this.props.post_view && (
<div class="form-group row">
<label class="col-sm-2 col-form-label" htmlFor="post-community">
{i18n.t('community')}
onInput={linkEvent(this, this.handlePostCommunityChange)}
>
<option>{i18n.t('select_a_community')}</option>
- {this.props.communities.map(community => (
- <option value={community.id}>
- {community.local
- ? community.name
- : `${hostname(community.actor_id)}/${community.name}`}
+ {this.props.communities.map(cv => (
+ <option value={cv.community.id}>
+ {cv.community.local
+ ? cv.community.name
+ : `${hostname(cv.community.actor_id)}/${
+ cv.community.name
+ }`}
</option>
))}
</select>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
- ) : this.props.post ? (
+ ) : this.props.post_view ? (
capitalizeFirstLetter(i18n.t('save'))
) : (
capitalizeFirstLetter(i18n.t('create'))
)}
</button>
- {this.props.post && (
+ {this.props.post_view && (
<button
type="button"
class="btn btn-secondary"
i.state.postForm.url = undefined;
}
- if (i.props.post) {
- WebSocketService.Instance.editPost(i.state.postForm);
+ if (i.props.post_view) {
+ let form: EditPost = {
+ ...i.state.postForm,
+ edit_id: i.props.post_view.post.id,
+ };
+ WebSocketService.Instance.send(wsClient.editPost(form));
} else {
- WebSocketService.Instance.createPost(i.state.postForm);
+ WebSocketService.Instance.send(wsClient.createPost(i.state.postForm));
}
i.state.loading = true;
i.setState(i.state);
fetchPageTitle() {
if (validURL(this.state.postForm.url)) {
- let form: SearchForm = {
+ let form: Search = {
q: this.state.postForm.url,
type_: SearchType.Url,
sort: SortType.TopAll,
page: 1,
limit: 6,
+ auth: authField(false),
};
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
// Fetch the page title
getPageTitle(this.state.postForm.url).then(d => {
}
fetchSimilarPosts() {
- let form: SearchForm = {
+ let form: Search = {
q: this.state.postForm.name,
type_: SearchType.Posts,
sort: SortType.TopAll,
community_id: this.state.postForm.community_id,
page: 1,
limit: 6,
+ auth: authField(false),
};
if (this.state.postForm.name !== '') {
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
} else {
this.state.suggestedPosts = [];
}
}
}
- if (this.props.post) {
- this.state.postForm.community_id = this.props.post.community_id;
+ if (this.props.post_view) {
+ this.state.postForm.community_id = this.props.post_view.community.id;
} else if (
this.props.params &&
(this.props.params.community_id || this.props.params.community_name)
) {
if (this.props.params.community_name) {
let foundCommunityId = this.props.communities.find(
- r => r.name == this.props.params.community_name
- ).id;
+ r => r.community.name == this.props.params.community_name
+ ).community.id;
this.state.postForm.community_id = foundCommunityId;
} else if (this.props.params.community_id) {
this.state.postForm.community_id = this.props.params.community_id;
}
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
- } else if (res.op == UserOperation.CreatePost) {
- let data = res.data as PostResponse;
- if (data.post.creator_id == UserService.Instance.user.id) {
+ } else if (op == UserOperation.CreatePost) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ if (data.post_view.creator.id == UserService.Instance.user.id) {
this.state.loading = false;
- this.props.onCreate(data.post.id);
+ this.props.onCreate(data.post_view);
}
- } else if (res.op == UserOperation.EditPost) {
- let data = res.data as PostResponse;
- if (data.post.creator_id == UserService.Instance.user.id) {
+ } else if (op == UserOperation.EditPost) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ if (data.post_view.creator.id == UserService.Instance.user.id) {
this.state.loading = false;
- this.props.onEdit(data.post);
+ this.props.onEdit(data.post_view);
}
- } else if (res.op == UserOperation.Search) {
- let data = res.data as SearchResponse;
+ } else if (op == UserOperation.Search) {
+ let data = wsJsonToRes<SearchResponse>(msg).data;
if (data.type_ == SearchType[SearchType.Posts]) {
this.state.suggestedPosts = data.posts;
import { Link } from 'inferno-router';
import { WebSocketService, UserService } from '../services';
import {
- Post,
- CreatePostLikeForm,
- DeletePostForm,
- RemovePostForm,
- LockPostForm,
- StickyPostForm,
- SavePostForm,
- CommunityUser,
- UserView,
- BanFromCommunityForm,
- BanUserForm,
- AddModToCommunityForm,
- AddAdminForm,
- TransferSiteForm,
- TransferCommunityForm,
+ PostView,
+ CreatePostLike,
+ DeletePost,
+ RemovePost,
+ LockPost,
+ StickyPost,
+ SavePost,
+ UserViewSafe,
+ BanFromCommunity,
+ BanUser,
+ AddModToCommunity,
+ AddAdmin,
+ TransferSite,
+ TransferCommunity,
+ CommunityModeratorView,
} from 'lemmy-js-client';
import { BanType } from '../interfaces';
import { MomentTime } from './moment-time';
setupTippy,
hostname,
previewLines,
+ wsClient,
+ authField,
} from '../utils';
import { i18n } from '../i18next';
import { externalHost } from '../env';
}
interface PostListingProps {
- post: Post;
+ post_view: PostView;
+ duplicates?: PostView[];
showCommunity?: boolean;
showBody?: boolean;
- moderators?: CommunityUser[];
- admins?: UserView[];
+ moderators?: CommunityModeratorView[];
+ admins?: UserViewSafe[];
enableDownvotes: boolean;
enableNsfw: boolean;
}
viewSource: false,
showAdvanced: false,
showMoreMobile: false,
- my_vote: this.props.post.my_vote,
- score: this.props.post.score,
- upvotes: this.props.post.upvotes,
- downvotes: this.props.post.downvotes,
+ my_vote: this.props.post_view.my_vote,
+ score: this.props.post_view.counts.score,
+ upvotes: this.props.post_view.counts.upvotes,
+ downvotes: this.props.post_view.counts.downvotes,
};
constructor(props: any, context: any) {
}
componentWillReceiveProps(nextProps: PostListingProps) {
- this.state.my_vote = nextProps.post.my_vote;
- this.state.upvotes = nextProps.post.upvotes;
- this.state.downvotes = nextProps.post.downvotes;
- this.state.score = nextProps.post.score;
- if (this.props.post.id !== nextProps.post.id) {
+ this.state.my_vote = nextProps.post_view.my_vote;
+ this.state.upvotes = nextProps.post_view.counts.upvotes;
+ this.state.downvotes = nextProps.post_view.counts.downvotes;
+ this.state.score = nextProps.post_view.counts.score;
+ if (this.props.post_view.post.id !== nextProps.post_view.post.id) {
this.state.imageExpanded = false;
}
this.setState(this.state);
) : (
<div class="col-12">
<PostForm
- post={this.props.post}
+ post_view={this.props.post_view}
onEdit={this.handleEditPost}
onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw}
}
body() {
+ let post = this.props.post_view.post;
return (
<div class="row">
<div class="col-12">
- {this.props.post.url &&
- this.props.showBody &&
- this.props.post.embed_title && (
- <IFramelyCard post={this.props.post} />
- )}
+ {post.url && this.props.showBody && post.embed_title && (
+ <IFramelyCard post={post} />
+ )}
{this.props.showBody &&
- this.props.post.body &&
+ post.body &&
(this.state.viewSource ? (
- <pre>{this.props.post.body}</pre>
+ <pre>{post.body}</pre>
) : (
<div
className="md-div"
- dangerouslySetInnerHTML={mdToHtml(this.props.post.body)}
+ dangerouslySetInnerHTML={mdToHtml(post.body)}
/>
))}
</div>
}
imgThumb(src: string) {
- let post = this.props.post;
+ let post_view = this.props.post_view;
return (
<PictrsImage
src={src}
thumbnail
- nsfw={post.nsfw || post.community_nsfw}
+ nsfw={post_view.post.nsfw || post_view.community.nsfw}
/>
);
}
getImageSrc(): string {
- let post = this.props.post;
+ let post = this.props.post_view.post;
if (isImage(post.url)) {
if (post.url.includes('pictrs')) {
return post.url;
}
thumbnail() {
- let post = this.props.post;
+ let post = this.props.post_view.post;
if (isImage(post.url)) {
return (
}
createdLine() {
- let post = this.props.post;
+ let post_view = this.props.post_view;
return (
<ul class="list-inline mb-1 text-muted small">
<li className="list-inline-item">
- <UserListing
- user={{
- name: post.creator_name,
- preferred_username: post.creator_preferred_username,
- avatar: post.creator_avatar,
- id: post.creator_id,
- local: post.creator_local,
- actor_id: post.creator_actor_id,
- published: post.creator_published,
- }}
- />
+ <UserListing user={post_view.creator} />
{this.isMod && (
<span className="mx-1 badge badge-light">{i18n.t('mod')}</span>
{this.isAdmin && (
<span className="mx-1 badge badge-light">{i18n.t('admin')}</span>
)}
- {(post.banned_from_community || post.banned) && (
+ {(post_view.creator_banned_from_community ||
+ post_view.creator.banned) && (
<span className="mx-1 badge badge-danger">{i18n.t('banned')}</span>
)}
{this.props.showCommunity && (
<span>
<span class="mx-1"> {i18n.t('to')} </span>
- <CommunityLink
- community={{
- name: post.community_name,
- id: post.community_id,
- local: post.community_local,
- actor_id: post.community_actor_id,
- icon: post.community_icon,
- }}
- />
+ <CommunityLink community={post_view.community} />
</span>
)}
</li>
<li className="list-inline-item">•</li>
- {post.url && !(hostname(post.url) == externalHost) && (
+ {post_view.post.url && !(hostname(post_view.post.url) == externalHost) && (
<>
<li className="list-inline-item">
<a
className="text-muted font-italic"
- href={post.url}
+ href={post_view.post.url}
target="_blank"
- title={post.url}
+ title={post_view.post.url}
rel="noopener"
>
- {hostname(post.url)}
+ {hostname(post_view.post.url)}
</a>
</li>
<li className="list-inline-item">•</li>
)}
<li className="list-inline-item">
<span>
- <MomentTime data={post} />
+ <MomentTime data={post_view.post} />
</span>
</li>
- {post.body && (
+ {post_view.post.body && (
<>
<li className="list-inline-item">•</li>
<li className="list-inline-item">
{/* Using a link with tippy doesn't work on touch devices unfortunately */}
<Link
className="text-muted"
- data-tippy-content={md.render(previewLines(post.body))}
+ data-tippy-content={md.render(
+ previewLines(post_view.post.body)
+ )}
data-tippy-allowHtml={true}
- to={`/post/${post.id}`}
+ to={`/post/${post_view.post.id}`}
>
<svg class="mr-1 icon icon-inline">
<use xlinkHref="#icon-book-open"></use>
}
postTitleLine() {
- let post = this.props.post;
+ let post = this.props.post_view.post;
return (
<div className="post-title overflow-hidden">
<h5>
{post.name}
</Link>
)}
- {(isImage(post.url) || this.props.post.thumbnail_url) &&
+ {(isImage(post.url) || post.thumbnail_url) &&
(!this.state.imageExpanded ? (
<span
class="text-monospace unselectable pointer ml-2 text-muted small"
}
commentsLine(mobile: boolean = false) {
- let post = this.props.post;
+ let post_view = this.props.post_view;
return (
<div class="d-flex justify-content-between justify-content-lg-start flex-wrap text-muted font-weight-bold mb-1">
<button class="btn btn-link text-muted p-0">
<Link
className="text-muted small"
title={i18n.t('number_of_comments', {
- count: post.number_of_comments,
+ count: post_view.counts.comments,
})}
- to={`/post/${post.id}`}
+ to={`/post/${post_view.post.id}`}
>
<svg class="mr-1 icon icon-inline">
<use xlinkHref="#icon-message-square"></use>
</svg>
{i18n.t('number_of_comments', {
- count: post.number_of_comments,
+ count: post_view.counts.comments,
})}
</Link>
</button>
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={
- post.saved ? i18n.t('unsave') : i18n.t('save')
+ post_view.saved ? i18n.t('unsave') : i18n.t('save')
}
>
<small>
<svg
- class={`icon icon-inline ${post.saved && 'text-warning'}`}
+ class={`icon icon-inline ${
+ post_view.saved && 'text-warning'
+ }`}
>
<use xlinkHref="#icon-star"></use>
</svg>
class="btn btn-link btn-animate text-muted py-0 pl-1 pr-0"
onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={
- post.saved ? i18n.t('unsave') : i18n.t('save')
+ post_view.saved ? i18n.t('unsave') : i18n.t('save')
}
>
- <svg class={`icon icon-inline ${post.saved && 'text-warning'}`}>
+ <svg
+ class={`icon icon-inline ${post_view.saved && 'text-warning'}`}
+ >
<use xlinkHref="#icon-star"></use>
</svg>
</button>
}
duplicatesLine() {
+ let dupes = this.props.duplicates;
return (
- this.props.post.duplicates && (
+ dupes &&
+ dupes.length > 0 && (
<ul class="list-inline mb-1 small text-muted">
<>
<li className="list-inline-item mr-2">
{i18n.t('cross_posted_to')}
</li>
- {this.props.post.duplicates.map(post => (
+ {dupes.map(pv => (
<li className="list-inline-item mr-2">
- <Link to={`/post/${post.id}`}>
- {post.community_local
- ? post.community_name
- : `${post.community_name}@${hostname(
- post.community_actor_id
- )}`}
+ <Link to={`/post/${pv.post.id}`}>
+ {pv.community.local
+ ? pv.community.name
+ : `${pv.community.name}@${hostname(pv.community.actor_id)}`}
</Link>
</li>
))}
}
postActions(mobile: boolean = false) {
- let post = this.props.post;
+ let post_view = this.props.post_view;
return (
UserService.Instance.user && (
<>
class="btn btn-link btn-animate text-muted py-0 pl-0"
onClick={linkEvent(this, this.handleSavePostClick)}
data-tippy-content={
- post.saved ? i18n.t('unsave') : i18n.t('save')
+ post_view.saved ? i18n.t('unsave') : i18n.t('save')
}
>
<svg
- class={`icon icon-inline ${post.saved && 'text-warning'}`}
+ class={`icon icon-inline ${
+ post_view.saved && 'text-warning'
+ }`}
>
<use xlinkHref="#icon-star"></use>
</svg>
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
- !post.deleted ? i18n.t('delete') : i18n.t('restore')
+ !post_view.post.deleted ? i18n.t('delete') : i18n.t('restore')
}
>
<svg
- class={`icon icon-inline ${post.deleted && 'text-danger'}`}
+ class={`icon icon-inline ${
+ post_view.post.deleted && 'text-danger'
+ }`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
</button>
) : (
<>
- {this.props.showBody && post.body && (
+ {this.props.showBody && post_view.post.body && (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleViewSource)}
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModLock)}
data-tippy-content={
- post.locked ? i18n.t('unlock') : i18n.t('lock')
+ post_view.post.locked ? i18n.t('unlock') : i18n.t('lock')
}
>
<svg
- class={`icon icon-inline ${post.locked && 'text-danger'}`}
+ class={`icon icon-inline ${
+ post_view.post.locked && 'text-danger'
+ }`}
>
<use xlinkHref="#icon-lock"></use>
</svg>
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModSticky)}
data-tippy-content={
- post.stickied ? i18n.t('unsticky') : i18n.t('sticky')
+ post_view.post.stickied
+ ? i18n.t('unsticky')
+ : i18n.t('sticky')
}
>
<svg
class={`icon icon-inline ${
- post.stickied && 'text-success'
+ post_view.post.stickied && 'text-success'
}`}
>
<use xlinkHref="#icon-pin"></use>
)}
{/* Mods can ban from community, and appoint as mods to community */}
{(this.canMod || this.canAdmin) &&
- (!post.removed ? (
+ (!post_view.post.removed ? (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModRemoveShow)}
{this.canMod && (
<>
{!this.isMod &&
- (!post.banned_from_community ? (
+ (!post_view.creator_banned_from_community ? (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(
{i18n.t('unban')}
</button>
))}
- {!post.banned_from_community && post.creator_local && (
- <button
- class="btn btn-link btn-animate text-muted py-0"
- onClick={linkEvent(this, this.handleAddModToCommunity)}
- >
- {this.isMod
- ? i18n.t('remove_as_mod')
- : i18n.t('appoint_as_mod')}
- </button>
- )}
+ {!post_view.creator_banned_from_community &&
+ post_view.creator.local && (
+ <button
+ class="btn btn-link btn-animate text-muted py-0"
+ onClick={linkEvent(this, this.handleAddModToCommunity)}
+ >
+ {this.isMod
+ ? i18n.t('remove_as_mod')
+ : i18n.t('appoint_as_mod')}
+ </button>
+ )}
</>
)}
{/* Community creators and admins can transfer community to another mod */}
{(this.amCommunityCreator || this.canAdmin) &&
this.isMod &&
- post.creator_local &&
+ post_view.creator.local &&
(!this.state.showConfirmTransferCommunity ? (
<button
class="btn btn-link btn-animate text-muted py-0"
{this.canAdmin && (
<>
{!this.isAdmin &&
- (!post.banned ? (
+ (!post_view.creator.banned ? (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleModBanShow)}
{i18n.t('unban_from_site')}
</button>
))}
- {!post.banned && post.creator_local && (
+ {!post_view.creator.banned && post_view.creator.local && (
<button
class="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleAddAdmin)}
}
removeAndBanDialogs() {
- let post = this.props.post;
+ let post = this.props.post_view;
return (
<>
{this.state.showRemoveDialog && (
{/* </div> */}
<div class="form-group row">
<button type="submit" class="btn btn-secondary">
- {i18n.t('ban')} {post.creator_name}
+ {i18n.t('ban')} {post.creator.name}
</button>
</div>
</form>
}
mobileThumbnail() {
- return this.props.post.thumbnail_url || isImage(this.props.post.url) ? (
+ let post = this.props.post_view.post;
+ return post.thumbnail_url || isImage(post.url) ? (
<div class="row">
<div className={`${this.state.imageExpanded ? 'col-12' : 'col-8'}`}>
{this.postTitleLine()}
}
showMobilePreview() {
+ let post = this.props.post_view.post;
return (
- this.props.post.body &&
+ post.body &&
!this.props.showBody && (
<div
className="md-div mb-1"
dangerouslySetInnerHTML={{
- __html: md.render(previewLines(this.props.post.body)),
+ __html: md.render(previewLines(post.body)),
}}
/>
)
private get myPost(): boolean {
return (
UserService.Instance.user &&
- this.props.post.creator_id == UserService.Instance.user.id
+ this.props.post_view.creator.id == UserService.Instance.user.id
);
}
return (
this.props.moderators &&
isMod(
- this.props.moderators.map(m => m.user_id),
- this.props.post.creator_id
+ this.props.moderators.map(m => m.moderator.id),
+ this.props.post_view.creator.id
)
);
}
return (
this.props.admins &&
isMod(
- this.props.admins.map(a => a.id),
- this.props.post.creator_id
+ this.props.admins.map(a => a.user.id),
+ this.props.post_view.creator.id
)
);
}
get canMod(): boolean {
if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins
- .map(a => a.id)
- .concat(this.props.moderators.map(m => m.user_id));
+ .map(a => a.user.id)
+ .concat(this.props.moderators.map(m => m.moderator.id));
return canMod(
UserService.Instance.user,
adminsThenMods,
- this.props.post.creator_id
+ this.props.post_view.creator.id
);
} else {
return false;
get canModOnSelf(): boolean {
if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins
- .map(a => a.id)
- .concat(this.props.moderators.map(m => m.user_id));
+ .map(a => a.user.id)
+ .concat(this.props.moderators.map(m => m.moderator.id));
return canMod(
UserService.Instance.user,
adminsThenMods,
- this.props.post.creator_id,
+ this.props.post_view.creator.id,
true
);
} else {
this.props.admins &&
canMod(
UserService.Instance.user,
- this.props.admins.map(a => a.id),
- this.props.post.creator_id
+ this.props.admins.map(a => a.user.id),
+ this.props.post_view.creator.id
)
);
}
return (
this.props.moderators &&
UserService.Instance.user &&
- this.props.post.creator_id != UserService.Instance.user.id &&
- UserService.Instance.user.id == this.props.moderators[0].user_id
+ this.props.post_view.creator.id != UserService.Instance.user.id &&
+ UserService.Instance.user.id == this.props.moderators[0].moderator.id
);
}
return (
this.props.admins &&
UserService.Instance.user &&
- this.props.post.creator_id != UserService.Instance.user.id &&
- UserService.Instance.user.id == this.props.admins[0].id
+ this.props.post_view.creator.id != UserService.Instance.user.id &&
+ UserService.Instance.user.id == this.props.admins[0].user.id
);
}
i.state.my_vote = new_vote;
- let form: CreatePostLikeForm = {
- post_id: i.props.post.id,
+ let form: CreatePostLike = {
+ post_id: i.props.post_view.post.id,
score: i.state.my_vote,
+ auth: authField(),
};
- WebSocketService.Instance.likePost(form);
+ WebSocketService.Instance.send(wsClient.likePost(form));
i.setState(i.state);
setupTippy();
}
i.state.my_vote = new_vote;
- let form: CreatePostLikeForm = {
- post_id: i.props.post.id,
+ let form: CreatePostLike = {
+ post_id: i.props.post_view.post.id,
score: i.state.my_vote,
+ auth: authField(),
};
- WebSocketService.Instance.likePost(form);
+ WebSocketService.Instance.send(wsClient.likePost(form));
i.setState(i.state);
setupTippy();
}
}
handleDeleteClick(i: PostListing) {
- let deleteForm: DeletePostForm = {
- edit_id: i.props.post.id,
- deleted: !i.props.post.deleted,
- auth: null,
+ let deleteForm: DeletePost = {
+ edit_id: i.props.post_view.post.id,
+ deleted: !i.props.post_view.post.deleted,
+ auth: authField(),
};
- WebSocketService.Instance.deletePost(deleteForm);
+ WebSocketService.Instance.send(wsClient.deletePost(deleteForm));
}
handleSavePostClick(i: PostListing) {
- let saved = i.props.post.saved == undefined ? true : !i.props.post.saved;
- let form: SavePostForm = {
- post_id: i.props.post.id,
+ let saved =
+ i.props.post_view.saved == undefined ? true : !i.props.post_view.saved;
+ let form: SavePost = {
+ post_id: i.props.post_view.post.id,
save: saved,
+ auth: authField(),
};
- WebSocketService.Instance.savePost(form);
+ WebSocketService.Instance.send(wsClient.savePost(form));
}
get crossPostParams(): string {
- let params = `?title=${this.props.post.name}`;
- let post = this.props.post;
+ let post = this.props.post_view.post;
+ let params = `?title=${post.name}`;
if (post.url) {
params += `&url=${encodeURIComponent(post.url)}`;
}
- if (this.props.post.body) {
- params += `&body=${this.props.post.body}`;
+ if (post.body) {
+ params += `&body=${post.body}`;
}
return params;
}
handleModRemoveSubmit(i: PostListing) {
event.preventDefault();
- let form: RemovePostForm = {
- edit_id: i.props.post.id,
- removed: !i.props.post.removed,
+ let form: RemovePost = {
+ edit_id: i.props.post_view.post.id,
+ removed: !i.props.post_view.post.removed,
reason: i.state.removeReason,
- auth: null,
+ auth: authField(),
};
- WebSocketService.Instance.removePost(form);
+ WebSocketService.Instance.send(wsClient.removePost(form));
i.state.showRemoveDialog = false;
i.setState(i.state);
}
handleModLock(i: PostListing) {
- let form: LockPostForm = {
- edit_id: i.props.post.id,
- locked: !i.props.post.locked,
- auth: null,
+ let form: LockPost = {
+ edit_id: i.props.post_view.post.id,
+ locked: !i.props.post_view.post.locked,
+ auth: authField(),
};
- WebSocketService.Instance.lockPost(form);
+ WebSocketService.Instance.send(wsClient.lockPost(form));
}
handleModSticky(i: PostListing) {
- let form: StickyPostForm = {
- edit_id: i.props.post.id,
- stickied: !i.props.post.stickied,
- auth: null,
+ let form: StickyPost = {
+ edit_id: i.props.post_view.post.id,
+ stickied: !i.props.post_view.post.stickied,
+ auth: authField(),
};
- WebSocketService.Instance.stickyPost(form);
+ WebSocketService.Instance.send(wsClient.stickyPost(form));
}
handleModBanFromCommunityShow(i: PostListing) {
if (i.state.banType == BanType.Community) {
// If its an unban, restore all their data
- let ban = !i.props.post.banned_from_community;
+ let ban = !i.props.post_view.creator_banned_from_community;
if (ban == false) {
i.state.removeData = false;
}
- let form: BanFromCommunityForm = {
- user_id: i.props.post.creator_id,
- community_id: i.props.post.community_id,
+ let form: BanFromCommunity = {
+ user_id: i.props.post_view.creator.id,
+ community_id: i.props.post_view.community.id,
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
+ auth: authField(),
};
- WebSocketService.Instance.banFromCommunity(form);
+ WebSocketService.Instance.send(wsClient.banFromCommunity(form));
} else {
// If its an unban, restore all their data
- let ban = !i.props.post.banned;
+ let ban = !i.props.post_view.creator.banned;
if (ban == false) {
i.state.removeData = false;
}
- let form: BanUserForm = {
- user_id: i.props.post.creator_id,
+ let form: BanUser = {
+ user_id: i.props.post_view.creator.id,
ban,
remove_data: i.state.removeData,
reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires),
+ auth: authField(),
};
- WebSocketService.Instance.banUser(form);
+ WebSocketService.Instance.send(wsClient.banUser(form));
}
i.state.showBanDialog = false;
}
handleAddModToCommunity(i: PostListing) {
- let form: AddModToCommunityForm = {
- user_id: i.props.post.creator_id,
- community_id: i.props.post.community_id,
+ let form: AddModToCommunity = {
+ user_id: i.props.post_view.creator.id,
+ community_id: i.props.post_view.community.id,
added: !i.isMod,
+ auth: authField(),
};
- WebSocketService.Instance.addModToCommunity(form);
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
i.setState(i.state);
}
handleAddAdmin(i: PostListing) {
- let form: AddAdminForm = {
- user_id: i.props.post.creator_id,
+ let form: AddAdmin = {
+ user_id: i.props.post_view.creator.id,
added: !i.isAdmin,
+ auth: authField(),
};
- WebSocketService.Instance.addAdmin(form);
+ WebSocketService.Instance.send(wsClient.addAdmin(form));
i.setState(i.state);
}
}
handleTransferCommunity(i: PostListing) {
- let form: TransferCommunityForm = {
- community_id: i.props.post.community_id,
- user_id: i.props.post.creator_id,
+ let form: TransferCommunity = {
+ community_id: i.props.post_view.community.id,
+ user_id: i.props.post_view.creator.id,
+ auth: authField(),
};
- WebSocketService.Instance.transferCommunity(form);
+ WebSocketService.Instance.send(wsClient.transferCommunity(form));
i.state.showConfirmTransferCommunity = false;
i.setState(i.state);
}
}
handleTransferSite(i: PostListing) {
- let form: TransferSiteForm = {
- user_id: i.props.post.creator_id,
+ let form: TransferSite = {
+ user_id: i.props.post_view.creator.id,
+ auth: authField(),
};
- WebSocketService.Instance.transferSite(form);
+ WebSocketService.Instance.send(wsClient.transferSite(form));
i.state.showConfirmTransferSite = false;
i.setState(i.state);
}
import { Component } from 'inferno';
import { Link } from 'inferno-router';
-import { Post, SortType } from 'lemmy-js-client';
+import { PostView, SortType } from 'lemmy-js-client';
import { postSort } from '../utils';
import { PostListing } from './post-listing';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
interface PostListingsProps {
- posts: Post[];
+ posts: PostView[];
showCommunity?: boolean;
removeDuplicates?: boolean;
sort?: SortType;
}
export class PostListings extends Component<PostListingsProps, any> {
+ private duplicatesMap = new Map<number, PostView[]>();
+
constructor(props: any, context: any) {
super(props, context);
}
return (
<div>
{this.props.posts.length > 0 ? (
- this.outer().map(post => (
+ this.outer().map(post_view => (
<>
<PostListing
- post={post}
+ post_view={post_view}
+ duplicates={this.duplicatesMap.get(post_view.post.id)}
showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
);
}
- outer(): Post[] {
+ outer(): PostView[] {
let out = this.props.posts;
if (this.props.removeDuplicates) {
out = this.removeDuplicates(out);
return out;
}
- removeDuplicates(posts: Post[]): Post[] {
+ removeDuplicates(posts: PostView[]): PostView[] {
// A map from post url to list of posts (dupes)
- let urlMap = new Map<string, Post[]>();
+ let urlMap = new Map<string, PostView[]>();
// Loop over the posts, find ones with same urls
- for (let post of posts) {
+ for (let pv of posts) {
if (
- post.url &&
- !post.deleted &&
- !post.removed &&
- !post.community_deleted &&
- !post.community_removed
+ pv.post.url &&
+ !pv.post.deleted &&
+ !pv.post.removed &&
+ !pv.community.deleted &&
+ !pv.community.removed
) {
- if (!urlMap.get(post.url)) {
- urlMap.set(post.url, [post]);
+ if (!urlMap.get(pv.post.url)) {
+ urlMap.set(pv.post.url, [pv]);
} else {
- urlMap.get(post.url).push(post);
+ urlMap.get(pv.post.url).push(pv);
}
}
}
if (e[1].length == 1) {
urlMap.delete(e[0]);
} else {
- e[1].sort((a, b) => a.published.localeCompare(b.published));
+ e[1].sort((a, b) => a.post.published.localeCompare(b.post.published));
}
}
for (let i = 0; i < posts.length; i++) {
- let post = posts[i];
- if (post.url) {
- let found = urlMap.get(post.url);
+ let pv = posts[i];
+ if (pv.post.url) {
+ let found = urlMap.get(pv.post.url);
if (found) {
// If its the oldest, add
- if (post.id == found[0].id) {
- post.duplicates = found.slice(1);
+ if (pv.post.id == found[0].post.id) {
+ this.duplicatesMap.set(pv.post.id, found.slice(1));
}
// Otherwise, delete it
else {
import { Subscription } from 'rxjs';
import {
UserOperation,
- Post as PostI,
+ PostView,
GetPostResponse,
PostResponse,
- MarkCommentAsReadForm,
+ MarkCommentAsRead,
CommentResponse,
CommunityResponse,
- CommentNode as CommentNodeI,
BanFromCommunityResponse,
BanUserResponse,
AddModToCommunityResponse,
AddAdminResponse,
SearchType,
SortType,
- SearchForm,
- GetPostForm,
+ Search,
+ GetPost,
SearchResponse,
GetSiteResponse,
GetCommunityResponse,
- WebSocketJsonResponse,
ListCategoriesResponse,
Category,
} from 'lemmy-js-client';
CommentSortType,
CommentViewType,
InitialFetchRequest,
+ CommentNode as CommentNodeI,
} from '../interfaces';
import { WebSocketService, UserService } from '../services';
import {
getIdFromProps,
getCommentIdFromProps,
wsSubscribe,
- setAuth,
isBrowser,
previewLines,
isImage,
+ wsUserOp,
+ wsClient,
+ authField,
+ setOptionalAuth,
} from '../utils';
import { PostListing } from './post-listing';
import { Sidebar } from './sidebar';
commentViewType: CommentViewType;
scrolled?: boolean;
loading: boolean;
- crossPosts: PostI[];
+ crossPosts: PostView[];
siteRes: GetSiteResponse;
categories: Category[];
}
scrolled: false,
loading: true,
crossPosts: [],
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
categories: [],
};
}
} else {
this.fetchPost();
- WebSocketService.Instance.listCategories();
+ WebSocketService.Instance.send(wsClient.listCategories());
}
}
fetchPost() {
- let form: GetPostForm = {
+ let form: GetPost = {
id: this.state.postId,
+ auth: authField(false),
};
- WebSocketService.Instance.getPost(form);
+ WebSocketService.Instance.send(wsClient.getPost(form));
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let id = Number(pathSplit[2]);
- let postForm: GetPostForm = {
+ let postForm: GetPost = {
id,
};
- setAuth(postForm, req.auth);
+ setOptionalAuth(postForm, req.auth);
promises.push(req.client.getPost(postForm));
promises.push(req.client.listCategories());
}
componentDidMount() {
- WebSocketService.Instance.postJoin({ post_id: this.state.postId });
+ WebSocketService.Instance.send(
+ wsClient.postJoin({ post_id: this.state.postId })
+ );
autosize(document.querySelectorAll('textarea'));
}
this.markScrolledAsRead(this.state.commentId);
}
+ // TODO this needs some re-work
markScrolledAsRead(commentId: number) {
- let found = this.state.postRes.comments.find(c => c.id == commentId);
- let parent = this.state.postRes.comments.find(c => found.parent_id == c.id);
+ let found = this.state.postRes.comments.find(
+ c => c.comment.id == commentId
+ );
+ let parent = this.state.postRes.comments.find(
+ c => found.comment.parent_id == c.comment.id
+ );
let parent_user_id = parent
- ? parent.creator_id
- : this.state.postRes.post.creator_id;
+ ? parent.creator.id
+ : this.state.postRes.post_view.creator.id;
if (
UserService.Instance.user &&
UserService.Instance.user.id == parent_user_id
) {
- let form: MarkCommentAsReadForm = {
- edit_id: found.id,
+ let form: MarkCommentAsRead = {
+ comment_id: found.creator.id,
read: true,
- auth: null,
+ auth: authField(),
};
- WebSocketService.Instance.markCommentAsRead(form);
+ WebSocketService.Instance.send(wsClient.markCommentAsRead(form));
UserService.Instance.unreadCountSub.next(
UserService.Instance.unreadCountSub.value - 1
);
}
get documentTitle(): string {
- return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
+ return `${this.state.postRes.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`;
}
get imageTag(): string {
+ let post = this.state.postRes.post_view.post;
return (
- this.state.postRes.post.thumbnail_url ||
- (this.state.postRes.post.url
- ? isImage(this.state.postRes.post.url)
- ? this.state.postRes.post.url
- : undefined
- : undefined)
+ post.thumbnail_url ||
+ (post.url ? (isImage(post.url) ? post.url : undefined) : undefined)
);
}
get descriptionTag(): string {
- return this.state.postRes.post.body
- ? previewLines(this.state.postRes.post.body)
- : undefined;
+ let body = this.state.postRes.post_view.post.body;
+ return body ? previewLines(body) : undefined;
}
render() {
+ let pv = this.state.postRes?.post_view;
return (
<div class="container">
{this.state.loading ? (
description={this.descriptionTag}
/>
<PostListing
- post={this.state.postRes.post}
+ post_view={pv}
+ duplicates={this.state.crossPosts}
showBody
showCommunity
moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableDownvotes={
+ this.state.siteRes.site_view.site.enable_downvotes
+ }
+ enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
/>
<div className="mb-2" />
<CommentForm
postId={this.state.postId}
- disabled={this.state.postRes.post.locked}
+ disabled={pv.post.locked}
/>
{this.state.postRes.comments.length > 0 && this.sortRadios()}
{this.state.commentViewType == CommentViewType.Tree &&
<CommentNodes
nodes={commentsToFlatNodes(this.state.postRes.comments)}
noIndent
- locked={this.state.postRes.post.locked}
+ locked={this.state.postRes.post_view.post.locked}
moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- postCreatorId={this.state.postRes.post.creator_id}
+ postCreatorId={this.state.postRes.post_view.creator.id}
showContext
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
+ enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
sort={this.state.commentSort}
/>
</div>
return (
<div class="mb-3">
<Sidebar
- community={this.state.postRes.community}
+ community_view={this.state.postRes.community_view}
moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
online={this.state.postRes.online}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
showIcon
categories={this.state.categories}
/>
buildCommentsTree(): CommentNodeI[] {
let map = new Map<number, CommentNodeI>();
- for (let comment of this.state.postRes.comments) {
+ for (let comment_view of this.state.postRes.comments) {
let node: CommentNodeI = {
- comment: comment,
+ comment_view: comment_view,
children: [],
};
- map.set(comment.id, { ...node });
+ map.set(comment_view.comment.id, { ...node });
}
let tree: CommentNodeI[] = [];
- for (let comment of this.state.postRes.comments) {
- let child = map.get(comment.id);
- if (comment.parent_id) {
- let parent_ = map.get(comment.parent_id);
+ for (let comment_view of this.state.postRes.comments) {
+ let child = map.get(comment_view.comment.id);
+ if (comment_view.comment.parent_id) {
+ let parent_ = map.get(comment_view.comment.parent_id);
parent_.children.push(child);
} else {
tree.push(child);
setDepth(node: CommentNodeI, i: number = 0): void {
for (let child of node.children) {
- child.comment.depth = i;
+ child.depth = i;
this.setDepth(child, i + 1);
}
}
<div>
<CommentNodes
nodes={nodes}
- locked={this.state.postRes.post.locked}
+ locked={this.state.postRes.post_view.post.locked}
moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- postCreatorId={this.state.postRes.post.creator_id}
+ postCreatorId={this.state.postRes.post_view.creator.id}
sort={this.state.commentSort}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
+ enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
/>
</div>
);
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
} else if (msg.reconnect) {
let postId = Number(this.props.match.params.id);
- WebSocketService.Instance.postJoin({ post_id: postId });
- WebSocketService.Instance.getPost({
- id: postId,
- });
- } else if (res.op == UserOperation.GetPost) {
- let data = res.data as GetPostResponse;
+ WebSocketService.Instance.send(wsClient.postJoin({ post_id: postId }));
+ WebSocketService.Instance.send(
+ wsClient.getPost({
+ id: postId,
+ auth: authField(false),
+ })
+ );
+ } else if (op == UserOperation.GetPost) {
+ let data = wsJsonToRes<GetPostResponse>(msg).data;
this.state.postRes = data;
this.state.loading = false;
// Get cross-posts
- if (this.state.postRes.post.url) {
- let form: SearchForm = {
- q: this.state.postRes.post.url,
+ if (this.state.postRes.post_view.post.url) {
+ let form: Search = {
+ q: this.state.postRes.post_view.post.url,
type_: SearchType.Url,
sort: SortType.TopAll,
page: 1,
limit: 6,
+ auth: authField(false),
};
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
}
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.CreateComment) {
- let data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
// Necessary since it might be a user reply
if (data.recipient_ids.length == 0) {
- this.state.postRes.comments.unshift(data.comment);
+ this.state.postRes.comments.unshift(data.comment_view);
this.setState(this.state);
}
} else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
+ op == UserOperation.EditComment ||
+ op == UserOperation.DeleteComment ||
+ op == UserOperation.RemoveComment
) {
- let data = res.data as CommentResponse;
- editCommentRes(data, this.state.postRes.comments);
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ editCommentRes(data.comment_view, this.state.postRes.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.SaveComment) {
- let data = res.data as CommentResponse;
- saveCommentRes(data, this.state.postRes.comments);
+ } else if (op == UserOperation.SaveComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ saveCommentRes(data.comment_view, this.state.postRes.comments);
this.setState(this.state);
setupTippy();
- } else if (res.op == UserOperation.CreateCommentLike) {
- let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.postRes.comments);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(data.comment_view, this.state.postRes.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePostLike) {
- let data = res.data as PostResponse;
- createPostLikeRes(data, this.state.postRes.post);
+ } else if (op == UserOperation.CreatePostLike) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ createPostLikeRes(data.post_view, this.state.postRes.post_view);
this.setState(this.state);
} else if (
- res.op == UserOperation.EditPost ||
- res.op == UserOperation.DeletePost ||
- res.op == UserOperation.RemovePost ||
- res.op == UserOperation.LockPost ||
- res.op == UserOperation.StickyPost
+ op == UserOperation.EditPost ||
+ op == UserOperation.DeletePost ||
+ op == UserOperation.RemovePost ||
+ op == UserOperation.LockPost ||
+ op == UserOperation.StickyPost ||
+ op == UserOperation.SavePost
) {
- let data = res.data as PostResponse;
- this.state.postRes.post = data.post;
- this.setState(this.state);
- setupTippy();
- } else if (res.op == UserOperation.SavePost) {
- let data = res.data as PostResponse;
- this.state.postRes.post = data.post;
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ this.state.postRes.post_view = data.post_view;
this.setState(this.state);
setupTippy();
} else if (
- res.op == UserOperation.EditCommunity ||
- res.op == UserOperation.DeleteCommunity ||
- res.op == UserOperation.RemoveCommunity
+ op == UserOperation.EditCommunity ||
+ op == UserOperation.DeleteCommunity ||
+ op == UserOperation.RemoveCommunity ||
+ op == UserOperation.FollowCommunity
) {
- let data = res.data as CommunityResponse;
- this.state.postRes.community = data.community;
- this.state.postRes.post.community_id = data.community.id;
- this.state.postRes.post.community_name = data.community.name;
+ let data = wsJsonToRes<CommunityResponse>(msg).data;
+ this.state.postRes.community_view = data.community_view;
+ this.state.postRes.post_view.community = data.community_view.community;
this.setState(this.state);
- } else if (res.op == UserOperation.FollowCommunity) {
- let data = res.data as CommunityResponse;
- this.state.postRes.community.subscribed = data.community.subscribed;
- this.state.postRes.community.number_of_subscribers =
- data.community.number_of_subscribers;
this.setState(this.state);
- } else if (res.op == UserOperation.BanFromCommunity) {
- let data = res.data as BanFromCommunityResponse;
+ } else if (op == UserOperation.BanFromCommunity) {
+ let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
this.state.postRes.comments
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned_from_community = data.banned));
- if (this.state.postRes.post.creator_id == data.user.id) {
- this.state.postRes.post.banned_from_community = data.banned;
+ .filter(c => c.creator.id == data.user_view.user.id)
+ .forEach(c => (c.creator_banned_from_community = data.banned));
+ if (this.state.postRes.post_view.creator.id == data.user_view.user.id) {
+ this.state.postRes.post_view.creator_banned_from_community =
+ data.banned;
}
this.setState(this.state);
- } else if (res.op == UserOperation.AddModToCommunity) {
- let data = res.data as AddModToCommunityResponse;
+ } else if (op == UserOperation.AddModToCommunity) {
+ let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
this.state.postRes.moderators = data.moderators;
this.setState(this.state);
- } else if (res.op == UserOperation.BanUser) {
- let data = res.data as BanUserResponse;
+ } else if (op == UserOperation.BanUser) {
+ let data = wsJsonToRes<BanUserResponse>(msg).data;
this.state.postRes.comments
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned = data.banned));
- if (this.state.postRes.post.creator_id == data.user.id) {
- this.state.postRes.post.banned = data.banned;
+ .filter(c => c.creator.id == data.user_view.user.id)
+ .forEach(c => (c.creator.banned = data.banned));
+ if (this.state.postRes.post_view.creator.id == data.user_view.user.id) {
+ this.state.postRes.post_view.creator.banned = data.banned;
}
this.setState(this.state);
- } else if (res.op == UserOperation.AddAdmin) {
- let data = res.data as AddAdminResponse;
+ } else if (op == UserOperation.AddAdmin) {
+ let data = wsJsonToRes<AddAdminResponse>(msg).data;
this.state.siteRes.admins = data.admins;
this.setState(this.state);
- } else if (res.op == UserOperation.Search) {
- let data = res.data as SearchResponse;
+ } else if (op == UserOperation.Search) {
+ let data = wsJsonToRes<SearchResponse>(msg).data;
this.state.crossPosts = data.posts.filter(
- p => p.id != Number(this.props.match.params.id)
+ p => p.post.id != Number(this.props.match.params.id)
);
- if (this.state.crossPosts.length) {
- this.state.postRes.post.duplicates = this.state.crossPosts;
- }
this.setState(this.state);
- } else if (res.op == UserOperation.TransferSite) {
- let data = res.data as GetSiteResponse;
+ } else if (op == UserOperation.TransferSite) {
+ let data = wsJsonToRes<GetSiteResponse>(msg).data;
this.state.siteRes = data;
this.setState(this.state);
- } else if (res.op == UserOperation.TransferCommunity) {
- let data = res.data as GetCommunityResponse;
- this.state.postRes.community = data.community;
+ } else if (op == UserOperation.TransferCommunity) {
+ let data = wsJsonToRes<GetCommunityResponse>(msg).data;
+ this.state.postRes.community_view = data.community_view;
+ this.state.postRes.post_view.community = data.community_view.community;
this.state.postRes.moderators = data.moderators;
this.setState(this.state);
- } else if (res.op == UserOperation.ListCategories) {
- let data = res.data as ListCategoriesResponse;
+ } else if (op == UserOperation.ListCategories) {
+ let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
this.state.categories = data.categories;
this.setState(this.state);
}
import { Prompt } from 'inferno-router';
import { Subscription } from 'rxjs';
import {
- PrivateMessageForm as PrivateMessageFormI,
- EditPrivateMessageForm,
- PrivateMessage,
+ CreatePrivateMessage,
+ EditPrivateMessage,
+ PrivateMessageView,
PrivateMessageResponse,
- UserView,
+ UserSafe,
UserOperation,
- WebSocketJsonResponse,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
import {
setupTippy,
wsSubscribe,
isBrowser,
+ wsUserOp,
+ wsClient,
+ authField,
} from '../utils';
import { UserListing } from './user-listing';
import { MarkdownTextArea } from './markdown-textarea';
import { T } from 'inferno-i18next';
interface PrivateMessageFormProps {
- recipient: UserView;
- privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
+ recipient: UserSafe;
+ privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
onCancel?(): any;
- onCreate?(message: PrivateMessage): any;
- onEdit?(message: PrivateMessage): any;
+ onCreate?(message: PrivateMessageView): any;
+ onEdit?(message: PrivateMessageView): any;
}
interface PrivateMessageFormState {
- privateMessageForm: PrivateMessageFormI;
+ privateMessageForm: CreatePrivateMessage;
loading: boolean;
previewMode: boolean;
showDisclaimer: boolean;
privateMessageForm: {
content: null,
recipient_id: this.props.recipient.id,
+ auth: authField(),
},
loading: false,
previewMode: false,
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
+ // Its an edit
if (this.props.privateMessage) {
- this.state.privateMessageForm = {
- content: this.props.privateMessage.content,
- recipient_id: this.props.privateMessage.recipient_id,
- };
+ this.state.privateMessageForm.content = this.props.privateMessage.private_message.content;
}
}
</label>
<div class="col-sm-10 form-control-plaintext">
- <UserListing
- user={{
- name: this.props.recipient.name,
- preferred_username: this.props.recipient.preferred_username,
- avatar: this.props.recipient.avatar,
- id: this.props.recipient.id,
- local: this.props.recipient.local,
- actor_id: this.props.recipient.actor_id,
- }}
- />
+ <UserListing user={this.props.recipient} />
</div>
</div>
)}
handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
event.preventDefault();
if (i.props.privateMessage) {
- let editForm: EditPrivateMessageForm = {
- edit_id: i.props.privateMessage.id,
+ let form: EditPrivateMessage = {
+ edit_id: i.props.privateMessage.private_message.id,
content: i.state.privateMessageForm.content,
+ auth: authField(),
};
- WebSocketService.Instance.editPrivateMessage(editForm);
+ WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
} else {
- WebSocketService.Instance.createPrivateMessage(
- i.state.privateMessageForm
+ WebSocketService.Instance.send(
+ wsClient.createPrivateMessage(i.state.privateMessageForm)
);
}
i.state.loading = true;
i.setState(i.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.loading = false;
this.setState(this.state);
return;
} else if (
- res.op == UserOperation.EditPrivateMessage ||
- res.op == UserOperation.DeletePrivateMessage ||
- res.op == UserOperation.MarkPrivateMessageAsRead
+ op == UserOperation.EditPrivateMessage ||
+ op == UserOperation.DeletePrivateMessage ||
+ op == UserOperation.MarkPrivateMessageAsRead
) {
- let data = res.data as PrivateMessageResponse;
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
this.state.loading = false;
- this.props.onEdit(data.message);
- } else if (res.op == UserOperation.CreatePrivateMessage) {
- let data = res.data as PrivateMessageResponse;
+ this.props.onEdit(data.private_message_view);
+ } else if (op == UserOperation.CreatePrivateMessage) {
+ let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
this.state.loading = false;
- this.props.onCreate(data.message);
+ this.props.onCreate(data.private_message_view);
this.setState(this.state);
}
}
import { Component, linkEvent } from 'inferno';
import {
- PrivateMessage as PrivateMessageI,
- DeletePrivateMessageForm,
- MarkPrivateMessageAsReadForm,
- UserView,
+ PrivateMessageView,
+ DeletePrivateMessage,
+ MarkPrivateMessageAsRead,
+ UserSafe,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
-import { mdToHtml, toast } from '../utils';
+import { authField, mdToHtml, toast, wsClient } from '../utils';
import { MomentTime } from './moment-time';
import { PrivateMessageForm } from './private-message-form';
import { UserListing } from './user-listing';
}
interface PrivateMessageProps {
- privateMessage: PrivateMessageI;
+ private_message_view: PrivateMessageView;
}
export class PrivateMessage extends Component<
get mine(): boolean {
return (
UserService.Instance.user &&
- UserService.Instance.user.id == this.props.privateMessage.creator_id
+ UserService.Instance.user.id == this.props.private_message_view.creator.id
);
}
render() {
- let message = this.props.privateMessage;
- let userOther: UserView = this.mine
- ? {
- name: message.recipient_name,
- preferred_username: message.recipient_preferred_username,
- id: message.recipient_id,
- avatar: message.recipient_avatar,
- local: message.recipient_local,
- actor_id: message.recipient_actor_id,
- published: message.published,
- number_of_posts: 0,
- post_score: 0,
- number_of_comments: 0,
- comment_score: 0,
- banned: false,
- }
- : {
- name: message.creator_name,
- preferred_username: message.creator_preferred_username,
- id: message.creator_id,
- avatar: message.creator_avatar,
- local: message.creator_local,
- actor_id: message.creator_actor_id,
- published: message.published,
- number_of_posts: 0,
- post_score: 0,
- number_of_comments: 0,
- comment_score: 0,
- banned: false,
- };
+ let message_view = this.props.private_message_view;
+ // TODO check this again
+ let userOther: UserSafe = this.mine
+ ? message_view.recipient
+ : message_view.creator;
return (
<div class="border-top border-light">
</li>
<li className="list-inline-item">
<span>
- <MomentTime data={message} />
+ <MomentTime data={message_view.private_message} />
</span>
</li>
<li className="list-inline-item">
{this.state.showEdit && (
<PrivateMessageForm
recipient={userOther}
- privateMessage={message}
+ privateMessage={message_view}
onEdit={this.handlePrivateMessageEdit}
onCreate={this.handlePrivateMessageCreate}
onCancel={this.handleReplyCancel}
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={
- message.read
+ message_view.private_message.read
? i18n.t('mark_as_unread')
: i18n.t('mark_as_read')
}
>
<svg
class={`icon icon-inline ${
- message.read && 'text-success'
+ message_view.private_message.read && 'text-success'
}`}
>
<use xlinkHref="#icon-check"></use>
class="btn btn-link btn-animate text-muted"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
- !message.deleted
+ !message_view.private_message.deleted
? i18n.t('delete')
: i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
- message.deleted && 'text-danger'
+ message_view.private_message.deleted &&
+ 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
}
get messageUnlessRemoved(): string {
- let message = this.props.privateMessage;
+ let message = this.props.private_message_view.private_message;
return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
}
}
handleDeleteClick(i: PrivateMessage) {
- let form: DeletePrivateMessageForm = {
- edit_id: i.props.privateMessage.id,
- deleted: !i.props.privateMessage.deleted,
+ let form: DeletePrivateMessage = {
+ edit_id: i.props.private_message_view.private_message.id,
+ deleted: !i.props.private_message_view.private_message.deleted,
+ auth: authField(),
};
- WebSocketService.Instance.deletePrivateMessage(form);
+ WebSocketService.Instance.send(wsClient.deletePrivateMessage(form));
}
handleReplyCancel() {
}
handleMarkRead(i: PrivateMessage) {
- let form: MarkPrivateMessageAsReadForm = {
- edit_id: i.props.privateMessage.id,
- read: !i.props.privateMessage.read,
+ let form: MarkPrivateMessageAsRead = {
+ edit_id: i.props.private_message_view.private_message.id,
+ read: !i.props.private_message_view.private_message.read,
+ auth: authField(),
};
- WebSocketService.Instance.markPrivateMessageAsRead(form);
+ WebSocketService.Instance.send(wsClient.markPrivateMessageAsRead(form));
}
handleMessageCollapse(i: PrivateMessage) {
this.setState(this.state);
}
- handlePrivateMessageCreate(message: PrivateMessageI) {
+ handlePrivateMessageCreate(message: PrivateMessageView) {
if (
UserService.Instance.user &&
- message.creator_id == UserService.Instance.user.id
+ message.creator.id == UserService.Instance.user.id
) {
this.state.showReply = false;
this.setState(this.state);
import { Subscription } from 'rxjs';
import {
UserOperation,
- Post,
- Comment,
- Community,
- UserView,
+ PostView,
+ CommentView,
+ CommunityView,
+ UserViewSafe,
SortType,
- SearchForm,
+ Search as SearchForm,
SearchResponse,
SearchType,
PostResponse,
CommentResponse,
- WebSocketJsonResponse,
Site,
} from 'lemmy-js-client';
import { WebSocketService } from '../services';
commentsToFlatNodes,
setIsoData,
wsSubscribe,
- setAuth,
+ wsUserOp,
+ wsClient,
+ authField,
+ setOptionalAuth,
} from '../utils';
import { PostListing } from './post-listing';
import { HtmlTags } from './html-tags';
users: [],
},
loading: false,
- site: this.isoData.site.site,
+ site: this.isoData.site_res.site_view.site,
};
static getSearchQueryFromProps(q: string): string {
page: this.getPageFromProps(pathSplit[9]),
limit: fetchLimit,
};
- setAuth(form, req.auth);
+ setOptionalAuth(form, req.auth);
if (form.q != '') {
promises.push(req.client.search(form));
all() {
let combined: {
type_: string;
- data: Comment | Post | Community | UserView;
+ data: CommentView | PostView | CommunityView | UserViewSafe;
+ published: string;
}[] = [];
let comments = this.state.searchResponse.comments.map(e => {
- return { type_: 'comments', data: e };
+ return { type_: 'comments', data: e, published: e.comment.published };
});
let posts = this.state.searchResponse.posts.map(e => {
- return { type_: 'posts', data: e };
+ return { type_: 'posts', data: e, published: e.post.published };
});
let communities = this.state.searchResponse.communities.map(e => {
- return { type_: 'communities', data: e };
+ return {
+ type_: 'communities',
+ data: e,
+ published: e.community.published,
+ };
});
let users = this.state.searchResponse.users.map(e => {
- return { type_: 'users', data: e };
+ return { type_: 'users', data: e, published: e.user.published };
});
combined.push(...comments);
// Sort it
if (this.state.sort == SortType.New) {
- combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
+ combined.sort((a, b) => b.published.localeCompare(a.published));
} else {
combined.sort(
(a, b) =>
- ((b.data as Comment | Post).score |
- (b.data as Community).number_of_subscribers |
- (b.data as UserView).comment_score) -
- ((a.data as Comment | Post).score |
- (a.data as Community).number_of_subscribers |
- (a.data as UserView).comment_score)
+ ((b.data as CommentView | PostView).counts.score |
+ (b.data as CommunityView).counts.subscribers |
+ (b.data as UserViewSafe).counts.comment_score) -
+ ((a.data as CommentView | PostView).counts.score |
+ (a.data as CommunityView).counts.subscribers |
+ (a.data as UserViewSafe).counts.comment_score)
);
}
<div class="col-12">
{i.type_ == 'posts' && (
<PostListing
- key={(i.data as Post).id}
- post={i.data as Post}
+ key={(i.data as PostView).post.id}
+ post_view={i.data as PostView}
showCommunity
enableDownvotes={this.state.site.enable_downvotes}
enableNsfw={this.state.site.enable_nsfw}
)}
{i.type_ == 'comments' && (
<CommentNodes
- key={(i.data as Comment).id}
- nodes={[{ comment: i.data as Comment }]}
+ key={(i.data as CommentView).comment.id}
+ nodes={[{ comment_view: i.data as CommentView }]}
locked
noIndent
enableDownvotes={this.state.site.enable_downvotes}
/>
)}
{i.type_ == 'communities' && (
- <div>{this.communityListing(i.data as Community)}</div>
+ <div>{this.communityListing(i.data as CommunityView)}</div>
)}
{i.type_ == 'users' && (
- <div>{this.userListing(i.data as UserView)}</div>
+ <div>{this.userListing(i.data as UserViewSafe)}</div>
)}
</div>
</div>
<div class="row">
<div class="col-12">
<PostListing
- post={post}
+ post_view={post}
showCommunity
enableDownvotes={this.state.site.enable_downvotes}
enableNsfw={this.state.site.enable_nsfw}
);
}
- communityListing(community: Community) {
+ communityListing(community_view: CommunityView) {
return (
<>
<span>
- <CommunityLink community={community} />
+ <CommunityLink community={community_view.community} />
</span>
- <span>{` - ${community.title} -
+ <span>{` - ${community_view.community.title} -
${i18n.t('number_of_subscribers', {
- count: community.number_of_subscribers,
+ count: community_view.counts.subscribers,
})}
`}</span>
</>
);
}
- userListing(user: UserView) {
+ userListing(user_view: UserViewSafe) {
return [
<span>
- <UserListing user={user} showApubName />
+ <UserListing user={user_view.user} showApubName />
</span>,
<span>{` - ${i18n.t('number_of_comments', {
- count: user.number_of_comments,
+ count: user_view.counts.comment_count,
})}`}</span>,
];
}
sort: this.state.sort,
page: this.state.page,
limit: fetchLimit,
+ auth: authField(false),
};
if (this.state.q != '') {
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
}
}
);
}
- parseMessage(msg: WebSocketJsonResponse) {
+ parseMessage(msg: any) {
console.log(msg);
- let res = wsJsonToRes(msg);
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
return;
- } else if (res.op == UserOperation.Search) {
- let data = res.data as SearchResponse;
+ } else if (op == UserOperation.Search) {
+ let data = wsJsonToRes<SearchResponse>(msg).data;
this.state.searchResponse = data;
this.state.loading = false;
window.scrollTo(0, 0);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateCommentLike) {
- let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.searchResponse.comments);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(
+ data.comment_view,
+ this.state.searchResponse.comments
+ );
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePostLike) {
- let data = res.data as PostResponse;
- createPostLikeFindRes(data, this.state.searchResponse.posts);
+ } else if (op == UserOperation.CreatePostLike) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ createPostLikeFindRes(data.post_view, this.state.searchResponse.posts);
this.setState(this.state);
}
}
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
-import {
- RegisterForm,
- LoginResponse,
- UserOperation,
- WebSocketJsonResponse,
-} from 'lemmy-js-client';
+import { Register, LoginResponse, UserOperation } from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
-import { wsJsonToRes, toast } from '../utils';
+import { wsUserOp, wsJsonToRes, toast, wsClient } from '../utils';
import { SiteForm } from './site-form';
import { i18n } from '../i18next';
interface State {
- userForm: RegisterForm;
+ userForm: Register;
doneRegisteringUser: boolean;
userLoading: boolean;
}
i.state.userLoading = true;
i.setState(i.state);
event.preventDefault();
- WebSocketService.Instance.register(i.state.userForm);
+ WebSocketService.Instance.send(wsClient.register(i.state.userForm));
}
handleRegisterUsernameChange(i: Setup, event: any) {
i.setState(i.state);
}
- parseMessage(msg: WebSocketJsonResponse) {
- let res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
this.state.userLoading = false;
this.setState(this.state);
return;
- } else if (res.op == UserOperation.Register) {
- let data = res.data as LoginResponse;
+ } else if (op == UserOperation.Register) {
+ let data = wsJsonToRes<LoginResponse>(msg).data;
this.state.userLoading = false;
this.state.doneRegisteringUser = true;
UserService.Instance.login(data);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateSite) {
+ } else if (op == UserOperation.CreateSite) {
window.location.href = '/';
}
}
import { Component, linkEvent } from 'inferno';
import { Link } from 'inferno-router';
import {
- Community,
- CommunityUser,
- FollowCommunityForm,
- DeleteCommunityForm,
- RemoveCommunityForm,
- UserView,
- AddModToCommunityForm,
+ CommunityView,
+ CommunityModeratorView,
+ FollowCommunity,
+ DeleteCommunity,
+ RemoveCommunity,
+ UserViewSafe,
+ AddModToCommunity,
Category,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
-import { mdToHtml, getUnixTime } from '../utils';
+import { mdToHtml, getUnixTime, wsClient, authField } from '../utils';
import { CommunityForm } from './community-form';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { i18n } from '../i18next';
interface SidebarProps {
- community: Community;
+ community_view: CommunityView;
categories: Category[];
- moderators: CommunityUser[];
- admins: UserView[];
+ moderators: CommunityModeratorView[];
+ admins: UserViewSafe[];
online: number;
enableNsfw: boolean;
showIcon?: boolean;
) : (
<CommunityForm
categories={this.props.categories}
- community={this.props.community}
+ community_view={this.props.community_view}
onEdit={this.handleEditCommunity}
onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw}
}
communityTitle() {
- let community = this.props.community;
+ let community = this.props.community_view.community;
+ let subscribed = this.props.community_view.subscribed;
return (
<div>
<h5 className="mb-0">
<BannerIconHeader icon={community.icon} banner={community.banner} />
)}
<span class="mr-2">{community.title}</span>
- {community.subscribed && (
+ {subscribed && (
<a
class="btn btn-secondary btn-sm mr-2"
href="#"
}
badges() {
- let community = this.props.community;
+ let community_view = this.props.community_view;
return (
<ul class="my-1 list-inline">
<li className="list-inline-item badge badge-secondary">
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_subscribers', {
- count: community.number_of_subscribers,
+ count: community_view.counts.subscribers,
})}
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_posts', {
- count: community.number_of_posts,
+ count: community_view.counts.posts,
})}
</li>
<li className="list-inline-item badge badge-secondary">
{i18n.t('number_of_comments', {
- count: community.number_of_comments,
+ count: community_view.counts.comments,
})}
</li>
<li className="list-inline-item">
<Link className="badge badge-secondary" to="/communities">
- {community.category_name}
+ {community_view.category.name}
</Link>
</li>
<li className="list-inline-item">
<Link
className="badge badge-secondary"
- to={`/modlog/community/${this.props.community.id}`}
+ to={`/modlog/community/${this.props.community_view.community.id}`}
>
{i18n.t('modlog')}
</Link>
<li class="list-inline-item">{i18n.t('mods')}: </li>
{this.props.moderators.map(mod => (
<li class="list-inline-item">
- <UserListing
- user={{
- name: mod.user_name,
- preferred_username: mod.user_preferred_username,
- avatar: mod.avatar,
- id: mod.user_id,
- local: mod.user_local,
- actor_id: mod.user_actor_id,
- }}
- />
+ <UserListing user={mod.moderator} />
</li>
))}
</ul>
}
createPost() {
- let community = this.props.community;
+ let community_view = this.props.community_view;
return (
- community.subscribed && (
+ community_view.subscribed && (
<Link
className={`btn btn-secondary btn-block mb-2 ${
- community.deleted || community.removed ? 'no-click' : ''
+ community_view.community.deleted || community_view.community.removed
+ ? 'no-click'
+ : ''
}`}
- to={`/create_post?community_id=${community.id}`}
+ to={`/create_post?community_id=${community_view.community.id}`}
>
{i18n.t('create_a_post')}
</Link>
}
subscribe() {
- let community = this.props.community;
+ let community_view = this.props.community_view;
return (
<div class="mb-2">
- {!community.subscribed && (
+ {!community_view.subscribed && (
<a
class="btn btn-secondary btn-block"
href="#"
- onClick={linkEvent(community.id, this.handleSubscribe)}
+ onClick={linkEvent(
+ community_view.community.id,
+ this.handleSubscribe
+ )}
>
{i18n.t('subscribe')}
</a>
}
description() {
- let community = this.props.community;
+ let description = this.props.community_view.community.description;
return (
- community.description && (
+ description && (
<div
className="md-div"
- dangerouslySetInnerHTML={mdToHtml(community.description)}
+ dangerouslySetInnerHTML={mdToHtml(description)}
/>
)
);
}
adminButtons() {
- let community = this.props.community;
+ let community_view = this.props.community_view;
return (
<>
<ul class="list-inline mb-1 text-muted font-weight-bold">
class="pointer"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
- !community.deleted ? i18n.t('delete') : i18n.t('restore')
+ !community_view.community.deleted
+ ? i18n.t('delete')
+ : i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
- community.deleted && 'text-danger'
+ community_view.community.deleted && 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
)}
{this.canAdmin && (
<li className="list-inline-item">
- {!this.props.community.removed ? (
+ {!this.props.community_view.community.removed ? (
<span
class="pointer"
onClick={linkEvent(this, this.handleModRemoveShow)}
handleDeleteClick(i: Sidebar, event: any) {
event.preventDefault();
- let deleteForm: DeleteCommunityForm = {
- edit_id: i.props.community.id,
- deleted: !i.props.community.deleted,
+ let deleteForm: DeleteCommunity = {
+ edit_id: i.props.community_view.community.id,
+ deleted: !i.props.community_view.community.deleted,
+ auth: authField(),
};
- WebSocketService.Instance.deleteCommunity(deleteForm);
+ WebSocketService.Instance.send(wsClient.deleteCommunity(deleteForm));
}
handleShowConfirmLeaveModTeamClick(i: Sidebar) {
}
handleLeaveModTeamClick(i: Sidebar) {
- let form: AddModToCommunityForm = {
+ let form: AddModToCommunity = {
user_id: UserService.Instance.user.id,
- community_id: i.props.community.id,
+ community_id: i.props.community_view.community.id,
added: false,
+ auth: authField(),
};
- WebSocketService.Instance.addModToCommunity(form);
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
i.state.showConfirmLeaveModTeam = false;
i.setState(i.state);
}
handleUnsubscribe(communityId: number, event: any) {
event.preventDefault();
- let form: FollowCommunityForm = {
+ let form: FollowCommunity = {
community_id: communityId,
follow: false,
+ auth: authField(),
};
- WebSocketService.Instance.followCommunity(form);
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
}
handleSubscribe(communityId: number, event: any) {
event.preventDefault();
- let form: FollowCommunityForm = {
+ let form: FollowCommunity = {
community_id: communityId,
follow: true,
+ auth: authField(),
};
- WebSocketService.Instance.followCommunity(form);
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
}
private get amCreator(): boolean {
- return this.props.community.creator_id == UserService.Instance.user.id;
+ return this.props.community_view.creator.id == UserService.Instance.user.id;
}
get canMod(): boolean {
return (
UserService.Instance.user &&
this.props.moderators
- .map(m => m.user_id)
+ .map(m => m.moderator.id)
.includes(UserService.Instance.user.id)
);
}
get canAdmin(): boolean {
return (
UserService.Instance.user &&
- this.props.admins.map(a => a.id).includes(UserService.Instance.user.id)
+ this.props.admins
+ .map(a => a.user.id)
+ .includes(UserService.Instance.user.id)
);
}
handleModRemoveSubmit(i: Sidebar, event: any) {
event.preventDefault();
- let removeForm: RemoveCommunityForm = {
- edit_id: i.props.community.id,
- removed: !i.props.community.removed,
+ let removeForm: RemoveCommunity = {
+ edit_id: i.props.community_view.community.id,
+ removed: !i.props.community_view.community.removed,
reason: i.state.removeReason,
expires: getUnixTime(i.state.removeExpires),
+ auth: authField(),
};
- WebSocketService.Instance.removeCommunity(removeForm);
+ WebSocketService.Instance.send(wsClient.removeCommunity(removeForm));
i.state.showRemoveDialog = false;
i.setState(i.state);
import { Prompt } from 'inferno-router';
import { MarkdownTextArea } from './markdown-textarea';
import { ImageUploadForm } from './image-upload-form';
-import { Site, SiteForm as SiteFormI } from 'lemmy-js-client';
+import { Site, EditSite } from 'lemmy-js-client';
import { WebSocketService } from '../services';
-import { capitalizeFirstLetter, randomStr } from '../utils';
+import {
+ authField,
+ capitalizeFirstLetter,
+ randomStr,
+ wsClient,
+} from '../utils';
import { i18n } from '../i18next';
interface SiteFormProps {
}
interface SiteFormState {
- siteForm: SiteFormI;
+ siteForm: EditSite;
loading: boolean;
}
name: null,
icon: null,
banner: null,
+ auth: authField(),
},
loading: false,
};
enable_nsfw: this.props.site.enable_nsfw,
icon: this.props.site.icon,
banner: this.props.site.banner,
+ auth: authField(),
};
}
}
event.preventDefault();
i.state.loading = true;
if (i.props.site) {
- WebSocketService.Instance.editSite(i.state.siteForm);
+ WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
} else {
- WebSocketService.Instance.createSite(i.state.siteForm);
+ WebSocketService.Instance.send(wsClient.createSite(i.state.siteForm));
}
i.setState(i.state);
}
-import { User } from 'lemmy-js-client';
+import { User_ } from 'lemmy-js-client';
import { Helmet } from 'inferno-helmet';
import { Component } from 'inferno';
interface Props {
- user: User | undefined;
+ user: User_ | undefined;
}
export class Theme extends Component<Props> {
import { Component, linkEvent } from 'inferno';
import { i18n } from '../i18next';
-import { Post, Comment, SortType, UserDetailsResponse } from 'lemmy-js-client';
+import {
+ PostView,
+ CommentView,
+ SortType,
+ GetUserDetailsResponse,
+ UserViewSafe,
+} from 'lemmy-js-client';
import { UserDetailsView } from '../interfaces';
import { commentsToFlatNodes, setupTippy } from '../utils';
import { PostListing } from './post-listing';
import { CommentNodes } from './comment-nodes';
interface UserDetailsProps {
- userRes: UserDetailsResponse;
+ userRes: GetUserDetailsResponse;
+ admins: UserViewSafe[];
page: number;
limit: number;
sort: SortType;
interface UserDetailsState {}
+enum ItemEnum {
+ Comment,
+ Post,
+}
+type ItemType = {
+ id: number;
+ type_: ItemEnum;
+ view: CommentView | PostView;
+ published: string;
+ score: number;
+};
+
export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
constructor(props: any, context: any) {
super(props, context);
}
}
+ renderItemType(i: ItemType) {
+ switch (i.type_) {
+ case ItemEnum.Comment:
+ let c = i.view as CommentView;
+ return (
+ <CommentNodes
+ key={i.id}
+ nodes={[{ comment_view: c }]}
+ admins={this.props.admins}
+ noBorder
+ noIndent
+ showCommunity
+ showContext
+ enableDownvotes={this.props.enableDownvotes}
+ />
+ );
+ case ItemEnum.Post:
+ let p = i.view as PostView;
+ return (
+ <PostListing
+ key={i.id}
+ post_view={p}
+ admins={this.props.admins}
+ showCommunity
+ enableDownvotes={this.props.enableDownvotes}
+ enableNsfw={this.props.enableNsfw}
+ />
+ );
+ default:
+ return <div />;
+ }
+ }
+
overview() {
- const comments = this.props.userRes.comments.map((c: Comment) => {
- return { type: 'comments', data: c };
- });
- const posts = this.props.userRes.posts.map((p: Post) => {
- return { type: 'posts', data: p };
- });
-
- const combined: { type: string; data: Comment | Post }[] = [
- ...comments,
- ...posts,
- ];
+ let id = 0;
+ let comments: ItemType[] = this.props.userRes.comments.map(r => ({
+ id: id++,
+ type_: ItemEnum.Comment,
+ view: r,
+ published: r.comment.published,
+ score: r.counts.score,
+ }));
+ let posts: ItemType[] = this.props.userRes.posts.map(r => ({
+ id: id++,
+ type_: ItemEnum.Post,
+ view: r,
+ published: r.post.published,
+ score: r.counts.score,
+ }));
+
+ let combined = [...comments, ...posts];
// Sort it
if (this.props.sort === SortType.New) {
- combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
+ combined.sort((a, b) => b.published.localeCompare(a.published));
} else {
- combined.sort((a, b) => b.data.score - a.data.score);
+ combined.sort((a, b) => b.score - a.score);
}
return (
<div>
- {combined.map(i => (
- <>
- <div>
- {i.type === 'posts' ? (
- <PostListing
- key={(i.data as Post).id}
- post={i.data as Post}
- admins={this.props.userRes.admins}
- showCommunity
- enableDownvotes={this.props.enableDownvotes}
- enableNsfw={this.props.enableNsfw}
- />
- ) : (
- <CommentNodes
- key={(i.data as Comment).id}
- nodes={[{ comment: i.data as Comment }]}
- admins={this.props.userRes.admins}
- noBorder
- noIndent
- showCommunity
- showContext
- enableDownvotes={this.props.enableDownvotes}
- />
- )}
- </div>
- <hr class="my-3" />
- </>
- ))}
+ {combined.map(i => [this.renderItemType(i), <hr class="my-3" />])}
</div>
);
}
<div>
<CommentNodes
nodes={commentsToFlatNodes(this.props.userRes.comments)}
- admins={this.props.userRes.admins}
+ admins={this.props.admins}
noIndent
showCommunity
showContext
{this.props.userRes.posts.map(post => (
<>
<PostListing
- post={post}
- admins={this.props.userRes.admins}
+ post_view={post}
+ admins={this.props.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
import { Component } from 'inferno';
import { Link } from 'inferno-router';
-import { UserView } from 'lemmy-js-client';
+import { UserSafe } from 'lemmy-js-client';
import { showAvatars, hostname, isCakeDay } from '../utils';
import { CakeDay } from './cake-day';
import { PictrsImage } from './pictrs-image';
-export interface UserOther {
- name: string;
- preferred_username?: string;
- id?: number; // Necessary if its federated
- avatar?: string;
- local?: boolean;
- actor_id?: string;
- published?: string;
-}
-
interface UserListingProps {
- user: UserView | UserOther;
+ user: UserSafe;
realLink?: boolean;
useApubName?: boolean;
muted?: boolean;
UserOperation,
SortType,
ListingType,
- UserSettingsForm,
+ SaveUserSettings,
LoginResponse,
- DeleteAccountForm,
- WebSocketJsonResponse,
+ DeleteAccount,
GetSiteResponse,
- UserDetailsResponse,
+ GetUserDetailsResponse,
AddAdminResponse,
- GetUserDetailsForm,
+ GetUserDetails,
CommentResponse,
PostResponse,
BanUserResponse,
editCommentRes,
saveCommentRes,
createPostLikeFindRes,
- setAuth,
previewLines,
editPostFindRes,
+ wsUserOp,
+ wsClient,
+ authField,
+ setOptionalAuth,
} from '../utils';
import { UserListing } from './user-listing';
import { HtmlTags } from './html-tags';
import { CommunityLink } from './community-link';
interface UserState {
- userRes: UserDetailsResponse;
+ userRes: GetUserDetailsResponse;
userId: number;
userName: string;
view: UserDetailsView;
sort: SortType;
page: number;
loading: boolean;
- userSettingsForm: UserSettingsForm;
+ userSettingsForm: SaveUserSettings;
userSettingsLoading: boolean;
deleteAccountLoading: boolean;
deleteAccountShowConfirm: boolean;
- deleteAccountForm: DeleteAccountForm;
+ deleteAccountForm: DeleteAccount;
siteRes: GetSiteResponse;
}
lang: null,
show_avatars: null,
send_notifications_to_email: null,
- auth: null,
bio: null,
preferred_username: null,
+ auth: authField(false),
},
userSettingsLoading: null,
deleteAccountLoading: null,
deleteAccountShowConfirm: false,
deleteAccountForm: {
password: null,
+ auth: authField(false),
},
- siteRes: this.isoData.site,
+ siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
this.state.userRes = this.isoData.routeData[0];
+ this.state.userRes.user_view =
+ this.state.userRes.user_view || this.state.userRes.user_view_dangerous;
this.setUserInfo();
this.state.loading = false;
} else {
}
fetchUserData() {
- let form: GetUserDetailsForm = {
+ let form: GetUserDetails = {
user_id: this.state.userId,
username: this.state.userName,
sort: this.state.sort,
saved_only: this.state.view === UserDetailsView.Saved,
page: this.state.page,
limit: fetchLimit,
+ auth: authField(false),
};
- WebSocketService.Instance.getUserDetails(form);
+ WebSocketService.Instance.send(wsClient.getUserDetails(form));
}
get isCurrentUser() {
return (
UserService.Instance.user &&
- UserService.Instance.user.id == this.state.userRes.user.id
+ UserService.Instance.user.id == this.state.userRes.user_view.user.id
);
}
let sort = this.getSortTypeFromProps(pathSplit[6]);
let page = this.getPageFromProps(Number(pathSplit[8]));
- let form: GetUserDetailsForm = {
+ let form: GetUserDetails = {
sort,
saved_only: view === UserDetailsView.Saved,
page,
limit: fetchLimit,
};
+ setOptionalAuth(form, req.auth);
this.setIdOrName(form, user_id, username);
- setAuth(form, req.auth);
promises.push(req.client.getUserDetails(form));
return promises;
}
}
get documentTitle(): string {
- return `@${this.state.userRes.user.name} - ${this.state.siteRes.site.name}`;
+ return `@${this.state.userRes.user_view.user.name} - ${this.state.siteRes.site_view.site.name}`;
}
get bioTag(): string {
- return this.state.userRes.user.bio
- ? previewLines(this.state.userRes.user.bio)
+ return this.state.userRes.user_view.user.bio
+ ? previewLines(this.state.userRes.user_view.user.bio)
: undefined;
}
title={this.documentTitle}
path={this.context.router.route.match.url}
description={this.bioTag}
- image={this.state.userRes.user.avatar}
+ image={this.state.userRes.user_view.user.avatar}
/>
{this.userInfo()}
<hr />
{!this.state.loading && this.selects()}
<UserDetails
userRes={this.state.userRes}
+ admins={this.state.siteRes.admins}
sort={this.state.sort}
page={this.state.page}
limit={fetchLimit}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
+ enableDownvotes={
+ this.state.siteRes.site_view.site.enable_downvotes
+ }
+ enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
view={this.state.view}
onPageChange={this.handlePageChange}
/>
}
userInfo() {
- let user = this.state.userRes.user;
+ let uv = this.state.userRes?.user_view;
return (
<div>
- <BannerIconHeader banner={user.banner} icon={user.avatar} />
+ <BannerIconHeader banner={uv.user.banner} icon={uv.user.avatar} />
<div class="mb-3">
<div class="">
<div class="mb-0 d-flex flex-wrap">
<div>
- {user.preferred_username && (
- <h5 class="mb-0">{user.preferred_username}</h5>
+ {uv.user.preferred_username && (
+ <h5 class="mb-0">{uv.user.preferred_username}</h5>
)}
<ul class="list-inline mb-2">
<li className="list-inline-item">
<UserListing
- user={user}
+ user={uv.user}
realLink
useApubName
muted
hideAvatar
/>
</li>
- {user.banned && (
+ {uv.user.banned && (
<li className="list-inline-item badge badge-danger">
{i18n.t('banned')}
</li>
<>
<a
className={`d-flex align-self-start btn btn-secondary mr-2 ${
- !user.matrix_user_id && 'invisible'
+ !uv.user.matrix_user_id && 'invisible'
}`}
target="_blank"
rel="noopener"
- href={`https://matrix.to/#/${user.matrix_user_id}`}
+ href={`https://matrix.to/#/${uv.user.matrix_user_id}`}
>
{i18n.t('send_secure_message')}
</a>
<Link
className={'d-flex align-self-start btn btn-secondary'}
- to={`/create_private_message/recipient/${user.id}`}
+ to={`/create_private_message/recipient/${uv.user.id}`}
>
{i18n.t('send_message')}
</Link>
</>
)}
</div>
- {user.bio && (
+ {uv.user.bio && (
<div className="d-flex align-items-center mb-2">
<div
className="md-div"
- dangerouslySetInnerHTML={mdToHtml(user.bio)}
+ dangerouslySetInnerHTML={mdToHtml(uv.user.bio)}
/>
</div>
)}
<div>
<ul class="list-inline mb-2">
<li className="list-inline-item badge badge-light">
- {i18n.t('number_of_posts', { count: user.number_of_posts })}
+ {i18n.t('number_of_posts', { count: uv.counts.post_count })}
</li>
<li className="list-inline-item badge badge-light">
{i18n.t('number_of_comments', {
- count: user.number_of_comments,
+ count: uv.counts.comment_count,
})}
</li>
</ul>
</div>
<div class="text-muted">
- {i18n.t('joined')} <MomentTime data={user} showAgo />
+ {i18n.t('joined')} <MomentTime data={uv.user} showAgo />
</div>
<div className="d-flex align-items-center text-muted mb-2">
<svg class="icon">
</svg>
<span className="ml-2">
{i18n.t('cake_day_title')}{' '}
- {moment.utc(user.published).local().format('MMM DD, YYYY')}
+ {moment.utc(uv.user.published).local().format('MMM DD, YYYY')}
</span>
</div>
</div>
/>
</div>
</div>
- {this.state.siteRes.site.enable_nsfw && (
+ {this.state.siteRes.site_view.site.enable_nsfw && (
<div class="form-group">
<div class="form-check">
<input
<div class="card-body">
<h5>{i18n.t('moderates')}</h5>
<ul class="list-unstyled mb-0">
- {this.state.userRes.moderates.map(community => (
+ {this.state.userRes.moderates.map(cmv => (
<li>
- <CommunityLink
- community={{
- name: community.community_name,
- id: community.community_id,
- local: community.community_local,
- actor_id: community.community_actor_id,
- icon: community.community_icon,
- }}
- />
+ <CommunityLink community={cmv.community} />
</li>
))}
</ul>
<div class="card-body">
<h5>{i18n.t('subscribed')}</h5>
<ul class="list-unstyled mb-0">
- {this.state.userRes.follows.map(community => (
+ {this.state.userRes.follows.map(cfv => (
<li>
- <CommunityLink
- community={{
- name: community.community_name,
- id: community.community_id,
- local: community.community_local,
- actor_id: community.community_actor_id,
- icon: community.community_icon,
- }}
- />
+ <CommunityLink community={cfv.community} />
</li>
))}
</ul>
i.state.userSettingsForm.matrix_user_id = event.target.value;
if (
i.state.userSettingsForm.matrix_user_id == '' &&
- !i.state.userRes.user.matrix_user_id
+ !i.state.userRes.user_view.user.matrix_user_id
) {
i.state.userSettingsForm.matrix_user_id = undefined;
}
i.state.userSettingsLoading = true;
i.setState(i.state);
- WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
+ WebSocketService.Instance.send(
+ wsClient.saveUserSettings(i.state.userSettingsForm)
+ );
}
handleDeleteAccountShowConfirmToggle(i: User, event: any) {
i.state.deleteAccountLoading = true;
i.setState(i.state);
- WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
+ WebSocketService.Instance.send(
+ wsClient.deleteAccount(i.state.deleteAccountForm)
+ );
i.handleLogoutClick(i);
}
}
}
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- const res = wsJsonToRes(msg);
+ parseMessage(msg: any) {
+ let op = wsUserOp(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
if (msg.error == 'couldnt_find_that_username_or_email') {
return;
} else if (msg.reconnect) {
this.fetchUserData();
- } else if (res.op == UserOperation.GetUserDetails) {
+ } else if (op == UserOperation.GetUserDetails) {
// Since the UserDetails contains posts/comments as well as some general user info we listen here as well
// and set the parent state if it is not set or differs
// TODO this might need to get abstracted
- const data = res.data as UserDetailsResponse;
+ let data = wsJsonToRes<GetUserDetailsResponse>(msg).data;
this.state.userRes = data;
+ this.state.userRes.user_view =
+ this.state.userRes.user_view || this.state.userRes.user_view_dangerous;
this.setUserInfo();
this.state.loading = false;
this.setState(this.state);
- } else if (res.op == UserOperation.SaveUserSettings) {
- const data = res.data as LoginResponse;
+ } else if (op == UserOperation.SaveUserSettings) {
+ let data = wsJsonToRes<LoginResponse>(msg).data;
UserService.Instance.login(data);
- this.state.userRes.user.bio = this.state.userSettingsForm.bio;
- this.state.userRes.user.preferred_username = this.state.userSettingsForm.preferred_username;
- this.state.userRes.user.banner = this.state.userSettingsForm.banner;
- this.state.userRes.user.avatar = this.state.userSettingsForm.avatar;
+ this.state.userRes.user_view.user.bio = this.state.userSettingsForm.bio;
+ this.state.userRes.user_view.user.preferred_username = this.state.userSettingsForm.preferred_username;
+ this.state.userRes.user_view.user.banner = this.state.userSettingsForm.banner;
+ this.state.userRes.user_view.user.avatar = this.state.userSettingsForm.avatar;
this.state.userSettingsLoading = false;
this.setState(this.state);
window.scrollTo(0, 0);
- } else if (res.op == UserOperation.DeleteAccount) {
+ } else if (op == UserOperation.DeleteAccount) {
this.setState({
deleteAccountLoading: false,
deleteAccountShowConfirm: false,
});
this.context.router.history.push('/');
- } else if (res.op == UserOperation.AddAdmin) {
- const data = res.data as AddAdminResponse;
+ } else if (op == UserOperation.AddAdmin) {
+ let data = wsJsonToRes<AddAdminResponse>(msg).data;
this.state.siteRes.admins = data.admins;
this.setState(this.state);
- } else if (res.op == UserOperation.CreateCommentLike) {
- const data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.userRes.comments);
+ } else if (op == UserOperation.CreateCommentLike) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ createCommentLikeRes(data.comment_view, this.state.userRes.comments);
this.setState(this.state);
} else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
+ op == UserOperation.EditComment ||
+ op == UserOperation.DeleteComment ||
+ op == UserOperation.RemoveComment
) {
- const data = res.data as CommentResponse;
- editCommentRes(data, this.state.userRes.comments);
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ editCommentRes(data.comment_view, this.state.userRes.comments);
this.setState(this.state);
- } else if (res.op == UserOperation.CreateComment) {
- const data = res.data as CommentResponse;
+ } else if (op == UserOperation.CreateComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
if (
UserService.Instance.user &&
- data.comment.creator_id == UserService.Instance.user.id
+ data.comment_view.creator.id == UserService.Instance.user.id
) {
toast(i18n.t('reply_sent'));
}
- } else if (res.op == UserOperation.SaveComment) {
- const data = res.data as CommentResponse;
- saveCommentRes(data, this.state.userRes.comments);
+ } else if (op == UserOperation.SaveComment) {
+ let data = wsJsonToRes<CommentResponse>(msg).data;
+ saveCommentRes(data.comment_view, this.state.userRes.comments);
this.setState(this.state);
} else if (
- res.op == UserOperation.EditPost ||
- res.op == UserOperation.DeletePost ||
- res.op == UserOperation.RemovePost ||
- res.op == UserOperation.LockPost ||
- res.op == UserOperation.StickyPost ||
- res.op == UserOperation.SavePost
+ op == UserOperation.EditPost ||
+ op == UserOperation.DeletePost ||
+ op == UserOperation.RemovePost ||
+ op == UserOperation.LockPost ||
+ op == UserOperation.StickyPost ||
+ op == UserOperation.SavePost
) {
- let data = res.data as PostResponse;
- editPostFindRes(data, this.state.userRes.posts);
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ editPostFindRes(data.post_view, this.state.userRes.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.CreatePostLike) {
- const data = res.data as PostResponse;
- createPostLikeFindRes(data, this.state.userRes.posts);
+ } else if (op == UserOperation.CreatePostLike) {
+ let data = wsJsonToRes<PostResponse>(msg).data;
+ createPostLikeFindRes(data.post_view, this.state.userRes.posts);
this.setState(this.state);
- } else if (res.op == UserOperation.BanUser) {
- const data = res.data as BanUserResponse;
+ } else if (op == UserOperation.BanUser) {
+ let data = wsJsonToRes<BanUserResponse>(msg).data;
this.state.userRes.comments
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned = data.banned));
+ .filter(c => c.creator.id == data.user_view.user.id)
+ .forEach(c => (c.creator.banned = data.banned));
this.state.userRes.posts
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned = data.banned));
+ .filter(c => c.creator.id == data.user_view.user.id)
+ .forEach(c => (c.creator.banned = data.banned));
this.setState(this.state);
}
}
const host = isBrowser() ? externalHost : internalHost;
const httpBase = `http://${host}`; // Don't use secure here
-export const wsUri = `ws${secure}://${host}/api/v1/ws`;
-export const httpUri = `${httpBase}/api/v1`;
+export const wsUri = `ws${secure}://${host}/api/v2/ws`;
+export const httpUri = `${httpBase}/api/v2`;
export const pictrsUri = `http${secure}://${host}/pictrs/image`;
console.log(`httpbase: ${httpBase}`);
-import { GetSiteResponse, LemmyHttp } from 'lemmy-js-client';
+import {
+ CommentView,
+ GetSiteResponse,
+ LemmyHttp,
+ UserMentionView,
+} from 'lemmy-js-client';
export interface IsoData {
path: string;
routeData: any[];
- site: GetSiteResponse;
+ site_res: GetSiteResponse;
// Lang and theme
lang: string;
// communities?: ListCommunitiesResponse;
client: LemmyHttp;
}
+export interface CommentNode {
+ comment_view: CommentView | UserMentionView;
+ children?: CommentNode[];
+ depth?: number;
+}
+
+export interface PostFormParams {
+ name: string;
+ url?: string;
+ body?: string;
+ community_name?: string;
+ community_id?: number;
+}
+
export enum CommentSortType {
Hot,
Top,
// import Cookies from 'js-cookie';
import IsomorphicCookie from 'isomorphic-cookie';
-import { User, LoginResponse } from 'lemmy-js-client';
+import { User_, LoginResponse } from 'lemmy-js-client';
import jwt_decode from 'jwt-decode';
import { Subject, BehaviorSubject } from 'rxjs';
export class UserService {
private static _instance: UserService;
- public user: User;
+ public user: User_;
public claims: Claims;
public jwtSub: Subject<string> = new Subject<string>();
public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
import { wsUri } from '../env';
-import {
- LemmyWebsocket,
- LoginForm,
- RegisterForm,
- CommunityForm,
- DeleteCommunityForm,
- RemoveCommunityForm,
- PostForm,
- DeletePostForm,
- RemovePostForm,
- LockPostForm,
- StickyPostForm,
- SavePostForm,
- CommentForm,
- DeleteCommentForm,
- RemoveCommentForm,
- MarkCommentAsReadForm,
- SaveCommentForm,
- CommentLikeForm,
- GetPostForm,
- GetPostsForm,
- CreatePostLikeForm,
- GetCommunityForm,
- FollowCommunityForm,
- GetFollowedCommunitiesForm,
- GetUserDetailsForm,
- ListCommunitiesForm,
- GetModlogForm,
- BanFromCommunityForm,
- AddModToCommunityForm,
- TransferCommunityForm,
- AddAdminForm,
- TransferSiteForm,
- BanUserForm,
- SiteForm,
- UserView,
- GetRepliesForm,
- GetUserMentionsForm,
- MarkUserMentionAsReadForm,
- SearchForm,
- UserSettingsForm,
- DeleteAccountForm,
- PasswordResetForm,
- PasswordChangeForm,
- PrivateMessageForm,
- EditPrivateMessageForm,
- DeletePrivateMessageForm,
- MarkPrivateMessageAsReadForm,
- GetPrivateMessagesForm,
- GetCommentsForm,
- UserJoinForm,
- GetSiteConfig,
- GetSiteForm,
- SiteConfigForm,
- MarkAllAsReadForm,
- WebSocketJsonResponse,
- CommunityJoinForm,
- PostJoinForm,
-} from 'lemmy-js-client';
-import { UserService } from './';
-import { i18n } from '../i18next';
-import { toast, isBrowser } from '../utils';
+import { UserViewSafe, WebSocketJsonResponse } from 'lemmy-js-client';
+import { isBrowser } from '../utils';
import { Observable } from 'rxjs';
import { share } from 'rxjs/operators';
import {
export class WebSocketService {
private static _instance: WebSocketService;
- public ws: ReconnectingWebSocket;
+ private ws: ReconnectingWebSocket;
public wsOptions: WSOptions = {
connectionTimeout: 5000,
maxRetries: 10,
};
public subject: Observable<any>;
- public admins: UserView[];
- public banned: UserView[];
- private client = new LemmyWebsocket();
+ public admins: UserViewSafe[];
+ public banned: UserViewSafe[];
private constructor() {
this.ws = new ReconnectingWebSocket(wsUri, [], this.wsOptions);
console.log(`Connected to ${wsUri}`);
if (!firstConnect) {
- let res: WebSocketJsonResponse = {
+ let res: WebSocketJsonResponse<any> = {
reconnect: true,
};
obs.next(res);
firstConnect = false;
};
}).pipe(share());
- }
-
- public static get Instance() {
- return this._instance || (this._instance = new this());
- }
-
- public userJoin() {
- let form: UserJoinForm = { auth: UserService.Instance.auth };
- this.ws.send(this.client.userJoin(form));
- }
-
- public postJoin(form: PostJoinForm) {
- this.ws.send(this.client.postJoin(form));
- }
-
- public communityJoin(form: CommunityJoinForm) {
- this.ws.send(this.client.communityJoin(form));
- }
-
- public login(form: LoginForm) {
- this.ws.send(this.client.login(form));
- }
-
- public register(form: RegisterForm) {
- this.ws.send(this.client.register(form));
- }
-
- public getCaptcha() {
- this.ws.send(this.client.getCaptcha());
- }
-
- public createCommunity(form: CommunityForm) {
- this.setAuth(form); // TODO all these setauths at some point would be good to make required
- this.ws.send(this.client.createCommunity(form));
- }
-
- public editCommunity(form: CommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.editCommunity(form));
- }
-
- public deleteCommunity(form: DeleteCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.deleteCommunity(form));
- }
-
- public removeCommunity(form: RemoveCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.removeCommunity(form));
- }
-
- public followCommunity(form: FollowCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.followCommunity(form));
- }
-
- public listCommunities(form: ListCommunitiesForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.listCommunities(form));
- }
-
- public getFollowedCommunities() {
- let form: GetFollowedCommunitiesForm = { auth: UserService.Instance.auth };
- this.ws.send(this.client.getFollowedCommunities(form));
- }
-
- public listCategories() {
- this.ws.send(this.client.listCategories());
- }
-
- public createPost(form: PostForm) {
- this.setAuth(form);
- this.ws.send(this.client.createPost(form));
- }
-
- public getPost(form: GetPostForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.getPost(form));
- }
-
- public getCommunity(form: GetCommunityForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.getCommunity(form));
- }
-
- public createComment(form: CommentForm) {
- this.setAuth(form);
- this.ws.send(this.client.createComment(form));
- }
-
- public editComment(form: CommentForm) {
- this.setAuth(form);
- this.ws.send(this.client.editComment(form));
- }
-
- public deleteComment(form: DeleteCommentForm) {
- this.setAuth(form);
- this.ws.send(this.client.deleteComment(form));
- }
-
- public removeComment(form: RemoveCommentForm) {
- this.setAuth(form);
- this.ws.send(this.client.removeComment(form));
- }
-
- public markCommentAsRead(form: MarkCommentAsReadForm) {
- this.setAuth(form);
- this.ws.send(this.client.markCommentAsRead(form));
- }
-
- public likeComment(form: CommentLikeForm) {
- this.setAuth(form);
- this.ws.send(this.client.likeComment(form));
- }
-
- public saveComment(form: SaveCommentForm) {
- this.setAuth(form);
- this.ws.send(this.client.saveComment(form));
- }
-
- public getPosts(form: GetPostsForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.getPosts(form));
- }
-
- public getComments(form: GetCommentsForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.getComments(form));
- }
-
- public likePost(form: CreatePostLikeForm) {
- this.setAuth(form);
- this.ws.send(this.client.likePost(form));
- }
-
- public editPost(form: PostForm) {
- this.setAuth(form);
- this.ws.send(this.client.editPost(form));
- }
-
- public deletePost(form: DeletePostForm) {
- this.setAuth(form);
- this.ws.send(this.client.deletePost(form));
- }
-
- public removePost(form: RemovePostForm) {
- this.setAuth(form);
- this.ws.send(this.client.removePost(form));
- }
-
- public lockPost(form: LockPostForm) {
- this.setAuth(form);
- this.ws.send(this.client.lockPost(form));
- }
-
- public stickyPost(form: StickyPostForm) {
- this.setAuth(form);
- this.ws.send(this.client.stickyPost(form));
- }
-
- public savePost(form: SavePostForm) {
- this.setAuth(form);
- this.ws.send(this.client.savePost(form));
- }
-
- public banFromCommunity(form: BanFromCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.banFromCommunity(form));
- }
-
- public addModToCommunity(form: AddModToCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.addModToCommunity(form));
- }
-
- public transferCommunity(form: TransferCommunityForm) {
- this.setAuth(form);
- this.ws.send(this.client.transferCommunity(form));
- }
-
- public transferSite(form: TransferSiteForm) {
- this.setAuth(form);
- this.ws.send(this.client.transferSite(form));
- }
-
- public banUser(form: BanUserForm) {
- this.setAuth(form);
- this.ws.send(this.client.banUser(form));
- }
-
- public addAdmin(form: AddAdminForm) {
- this.setAuth(form);
- this.ws.send(this.client.addAdmin(form));
- }
-
- public getUserDetails(form: GetUserDetailsForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.getUserDetails(form));
- }
-
- public getReplies(form: GetRepliesForm) {
- this.setAuth(form);
- this.ws.send(this.client.getReplies(form));
- }
-
- public getUserMentions(form: GetUserMentionsForm) {
- this.setAuth(form);
- this.ws.send(this.client.getUserMentions(form));
- }
-
- public markUserMentionAsRead(form: MarkUserMentionAsReadForm) {
- this.setAuth(form);
- this.ws.send(this.client.markUserMentionAsRead(form));
- }
-
- public getModlog(form: GetModlogForm) {
- this.ws.send(this.client.getModlog(form));
- }
-
- public createSite(form: SiteForm) {
- this.setAuth(form);
- this.ws.send(this.client.createSite(form));
- }
-
- public editSite(form: SiteForm) {
- this.setAuth(form);
- this.ws.send(this.client.editSite(form));
- }
- public getSite(form: GetSiteForm = {}) {
- this.setAuth(form, false);
- this.ws.send(this.client.getSite(form));
- }
-
- public getSiteConfig() {
- let form: GetSiteConfig = {};
- this.setAuth(form);
- this.ws.send(this.client.getSiteConfig(form));
- }
-
- public search(form: SearchForm) {
- this.setAuth(form, false);
- this.ws.send(this.client.search(form));
- }
-
- public markAllAsRead() {
- let form: MarkAllAsReadForm = { auth: null };
- this.setAuth(form);
- this.ws.send(this.client.markAllAsRead(form));
- }
-
- public saveUserSettings(form: UserSettingsForm) {
- this.setAuth(form);
- this.ws.send(this.client.saveUserSettings(form));
- }
-
- public deleteAccount(form: DeleteAccountForm) {
- this.setAuth(form);
- this.ws.send(this.client.deleteAccount(form));
- }
-
- public passwordReset(form: PasswordResetForm) {
- this.ws.send(this.client.passwordReset(form));
- }
-
- public passwordChange(form: PasswordChangeForm) {
- this.ws.send(this.client.passwordChange(form));
- }
-
- public createPrivateMessage(form: PrivateMessageForm) {
- this.setAuth(form);
- this.ws.send(this.client.createPrivateMessage(form));
- }
-
- public editPrivateMessage(form: EditPrivateMessageForm) {
- this.setAuth(form);
- this.ws.send(this.client.editPrivateMessage(form));
- }
-
- public deletePrivateMessage(form: DeletePrivateMessageForm) {
- this.setAuth(form);
- this.ws.send(this.client.deletePrivateMessage(form));
- }
-
- public markPrivateMessageAsRead(form: MarkPrivateMessageAsReadForm) {
- this.setAuth(form);
- this.ws.send(this.client.markPrivateMessageAsRead(form));
- }
-
- public getPrivateMessages(form: GetPrivateMessagesForm) {
- this.setAuth(form);
- this.ws.send(this.client.getPrivateMessages(form));
+ if (isBrowser()) {
+ window.onbeforeunload = () => {
+ this.ws.close();
+ };
+ }
}
- public saveSiteConfig(form: SiteConfigForm) {
- this.setAuth(form);
- this.ws.send(this.client.saveSiteConfig(form));
+ public send(data: string) {
+ this.ws.send(data);
}
- public setAuth(obj: any, throwErr: boolean = true) {
- obj.auth = UserService.Instance.auth;
- if (obj.auth == null && throwErr) {
- toast(i18n.t('not_logged_in'), 'danger');
- throw 'Not logged in';
- }
+ public static get Instance() {
+ return this._instance || (this._instance = new this());
}
}
-
-if (isBrowser()) {
- window.onbeforeunload = () => {
- WebSocketService.Instance.ws.close();
- };
-}
import {
UserOperation,
- Comment,
- CommentNode as CommentNodeI,
- Post,
- PrivateMessage,
- User,
+ CommentView,
+ User_,
SortType,
ListingType,
SearchType,
WebSocketResponse,
WebSocketJsonResponse,
- SearchForm,
+ Search,
SearchResponse,
- CommentResponse,
- PostResponse,
+ PostView,
+ PrivateMessageView,
+ LemmyWebsocket,
} from 'lemmy-js-client';
-import { CommentSortType, DataType, IsoData } from './interfaces';
+import {
+ CommentSortType,
+ DataType,
+ IsoData,
+ CommentNode as CommentNodeI,
+} from './interfaces';
import { UserService, WebSocketService } from './services';
var Tribute;
import moment from 'moment';
import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
+import { i18n } from './i18next';
+
+export const wsClient = new LemmyWebsocket();
export const favIconUrl = '/static/assets/favicon.svg';
export const favIconPngUrl = '/static/assets/apple-touch-icon.png';
.join('');
}
-export function wsJsonToRes(msg: WebSocketJsonResponse): WebSocketResponse {
- let opStr: string = msg.op;
+export function wsJsonToRes<ResponseType>(
+ msg: WebSocketJsonResponse<ResponseType>
+): WebSocketResponse<ResponseType> {
return {
- op: UserOperation[opStr],
+ op: wsUserOp(msg),
data: msg.data,
};
}
+export function wsUserOp(msg: any): UserOperation {
+ let opStr: string = msg.op;
+ return UserOperation[opStr];
+}
+
export const md = new markdown_it({
html: false,
linkify: true,
defs: objectFlip(emojiShortName),
});
-export function hotRankComment(comment: Comment): number {
- return hotRank(comment.score, comment.published);
+export function hotRankComment(comment_view: CommentView): number {
+ return hotRank(comment_view.counts.score, comment_view.comment.published);
+}
+
+export function hotRankActivePost(post_view: PostView): number {
+ return hotRank(post_view.counts.score, post_view.counts.newest_comment_time);
}
-export function hotRankPost(post: Post): number {
- return hotRank(post.score, post.newest_activity_time);
+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 {
return text ? new Date(text).getTime() / 1000 : undefined;
}
-export function addTypeInfo<T>(
- arr: T[],
- name: string
-): { type_: string; data: T }[] {
- return arr.map(e => {
- return { type_: name, data: e };
- });
-}
-
export function canMod(
- user: User,
+ user: User_,
modIds: number[],
creator_id: number,
onSelf: boolean = false
return SortType[sort];
}
+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): ListingType {
return ListingType[type];
}
);
}
-export function isCommentType(
- item: Comment | PrivateMessage | Post
-): item is Comment {
- return (
- (item as Comment).community_id !== undefined &&
- (item as Comment).content !== undefined
- );
-}
-
-export function isPostType(
- item: Comment | PrivateMessage | Post
-): item is Post {
- return (item as Post).stickied !== undefined;
-}
-
export function toast(text: string, background: string = 'success') {
if (isBrowser()) {
let backgroundColor = `var(--${background})`;
}
}
-export function notifyPost(post: Post, router: any) {
+export function notifyPost(post_view: PostView, router: any) {
let info: NotifyInfo = {
- name: post.community_name,
- icon: post.community_icon ? post.community_icon : defaultFavIcon,
- link: `/post/${post.id}`,
- body: post.name,
+ name: post_view.community.name,
+ icon: post_view.community.icon ? post_view.community.icon : defaultFavIcon,
+ link: `/post/${post_view.post.id}`,
+ body: post_view.post.name,
};
notify(info, router);
}
-export function notifyComment(comment: Comment, router: any) {
+export function notifyComment(comment_view: CommentView, router: any) {
let info: NotifyInfo = {
- name: comment.creator_name,
- icon: comment.creator_avatar ? comment.creator_avatar : defaultFavIcon,
- link: `/post/${comment.post_id}/comment/${comment.id}`,
- body: comment.content,
+ name: comment_view.creator.name,
+ icon: comment_view.creator.avatar
+ ? comment_view.creator.avatar
+ : defaultFavIcon,
+ link: `/post/${comment_view.post.id}/comment/${comment_view.comment.id}`,
+ body: comment_view.comment.content,
};
notify(info, router);
}
-export function notifyPrivateMessage(pm: PrivateMessage, router: any) {
+export function notifyPrivateMessage(pmv: PrivateMessageView, router: any) {
let info: NotifyInfo = {
- name: pm.creator_name,
- icon: pm.creator_avatar ? pm.creator_avatar : defaultFavIcon,
+ name: pmv.creator.name,
+ icon: pmv.creator.avatar ? pmv.creator.avatar : defaultFavIcon,
link: `/inbox`,
- body: pm.content,
+ body: pmv.private_message.content,
};
notify(info, router);
}
function userSearch(text: string, cb: any) {
if (text) {
- let form: SearchForm = {
+ let form: Search = {
q: text,
type_: SearchType.Users,
sort: SortType.TopAll,
page: 1,
limit: mentionDropdownFetchLimit,
+ auth: authField(false),
};
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
let userSub = WebSocketService.Instance.subject.subscribe(
msg => {
let res = wsJsonToRes(msg);
if (res.op == UserOperation.Search) {
let data = res.data as SearchResponse;
- let users = data.users.map(u => {
+ let users = data.users.map(uv => {
return {
- key: `@${u.name}@${hostname(u.actor_id)}`,
- name: u.name,
- local: u.local,
- id: u.id,
+ key: `@${uv.user.name}@${hostname(uv.user.actor_id)}`,
+ name: uv.user.name,
+ local: uv.user.local,
+ id: uv.user.id,
};
});
cb(users);
function communitySearch(text: string, cb: any) {
if (text) {
- let form: SearchForm = {
+ let form: Search = {
q: text,
type_: SearchType.Communities,
sort: SortType.TopAll,
page: 1,
limit: mentionDropdownFetchLimit,
+ auth: authField(false),
};
- WebSocketService.Instance.search(form);
+ WebSocketService.Instance.send(wsClient.search(form));
let communitySub = WebSocketService.Instance.subject.subscribe(
msg => {
let res = wsJsonToRes(msg);
if (res.op == UserOperation.Search) {
let data = res.data as SearchResponse;
- let communities = data.communities.map(c => {
+ let communities = data.communities.map(cv => {
return {
- key: `!${c.name}@${hostname(c.actor_id)}`,
- name: c.name,
- local: c.local,
- id: c.id,
+ key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
+ name: cv.community.name,
+ local: cv.community.local,
+ id: cv.community.id,
};
});
cb(communities);
return props.match.params.username;
}
-export function editCommentRes(data: CommentResponse, comments: Comment[]) {
- let found = comments.find(c => c.id == data.comment.id);
+export function editCommentRes(data: CommentView, comments: CommentView[]) {
+ let found = comments.find(c => c.comment.id == data.comment.id);
if (found) {
- found.content = data.comment.content;
- found.updated = data.comment.updated;
- found.removed = data.comment.removed;
- found.deleted = data.comment.deleted;
- found.upvotes = data.comment.upvotes;
- found.downvotes = data.comment.downvotes;
- found.score = data.comment.score;
+ found.comment.content = data.comment.content;
+ found.comment.updated = data.comment.updated;
+ found.comment.removed = data.comment.removed;
+ found.comment.deleted = data.comment.deleted;
+ found.counts.upvotes = data.counts.upvotes;
+ found.counts.downvotes = data.counts.downvotes;
+ found.counts.score = data.counts.score;
}
}
-export function saveCommentRes(data: CommentResponse, comments: Comment[]) {
- let found = comments.find(c => c.id == data.comment.id);
+export function saveCommentRes(data: CommentView, comments: CommentView[]) {
+ let found = comments.find(c => c.comment.id == data.comment.id);
if (found) {
- found.saved = data.comment.saved;
+ found.saved = data.saved;
}
}
export function createCommentLikeRes(
- data: CommentResponse,
- comments: Comment[]
+ data: CommentView,
+ comments: CommentView[]
) {
- let found: Comment = comments.find(c => c.id === data.comment.id);
+ let found = comments.find(c => c.comment.id === data.comment.id);
if (found) {
- found.score = data.comment.score;
- found.upvotes = data.comment.upvotes;
- found.downvotes = data.comment.downvotes;
- if (data.comment.my_vote !== null) {
- found.my_vote = data.comment.my_vote;
+ found.counts.score = data.counts.score;
+ found.counts.upvotes = data.counts.upvotes;
+ found.counts.downvotes = data.counts.downvotes;
+ if (data.my_vote !== null) {
+ found.my_vote = data.my_vote;
}
}
}
-export function createPostLikeFindRes(data: PostResponse, posts: Post[]) {
- let found = posts.find(c => c.id == data.post.id);
+export function createPostLikeFindRes(data: PostView, posts: PostView[]) {
+ let found = posts.find(p => p.post.id == data.post.id);
if (found) {
createPostLikeRes(data, found);
}
}
-export function createPostLikeRes(data: PostResponse, post: Post) {
- if (post) {
- post.score = data.post.score;
- post.upvotes = data.post.upvotes;
- post.downvotes = data.post.downvotes;
- if (data.post.my_vote !== null) {
- post.my_vote = data.post.my_vote;
+export function createPostLikeRes(data: PostView, post_view: PostView) {
+ if (post_view) {
+ post_view.counts.score = data.counts.score;
+ post_view.counts.upvotes = data.counts.upvotes;
+ post_view.counts.downvotes = data.counts.downvotes;
+ if (data.my_vote !== null) {
+ post_view.my_vote = data.my_vote;
}
}
}
-export function editPostFindRes(data: PostResponse, posts: Post[]) {
- let found = posts.find(c => c.id == data.post.id);
+export function editPostFindRes(data: PostView, posts: PostView[]) {
+ let found = posts.find(p => p.post.id == data.post.id);
if (found) {
editPostRes(data, found);
}
}
-export function editPostRes(data: PostResponse, post: Post) {
+export function editPostRes(data: PostView, post: PostView) {
if (post) {
- post.url = data.post.url;
- post.name = data.post.name;
- post.nsfw = data.post.nsfw;
- post.deleted = data.post.deleted;
- post.removed = data.post.removed;
- post.stickied = data.post.stickied;
- post.body = data.post.body;
- post.locked = data.post.locked;
- post.saved = data.post.saved;
+ post.post.url = data.post.url;
+ post.post.name = data.post.name;
+ post.post.nsfw = data.post.nsfw;
+ post.post.deleted = data.post.deleted;
+ post.post.removed = data.post.removed;
+ post.post.stickied = data.post.stickied;
+ post.post.body = data.post.body;
+ post.post.locked = data.post.locked;
+ post.saved = data.saved;
}
}
-export function commentsToFlatNodes(comments: Comment[]): CommentNodeI[] {
+export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
let nodes: CommentNodeI[] = [];
for (let comment of comments) {
- nodes.push({ comment: comment });
+ nodes.push({ comment_view: comment });
}
return nodes;
}
if (sort == CommentSortType.Top) {
tree.sort(
(a, b) =>
- +a.comment.removed - +b.comment.removed ||
- +a.comment.deleted - +b.comment.deleted ||
- b.comment.score - a.comment.score
+ +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
+ +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
+ b.comment_view.counts.score - a.comment_view.counts.score
);
} else if (sort == CommentSortType.New) {
tree.sort(
(a, b) =>
- +a.comment.removed - +b.comment.removed ||
- +a.comment.deleted - +b.comment.deleted ||
- b.comment.published.localeCompare(a.comment.published)
+ +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
+ +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
+ b.comment_view.comment.published.localeCompare(
+ a.comment_view.comment.published
+ )
);
} else if (sort == CommentSortType.Old) {
tree.sort(
(a, b) =>
- +a.comment.removed - +b.comment.removed ||
- +a.comment.deleted - +b.comment.deleted ||
- a.comment.published.localeCompare(b.comment.published)
+ +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
+ +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
+ a.comment_view.comment.published.localeCompare(
+ b.comment_view.comment.published
+ )
);
} else if (sort == CommentSortType.Hot) {
tree.sort(
(a, b) =>
- +a.comment.removed - +b.comment.removed ||
- +a.comment.deleted - +b.comment.deleted ||
- hotRankComment(b.comment) - hotRankComment(a.comment)
+ +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
+ +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
+ hotRankComment(b.comment_view) - hotRankComment(a.comment_view)
);
}
}
export function postSort(
- posts: Post[],
+ posts: PostView[],
sort: SortType,
communityType: boolean
) {
) {
posts.sort(
(a, b) =>
- +a.removed - +b.removed ||
- +a.deleted - +b.deleted ||
- (communityType && +b.stickied - +a.stickied) ||
- b.score - a.score
+ +a.post.removed - +b.post.removed ||
+ +a.post.deleted - +b.post.deleted ||
+ (communityType && +b.post.stickied - +a.post.stickied) ||
+ b.counts.score - a.counts.score
);
} else if (sort == SortType.New) {
posts.sort(
(a, b) =>
- +a.removed - +b.removed ||
- +a.deleted - +b.deleted ||
- (communityType && +b.stickied - +a.stickied) ||
- b.published.localeCompare(a.published)
+ +a.post.removed - +b.post.removed ||
+ +a.post.deleted - +b.post.deleted ||
+ (communityType && +b.post.stickied - +a.post.stickied) ||
+ b.post.published.localeCompare(a.post.published)
);
} else if (sort == SortType.Hot) {
posts.sort(
(a, b) =>
- +a.removed - +b.removed ||
- +a.deleted - +b.deleted ||
- (communityType && +b.stickied - +a.stickied) ||
- b.hot_rank - a.hot_rank
+ +a.post.removed - +b.post.removed ||
+ +a.post.deleted - +b.post.deleted ||
+ (communityType && +b.post.stickied - +a.post.stickied) ||
+ hotRankPost(b) - hotRankPost(a)
);
} else if (sort == SortType.Active) {
posts.sort(
(a, b) =>
- +a.removed - +b.removed ||
- +a.deleted - +b.deleted ||
- (communityType && +b.stickied - +a.stickied) ||
- b.hot_rank_active - a.hot_rank_active
+ +a.post.removed - +b.post.removed ||
+ +a.post.deleted - +b.post.deleted ||
+ (communityType && +b.post.stickied - +a.post.stickied) ||
+ hotRankActivePost(b) - hotRankActivePost(a)
);
}
}
return typeof window !== 'undefined';
}
-export function setAuth(obj: any, auth: string) {
- if (auth) {
- obj.auth = auth;
- }
-}
-
export function setIsoData(context: any): IsoData {
let isoData: IsoData = isBrowser()
? window.isoData
}
}
+export function setOptionalAuth(obj: any, auth = UserService.Instance.auth) {
+ if (auth) {
+ obj.auth = auth;
+ }
+}
+
+export function authField(
+ throwErr: boolean = true,
+ auth = UserService.Instance.auth
+): string {
+ if (auth == null && throwErr) {
+ toast(i18n.t('not_logged_in'), 'danger');
+ throw 'Not logged in';
+ } else {
+ return auth;
+ }
+}
+
moment.updateLocale('en', {
relativeTime: {
future: 'in %s',
dependencies:
"@babel/highlight" "^7.10.4"
+"@babel/code-frame@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
+ integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
+ dependencies:
+ "@babel/highlight" "^7.10.4"
+
"@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.7.tgz#9329b4782a7d6bbd7eef57e11addf91ee3ef1e41"
integrity sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==
-"@babel/core@^7.12.9":
- version "7.12.9"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8"
- integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==
+"@babel/core@^7.12.10":
+ version "7.12.10"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd"
+ integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==
dependencies:
"@babel/code-frame" "^7.10.4"
- "@babel/generator" "^7.12.5"
+ "@babel/generator" "^7.12.10"
"@babel/helper-module-transforms" "^7.12.1"
"@babel/helpers" "^7.12.5"
- "@babel/parser" "^7.12.7"
+ "@babel/parser" "^7.12.10"
"@babel/template" "^7.12.7"
- "@babel/traverse" "^7.12.9"
- "@babel/types" "^7.12.7"
+ "@babel/traverse" "^7.12.10"
+ "@babel/types" "^7.12.10"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.1"
json5 "^2.1.2"
lodash "^4.17.19"
- resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
jsesc "^2.5.1"
source-map "^0.5.0"
+"@babel/generator@^7.12.10", "@babel/generator@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af"
+ integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==
+ dependencies:
+ "@babel/types" "^7.12.11"
+ jsesc "^2.5.1"
+ source-map "^0.5.0"
+
"@babel/generator@^7.12.5":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de"
"@babel/template" "^7.10.4"
"@babel/types" "^7.10.4"
+"@babel/helper-function-name@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42"
+ integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.12.10"
+ "@babel/template" "^7.12.7"
+ "@babel/types" "^7.12.11"
+
"@babel/helper-get-function-arity@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
dependencies:
"@babel/types" "^7.10.4"
+"@babel/helper-get-function-arity@^7.12.10":
+ version "7.12.10"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf"
+ integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==
+ dependencies:
+ "@babel/types" "^7.12.10"
+
"@babel/helper-hoist-variables@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e"
dependencies:
"@babel/types" "^7.11.0"
+"@babel/helper-split-export-declaration@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz#1b4cc424458643c47d37022223da33d76ea4603a"
+ integrity sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==
+ dependencies:
+ "@babel/types" "^7.12.11"
+
"@babel/helper-validator-identifier@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
+"@babel/helper-validator-identifier@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
+ integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
+
"@babel/helper-validator-option@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9"
integrity sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==
+"@babel/helper-validator-option@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
+ integrity sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==
+
"@babel/helper-wrap-function@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd"
integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==
+"@babel/parser@^7.12.10", "@babel/parser@^7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79"
+ integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==
+
"@babel/parser@^7.12.7":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056"
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-transform-block-scoping@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz#f0ee727874b42a208a48a586b84c3d222c2bbef1"
- integrity sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==
+"@babel/plugin-transform-block-scoping@^7.12.11":
+ version "7.12.12"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.12.tgz#d93a567a152c22aea3b1929bb118d1d0a175cdca"
+ integrity sha512-VOEPQ/ExOVqbukuP7BYJtI5ZxxsmegTwzZ04j1aF0dkSypGo9XpDHuOrABsJu+ie+penpSJheDJ11x1BEZNiyQ==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-transform-runtime@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz#04b792057eb460389ff6a4198e377614ea1e7ba5"
- integrity sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==
+"@babel/plugin-transform-runtime@^7.12.10":
+ version "7.12.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz#af0fded4e846c4b37078e8e5d06deac6cd848562"
+ integrity sha512-xOrUfzPxw7+WDm9igMgQCbO3cJKymX7dFdsgRr1eu9n3KjjyU4pptIXbXPseQDquw+W+RuJEJMHKHNsPNNm3CA==
dependencies:
- "@babel/helper-module-imports" "^7.12.1"
+ "@babel/helper-module-imports" "^7.12.5"
"@babel/helper-plugin-utils" "^7.10.4"
- resolve "^1.8.1"
semver "^5.5.1"
"@babel/plugin-transform-shorthand-properties@^7.12.1":
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-transform-typeof-symbol@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz#9ca6be343d42512fbc2e68236a82ae64bc7af78a"
- integrity sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==
+"@babel/plugin-transform-typeof-symbol@^7.12.10":
+ version "7.12.10"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz#de01c4c8f96580bd00f183072b0d0ecdcf0dec4b"
+ integrity sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/helper-create-regexp-features-plugin" "^7.12.1"
"@babel/helper-plugin-utils" "^7.10.4"
-"@babel/preset-env@7.12.7":
- version "7.12.7"
- resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.7.tgz#54ea21dbe92caf6f10cb1a0a576adc4ebf094b55"
- integrity sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==
+"@babel/preset-env@7.12.11":
+ version "7.12.11"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.11.tgz#55d5f7981487365c93dbbc84507b1c7215e857f9"
+ integrity sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==
dependencies:
"@babel/compat-data" "^7.12.7"
"@babel/helper-compilation-targets" "^7.12.5"
"@babel/helper-module-imports" "^7.12.5"
"@babel/helper-plugin-utils" "^7.10.4"
- "@babel/helper-validator-option" "^7.12.1"
+ "@babel/helper-validator-option" "^7.12.11"
"@babel/plugin-proposal-async-generator-functions" "^7.12.1"
"@babel/plugin-proposal-class-properties" "^7.12.1"
"@babel/plugin-proposal-dynamic-import" "^7.12.1"
"@babel/plugin-transform-arrow-functions" "^7.12.1"
"@babel/plugin-transform-async-to-generator" "^7.12.1"
"@babel/plugin-transform-block-scoped-functions" "^7.12.1"
- "@babel/plugin-transform-block-scoping" "^7.12.1"
+ "@babel/plugin-transform-block-scoping" "^7.12.11"
"@babel/plugin-transform-classes" "^7.12.1"
"@babel/plugin-transform-computed-properties" "^7.12.1"
"@babel/plugin-transform-destructuring" "^7.12.1"
"@babel/plugin-transform-spread" "^7.12.1"
"@babel/plugin-transform-sticky-regex" "^7.12.7"
"@babel/plugin-transform-template-literals" "^7.12.1"
- "@babel/plugin-transform-typeof-symbol" "^7.12.1"
+ "@babel/plugin-transform-typeof-symbol" "^7.12.10"
"@babel/plugin-transform-unicode-escapes" "^7.12.1"
"@babel/plugin-transform-unicode-regex" "^7.12.1"
"@babel/preset-modules" "^0.1.3"
- "@babel/types" "^7.12.7"
- core-js-compat "^3.7.0"
+ "@babel/types" "^7.12.11"
+ core-js-compat "^3.8.0"
semver "^5.5.0"
"@babel/preset-modules@^0.1.3":
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5":
+ version "7.12.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
+ integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/runtime@^7.12.0":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.12.5":
- version "7.12.5"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
- integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
- dependencies:
- regenerator-runtime "^0.13.4"
-
"@babel/template@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
globals "^11.1.0"
lodash "^4.17.19"
-"@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9":
+"@babel/traverse@^7.12.10":
+ version "7.12.12"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376"
+ integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==
+ dependencies:
+ "@babel/code-frame" "^7.12.11"
+ "@babel/generator" "^7.12.11"
+ "@babel/helper-function-name" "^7.12.11"
+ "@babel/helper-split-export-declaration" "^7.12.11"
+ "@babel/parser" "^7.12.11"
+ "@babel/types" "^7.12.12"
+ debug "^4.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.19"
+
+"@babel/traverse@^7.12.5":
version "7.12.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.9.tgz#fad26c972eabbc11350e0b695978de6cc8e8596f"
integrity sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==
lodash "^4.17.19"
to-fast-properties "^2.0.0"
+"@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12":
+ version "7.12.12"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299"
+ integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.12.11"
+ lodash "^4.17.19"
+ to-fast-properties "^2.0.0"
+
"@babel/types@^7.12.5", "@babel/types@^7.12.7":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13"
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"
-"@npmcli/move-file@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464"
- integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==
- dependencies:
- mkdirp "^1.0.4"
-
"@popperjs/core@^2.4.4":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.4.4.tgz#11d5db19bd178936ec89cd84519c4de439574398"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.0.tgz#7d4411bf5157339337d7cff864d9ff45f177b499"
integrity sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA==
-"@types/node@^14.14.11":
- version "14.14.11"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.11.tgz#fc25a4248a5e8d0837019b1d170146d07334abe0"
- integrity sha512-BJ97wAUuU3NUiUCp44xzUFquQEvnk1wu7q4CMEUYKJWjdkr0YWYDsm4RFtAvxYsNjLsKcrFt6RvK8r+mnzMbEQ==
+"@types/node@^14.14.16":
+ version "14.14.16"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.16.tgz#3cc351f8d48101deadfed4c9e4f116048d437b4b"
+ integrity sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
"@types/webpack-sources" "*"
source-map "^0.6.0"
-"@typescript-eslint/eslint-plugin@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.5.0.tgz#4ff9c1d8535ae832e239f0ef6d7210592d9b0b07"
- integrity sha512-mjb/gwNcmDKNt+6mb7Aj/TjKzIJjOPcoCJpjBQC9ZnTRnBt1p4q5dJSSmIqAtsZ/Pff5N+hJlbiPc5bl6QN4OQ==
+"@typescript-eslint/eslint-plugin@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.0.tgz#bc6c1e4175c0cf42083da4314f7931ad12f731cc"
+ integrity sha512-x4arJMXBxyD6aBXLm3W7mSDZRiABzy+2PCLJbL7OPqlp53VXhaA1HKK7R2rTee5OlRhnUgnp8lZyVIqjnyPT6g==
dependencies:
- "@typescript-eslint/experimental-utils" "4.5.0"
- "@typescript-eslint/scope-manager" "4.5.0"
+ "@typescript-eslint/experimental-utils" "4.11.0"
+ "@typescript-eslint/scope-manager" "4.11.0"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.0.0"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/experimental-utils@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.5.0.tgz#547fe1158609143ce60645383aa1d6f83ada28df"
- integrity sha512-bW9IpSAKYvkqDGRZzayBXIgPsj2xmmVHLJ+flGSoN0fF98pGoKFhbunIol0VF2Crka7z984EEhFi623Rl7e6gg==
+"@typescript-eslint/experimental-utils@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.0.tgz#d1a47cc6cfe1c080ce4ead79267574b9881a1565"
+ integrity sha512-1VC6mSbYwl1FguKt8OgPs8xxaJgtqFpjY/UzUYDBKq4pfQ5lBvN2WVeqYkzf7evW42axUHYl2jm9tNyFsb8oLg==
dependencies:
"@types/json-schema" "^7.0.3"
- "@typescript-eslint/scope-manager" "4.5.0"
- "@typescript-eslint/types" "4.5.0"
- "@typescript-eslint/typescript-estree" "4.5.0"
+ "@typescript-eslint/scope-manager" "4.11.0"
+ "@typescript-eslint/types" "4.11.0"
+ "@typescript-eslint/typescript-estree" "4.11.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
-"@typescript-eslint/parser@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.5.0.tgz#b2d659f25eec0041c7bc5660b91db1eefe8d7122"
- integrity sha512-xb+gmyhQcnDWe+5+xxaQk5iCw6KqXd8VQxGiTeELTMoYeRjpocZYYRP1gFVM2C8Yl0SpUvLa1lhprwqZ00w3Iw==
- dependencies:
- "@typescript-eslint/scope-manager" "4.5.0"
- "@typescript-eslint/types" "4.5.0"
- "@typescript-eslint/typescript-estree" "4.5.0"
- debug "^4.1.1"
-
-"@typescript-eslint/parser@^4.9.1":
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.9.1.tgz#2d74c4db5dd5117379a9659081a4d1ec02629055"
- integrity sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g==
+"@typescript-eslint/parser@4.11.0", "@typescript-eslint/parser@^4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.11.0.tgz#1dd3d7e42708c10ce9f3aa64c63c0ab99868b4e2"
+ integrity sha512-NBTtKCC7ZtuxEV5CrHUO4Pg2s784pvavc3cnz6V+oJvVbK4tH9135f/RBP6eUA2KHiFKAollSrgSctQGmHbqJQ==
dependencies:
- "@typescript-eslint/scope-manager" "4.9.1"
- "@typescript-eslint/types" "4.9.1"
- "@typescript-eslint/typescript-estree" "4.9.1"
+ "@typescript-eslint/scope-manager" "4.11.0"
+ "@typescript-eslint/types" "4.11.0"
+ "@typescript-eslint/typescript-estree" "4.11.0"
debug "^4.1.1"
"@typescript-eslint/scope-manager@4.1.0":
"@typescript-eslint/types" "4.1.0"
"@typescript-eslint/visitor-keys" "4.1.0"
-"@typescript-eslint/scope-manager@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.5.0.tgz#8dfd53c3256d4357e7d66c2fc8956835f4d239be"
- integrity sha512-C0cEO0cTMPJ/w4RA/KVe4LFFkkSh9VHoFzKmyaaDWAnPYIEzVCtJ+Un8GZoJhcvq+mPFXEsXa01lcZDHDG6Www==
+"@typescript-eslint/scope-manager@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz#2d906537db8a3a946721699e4fc0833810490254"
+ integrity sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==
dependencies:
- "@typescript-eslint/types" "4.5.0"
- "@typescript-eslint/visitor-keys" "4.5.0"
-
-"@typescript-eslint/scope-manager@4.9.1":
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz#cc2fde310b3f3deafe8436a924e784eaab265103"
- integrity sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ==
- dependencies:
- "@typescript-eslint/types" "4.9.1"
- "@typescript-eslint/visitor-keys" "4.9.1"
+ "@typescript-eslint/types" "4.11.0"
+ "@typescript-eslint/visitor-keys" "4.11.0"
"@typescript-eslint/types@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.0.tgz#edbd3fec346f34e13ce7aa176b03b497a32c496a"
integrity sha512-rkBqWsO7m01XckP9R2YHVN8mySOKKY2cophGM8K5uDK89ArCgahItQYdbg/3n8xMxzu2elss+an1TphlUpDuJw==
-"@typescript-eslint/types@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.5.0.tgz#98256e07bad1c8d15d0c9627ebec82fd971bb3c3"
- integrity sha512-n2uQoXnyWNk0Les9MtF0gCK3JiWd987JQi97dMSxBOzVoLZXCNtxFckVqt1h8xuI1ix01t+iMY4h4rFMj/303g==
-
-"@typescript-eslint/types@4.9.1":
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.9.1.tgz#a1a7dd80e4e5ac2c593bc458d75dd1edaf77faa2"
- integrity sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA==
+"@typescript-eslint/types@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.11.0.tgz#86cf95e7eac4ccfd183f9fcf1480cece7caf4ca4"
+ integrity sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==
"@typescript-eslint/typescript-estree@4.1.0":
version "4.1.0"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/typescript-estree@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.5.0.tgz#d50cf91ae3a89878401111031eb6fb6d03554f64"
- integrity sha512-gN1mffq3zwRAjlYWzb5DanarOPdajQwx5MEWkWCk0XvqC8JpafDTeioDoow2L4CA/RkYZu7xEsGZRhqrTsAG8w==
- dependencies:
- "@typescript-eslint/types" "4.5.0"
- "@typescript-eslint/visitor-keys" "4.5.0"
- debug "^4.1.1"
- globby "^11.0.1"
- is-glob "^4.0.1"
- lodash "^4.17.15"
- semver "^7.3.2"
- tsutils "^3.17.1"
-
-"@typescript-eslint/typescript-estree@4.9.1":
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz#6e5b86ff5a5f66809e1f347469fadeec69ac50bf"
- integrity sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw==
+"@typescript-eslint/typescript-estree@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.0.tgz#1144d145841e5987d61c4c845442a24b24165a4b"
+ integrity sha512-eA6sT5dE5RHAFhtcC+b5WDlUIGwnO9b0yrfGa1mIOIAjqwSQCpXbLiFmKTdRbQN/xH2EZkGqqLDrKUuYOZ0+Hg==
dependencies:
- "@typescript-eslint/types" "4.9.1"
- "@typescript-eslint/visitor-keys" "4.9.1"
+ "@typescript-eslint/types" "4.11.0"
+ "@typescript-eslint/visitor-keys" "4.11.0"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
"@typescript-eslint/types" "4.1.0"
eslint-visitor-keys "^2.0.0"
-"@typescript-eslint/visitor-keys@4.5.0":
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.5.0.tgz#b59f26213ac597efe87f6b13cf2aabee70542af0"
- integrity sha512-UHq4FSa55NDZqscRU//O5ROFhHa9Hqn9KWTEvJGTArtTQp5GKv9Zqf6d/Q3YXXcFv4woyBml7fJQlQ+OuqRcHA==
+"@typescript-eslint/visitor-keys@4.11.0":
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz#906669a50f06aa744378bb84c7d5c4fdbc5b7d51"
+ integrity sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==
dependencies:
- "@typescript-eslint/types" "4.5.0"
+ "@typescript-eslint/types" "4.11.0"
eslint-visitor-keys "^2.0.0"
-"@typescript-eslint/visitor-keys@4.9.1":
- version "4.9.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz#d76374a58c4ead9e92b454d186fea63487b25ae1"
- integrity sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ==
+"@webassemblyjs/ast@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.1.tgz#76c6937716d68bf1484c15139f5ed30b9abc8bb4"
+ integrity sha512-uMu1nCWn2Wxyy126LlGqRVlhdTOsO/bsBRI4dNq3+6SiSuRKRQX6ejjKgh82LoGAPSq72lDUiQ4FWVaf0PecYw==
dependencies:
- "@typescript-eslint/types" "4.9.1"
- eslint-visitor-keys "^2.0.0"
+ "@webassemblyjs/helper-module-context" "1.9.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.1"
+ "@webassemblyjs/wast-parser" "1.9.1"
+
+"@webassemblyjs/floating-point-hex-parser@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.1.tgz#9eb0ff90a1cdeef51f36ba533ed9f06b5cdadd09"
+ integrity sha512-5VEKu024RySmLKTTBl9q1eO/2K5jk9ZS+2HXDBLA9s9p5IjkaXxWiDb/+b7wSQp6FRdLaH1IVGIfOex58Na2pg==
+
+"@webassemblyjs/helper-api-error@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.1.tgz#ad89015c4246cd7f5ed0556700237f8b9c2c752f"
+ integrity sha512-y1lGmfm38djrScwpeL37rRR9f1D6sM8RhMpvM7CYLzOlHVboouZokXK/G88BpzW0NQBSvCCOnW5BFhten4FPfA==
-"@webassemblyjs/ast@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
- integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==
- dependencies:
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
-
-"@webassemblyjs/floating-point-hex-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4"
- integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==
-
-"@webassemblyjs/helper-api-error@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2"
- integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==
-
-"@webassemblyjs/helper-buffer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00"
- integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==
-
-"@webassemblyjs/helper-code-frame@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27"
- integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==
- dependencies:
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/helper-fsm@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8"
- integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==
-
-"@webassemblyjs/helper-module-context@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07"
- integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
-
-"@webassemblyjs/helper-wasm-bytecode@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790"
- integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==
-
-"@webassemblyjs/helper-wasm-section@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346"
- integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
-
-"@webassemblyjs/ieee754@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4"
- integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==
+"@webassemblyjs/helper-buffer@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.1.tgz#186e67ac25f9546ea7939759413987f157524133"
+ integrity sha512-uS6VSgieHbk/m4GSkMU5cqe/5TekdCzQso4revCIEQ3vpGZgqSSExi4jWpTWwDpAHOIAb1Jfrs0gUB9AA4n71w==
+
+"@webassemblyjs/helper-code-frame@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.1.tgz#aab177b7cc87a318a8f8664ad68e2c3828ebc42b"
+ integrity sha512-ZQ2ZT6Evk4DPIfD+92AraGYaFIqGm4U20e7FpXwl7WUo2Pn1mZ1v8VGH8i+Y++IQpxPbQo/UyG0Khs7eInskzA==
+ dependencies:
+ "@webassemblyjs/wast-printer" "1.9.1"
+
+"@webassemblyjs/helper-fsm@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.1.tgz#527e91628e84d13d3573884b3dc4c53a81dcb911"
+ integrity sha512-J32HGpveEqqcKFS0YbgicB0zAlpfIxJa5MjxDxhu3i5ltPcVfY5EPvKQ1suRguFPehxiUs+/hfkwPEXom/l0lw==
+
+"@webassemblyjs/helper-module-context@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.1.tgz#778670b3d471f7cf093d1e7c0dde431b54310e16"
+ integrity sha512-IEH2cMmEQKt7fqelLWB5e/cMdZXf2rST1JIrzWmf4XBt3QTxGdnnLvV4DYoN8pJjOx0VYXsWg+yF16MmJtolZg==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+
+"@webassemblyjs/helper-wasm-bytecode@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.1.tgz#563f59bcf409ccf469edde168b9426961ffbf6df"
+ integrity sha512-i2rGTBqFUcSXxyjt2K4vm/3kkHwyzG6o427iCjcIKjOqpWH8SEem+xe82jUk1iydJO250/CvE5o7hzNAMZf0dQ==
+
+"@webassemblyjs/helper-wasm-section@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.1.tgz#f7988f94c12b01b99a16120cb01dc099b00e4798"
+ integrity sha512-FetqzjtXZr2d57IECK+aId3D0IcGweeM0CbAnJHkYJkcRTHP+YcMb7Wmc0j21h5UWBpwYGb9dSkK/93SRCTrGg==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-buffer" "1.9.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.1"
+ "@webassemblyjs/wasm-gen" "1.9.1"
+
+"@webassemblyjs/ieee754@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.1.tgz#3b715871ca7d75784717cf9ceca9d7b81374b8af"
+ integrity sha512-EvTG9M78zP1MmkBpUjGQHZc26DzPGZSLIPxYHCjQsBMo60Qy2W34qf8z0exRDtxBbRIoiKa5dFyWer/7r1aaSQ==
dependencies:
"@xtuc/ieee754" "^1.2.0"
-"@webassemblyjs/leb128@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95"
- integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==
+"@webassemblyjs/leb128@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.1.tgz#b2ecaa39f9e8277cc9c707c1ca8b2aa7b27d0b72"
+ integrity sha512-Oc04ub0vFfLnF+2/+ki3AE+anmW4sv9uNBqb+79fgTaPv6xJsOT0dhphNfL3FrME84CbX/D1T9XT8tjFo0IIiw==
dependencies:
"@xtuc/long" "4.2.2"
-"@webassemblyjs/utf8@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab"
- integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==
-
-"@webassemblyjs/wasm-edit@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf"
- integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/helper-wasm-section" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-opt" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
- "@webassemblyjs/wast-printer" "1.9.0"
-
-"@webassemblyjs/wasm-gen@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c"
- integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wasm-opt@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61"
- integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-buffer" "1.9.0"
- "@webassemblyjs/wasm-gen" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
-
-"@webassemblyjs/wasm-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e"
- integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
- "@webassemblyjs/ieee754" "1.9.0"
- "@webassemblyjs/leb128" "1.9.0"
- "@webassemblyjs/utf8" "1.9.0"
-
-"@webassemblyjs/wast-parser@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914"
- integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==
- dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/floating-point-hex-parser" "1.9.0"
- "@webassemblyjs/helper-api-error" "1.9.0"
- "@webassemblyjs/helper-code-frame" "1.9.0"
- "@webassemblyjs/helper-fsm" "1.9.0"
+"@webassemblyjs/utf8@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.1.tgz#d02d9daab85cda3211e43caf31dca74c260a73b0"
+ integrity sha512-llkYtppagjCodFjo0alWOUhAkfOiQPQDIc5oA6C9sFAXz7vC9QhZf/f8ijQIX+A9ToM3c9Pq85X0EX7nx9gVhg==
+
+"@webassemblyjs/wasm-edit@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.1.tgz#e27a6bdbf78e5c72fa812a2fc3cbaad7c3e37578"
+ integrity sha512-S2IaD6+x9B2Xi8BCT0eGsrXXd8UxAh2LVJpg1ZMtHXnrDcsTtIX2bDjHi40Hio6Lc62dWHmKdvksI+MClCYbbw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-buffer" "1.9.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.1"
+ "@webassemblyjs/helper-wasm-section" "1.9.1"
+ "@webassemblyjs/wasm-gen" "1.9.1"
+ "@webassemblyjs/wasm-opt" "1.9.1"
+ "@webassemblyjs/wasm-parser" "1.9.1"
+ "@webassemblyjs/wast-printer" "1.9.1"
+
+"@webassemblyjs/wasm-gen@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.1.tgz#56a0787d1fa7994fdc7bea59004e5bec7189c5fc"
+ integrity sha512-bqWI0S4lBQsEN5FTZ35vYzfKUJvtjNnBobB1agCALH30xNk1LToZ7Z8eiaR/Z5iVECTlBndoRQV3F6mbEqE/fg==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.1"
+ "@webassemblyjs/ieee754" "1.9.1"
+ "@webassemblyjs/leb128" "1.9.1"
+ "@webassemblyjs/utf8" "1.9.1"
+
+"@webassemblyjs/wasm-opt@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.1.tgz#fbdf8943a825e6dcc4cd69c3e092289fa4aec96c"
+ integrity sha512-gSf7I7YWVXZ5c6XqTEqkZjVs8K1kc1k57vsB6KBQscSagDNbAdxt6MwuJoMjsE1yWY1tsuL+pga268A6u+Fdkg==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-buffer" "1.9.1"
+ "@webassemblyjs/wasm-gen" "1.9.1"
+ "@webassemblyjs/wasm-parser" "1.9.1"
+
+"@webassemblyjs/wasm-parser@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.1.tgz#5e8352a246d3f605312c8e414f7990de55aaedfa"
+ integrity sha512-ImM4N2T1MEIond0MyE3rXvStVxEmivQrDKf/ggfh5pP6EHu3lL/YTAoSrR7shrbKNPpeKpGesW1LIK/L4kqduw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-api-error" "1.9.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.1"
+ "@webassemblyjs/ieee754" "1.9.1"
+ "@webassemblyjs/leb128" "1.9.1"
+ "@webassemblyjs/utf8" "1.9.1"
+
+"@webassemblyjs/wast-parser@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.1.tgz#e25ef13585c060073c1db0d6bd94340fdeee7596"
+ integrity sha512-2xVxejXSvj3ls/o2TR/zI6p28qsGupjHhnHL6URULQRcXmryn3w7G83jQMcT7PHqUfyle65fZtWLukfdLdE7qw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/floating-point-hex-parser" "1.9.1"
+ "@webassemblyjs/helper-api-error" "1.9.1"
+ "@webassemblyjs/helper-code-frame" "1.9.1"
+ "@webassemblyjs/helper-fsm" "1.9.1"
"@xtuc/long" "4.2.2"
-"@webassemblyjs/wast-printer@1.9.0":
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899"
- integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==
+"@webassemblyjs/wast-printer@1.9.1":
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.1.tgz#b9f38e93652037d4f3f9c91584635af4191ed7c1"
+ integrity sha512-tDV8V15wm7mmbAH6XvQRU1X+oPGmeOzYsd6h7hlRLz6QpV4Ec/KKxM8OpLtFmQPLCreGxTp+HuxtH4pRIZyL9w==
dependencies:
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/wast-parser" "1.9.0"
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/wast-parser" "1.9.1"
"@xtuc/long" "4.2.2"
"@webpack-cli/info@^1.1.0":
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
-ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
+ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
version "6.12.4"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234"
integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==
es-abstract "^1.17.0"
is-string "^1.0.5"
+array-includes@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.2.tgz#a8db03e0b88c8c6aeddc49cb132f9bcab4ebf9c8"
+ integrity sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+ es-abstract "^1.18.0-next.1"
+ get-intrinsic "^1.0.1"
+ is-string "^1.0.5"
+
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
-astral-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
- integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
-
astral-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
-axe-core@^3.5.4:
- version "3.5.5"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
- integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
+axe-core@^4.0.2:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.1.tgz#70a7855888e287f7add66002211a423937063eaf"
+ integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==
-axobject-query@^2.1.2:
+axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
escalade "^3.1.0"
node-releases "^1.1.61"
-browserslist@^4.14.7:
- version "4.14.7"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.7.tgz#c071c1b3622c1c2e790799a37bb09473a4351cb6"
- integrity sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==
+browserslist@^4.15.0:
+ version "4.16.0"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.0.tgz#410277627500be3cb28a1bfe037586fbedf9488b"
+ integrity sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==
dependencies:
- caniuse-lite "^1.0.30001157"
+ caniuse-lite "^1.0.30001165"
colorette "^1.2.1"
- electron-to-chromium "^1.3.591"
+ electron-to-chromium "^1.3.621"
escalade "^3.1.1"
- node-releases "^1.1.66"
+ node-releases "^1.1.67"
buffer-from@^1.0.0:
version "1.1.1"
unique-filename "^1.1.1"
y18n "^4.0.0"
-cacache@^15.0.5:
- version "15.0.5"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0"
- integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==
- dependencies:
- "@npmcli/move-file" "^1.0.1"
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- glob "^7.1.4"
- infer-owner "^1.0.4"
- lru-cache "^6.0.0"
- minipass "^3.1.1"
- minipass-collect "^1.0.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.2"
- mkdirp "^1.0.3"
- p-map "^4.0.0"
- promise-inflight "^1.0.1"
- rimraf "^3.0.2"
- ssri "^8.0.0"
- tar "^6.0.2"
- unique-filename "^1.1.1"
-
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
union-value "^1.0.0"
unset-value "^1.0.0"
+call-bind@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce"
+ integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.0"
+
call-limit@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001151.tgz#1ddfde5e6fff02aad7940b4edb7d3ac76b0cb00b"
integrity sha512-Zh3sHqskX6mHNrqUerh+fkf0N72cMxrmflzje/JyVImfpknscMnkeJrlFGJcqTmaa0iszdYptGpWMJCRQDkBVw==
-caniuse-lite@^1.0.30001157:
- version "1.0.30001164"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001164.tgz#5bbfd64ca605d43132f13cc7fdabb17c3036bfdc"
- integrity sha512-G+A/tkf4bu0dSp9+duNiXc7bGds35DioCyC6vgK2m/rjA4Krpy5WeZgZyfH2f0wj2kI6yAWWucyap6oOwmY1mg==
+caniuse-lite@^1.0.30001165:
+ version "1.0.30001170"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz#0088bfecc6a14694969e391cc29d7eb6362ca6a7"
+ integrity sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==
capture-stack-trace@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-copy-webpack-plugin@^6.4.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.0.tgz#7fd397af78e0d310dbf6575d1a0f2fe10efd4d59"
- integrity sha512-p4eIA0ZWk4UI+xewyxOBTDCSDfjK6nCkr3zhDenoi7SFd+NgDNH/D14IZeFaCEFcK/psNDcAUMOB+sAxZ3SsAA==
+copy-webpack-plugin@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-7.0.0.tgz#3506f867ca6e861ee2769d4deaf8fa0d2563ada9"
+ integrity sha512-SLjQNa5iE3BoCP76ESU9qYo9ZkEWtXoZxDurHoqPchAFRblJ9g96xTeC560UXBMre1Nx6ixIIUfiY3VcjpJw3g==
dependencies:
- cacache "^15.0.5"
fast-glob "^3.2.4"
- find-cache-dir "^3.3.1"
glob-parent "^5.1.1"
globby "^11.0.1"
loader-utils "^2.0.0"
p-limit "^3.0.2"
schema-utils "^3.0.0"
serialize-javascript "^5.0.1"
- webpack-sources "^1.4.3"
-core-js-compat@^3.7.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.0.tgz#3248c6826f4006793bd637db608bca6e4cd688b1"
- integrity sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==
+core-js-compat@^3.8.0:
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e"
+ integrity sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==
dependencies:
- browserslist "^4.14.7"
+ browserslist "^4.15.0"
semver "7.0.0"
core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.583.tgz#47a9fde74740b1205dba96db2e433132964ba3ee"
integrity sha512-L9BwLwJohjZW9mQESI79HRzhicPk1DFgM+8hOCfGgGCFEcA3Otpv7QK6SGtYoZvfQfE3wKLh0Hd5ptqUFv3gvQ==
-electron-to-chromium@^1.3.591:
- version "1.3.612"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.612.tgz#4a49864b9de694403a69d5a9f439cbceca543e48"
- integrity sha512-CdrdX1B6mQqxfw+51MPWB5qA6TKWjza9f5voBtUlRfEZEwZiFaxJLrhFI8zHE9SBAuGt4h84rQU6Ho9Bauo1LA==
+electron-to-chromium@^1.3.621:
+ version "1.3.633"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz#16dd5aec9de03894e8d14a1db4cda8a369b9b7fe"
+ integrity sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA==
emoji-regex@^7.0.1:
version "7.0.3"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
+es-abstract@^1.18.0-next.1:
+ version "1.18.0-next.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
+ integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
+ dependencies:
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+ is-callable "^1.2.2"
+ is-negative-zero "^2.0.0"
+ is-regex "^1.1.1"
+ object-inspect "^1.8.0"
+ object-keys "^1.1.1"
+ object.assign "^4.1.1"
+ string.prototype.trimend "^1.0.1"
+ string.prototype.trimstart "^1.0.1"
+
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
lodash.get "^4.4.2"
lodash.zip "^4.2.0"
-eslint-config-prettier@6.13.0:
- version "6.13.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.13.0.tgz#207d88796b5624e5bb815bbbdfc5891ceb9ebffa"
- integrity sha512-LcT0i0LSmnzqK2t764pyIt7kKH2AuuqKRTtJTdddWxOiUja9HdG5GXBVF2gmCTvVYWVsTu8J2MhJLVGRh+pj8w==
- dependencies:
- get-stdin "^6.0.0"
+eslint-config-prettier@7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz#5402eb559aa94b894effd6bddfa0b1ca051c858f"
+ integrity sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==
eslint-import-resolver-node@^0.3.4:
version "0.3.4"
resolve "^1.17.0"
tsconfig-paths "^3.9.0"
-eslint-plugin-jane@^9.0.4:
- version "9.0.4"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jane/-/eslint-plugin-jane-9.0.4.tgz#57ef9c1c1b86213b782ade988374b27533cc18c8"
- integrity sha512-29ceI3RjUfjRnObnw4xr9tiMHeWhVHxqwyh6lFi8FkUxkId6f6aklmQGm+ZUap9V545Dg5WDKzr89BPzBl165w==
+eslint-plugin-jane@^9.0.6:
+ version "9.0.6"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jane/-/eslint-plugin-jane-9.0.6.tgz#eeef17db748ef4cdacf66a54d08e5b1e99b7372b"
+ integrity sha512-TREFB1cewQqx4Bv6I1hAZ3oYmWPFAwUdEV8Kh2bvuGpA1V2hGWEJi6XqLUUkuo+hyVRYcceQp4MGYdgj0PtbLg==
dependencies:
- "@typescript-eslint/eslint-plugin" "4.5.0"
- "@typescript-eslint/parser" "4.5.0"
+ "@typescript-eslint/eslint-plugin" "4.11.0"
+ "@typescript-eslint/parser" "4.11.0"
babel-eslint "10.1.0"
- eslint-config-prettier "6.13.0"
+ eslint-config-prettier "7.1.0"
eslint-plugin-babel "5.3.1"
eslint-plugin-import "2.22.1"
- eslint-plugin-jest "24.1.0"
- eslint-plugin-jsx-a11y "6.3.1"
+ eslint-plugin-jest "24.1.3"
+ eslint-plugin-jsx-a11y "6.4.1"
eslint-plugin-node "11.1.0"
- eslint-plugin-prettier "3.1.4"
+ eslint-plugin-prettier "3.3.0"
eslint-plugin-promise "4.2.1"
eslint-plugin-react "7.21.5"
eslint-plugin-react-hooks "4.2.0"
- eslint-plugin-unicorn "21.0.0"
+ eslint-plugin-unicorn "24.0.0"
-eslint-plugin-jest@24.1.0:
- version "24.1.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.0.tgz#6708037d7602e5288ce877fd0103f329dc978361"
- integrity sha512-827YJ+E8B9PvXu/0eiVSNFfxxndbKv+qE/3GSMhdorCaeaOehtqHGX2YDW9B85TEOre9n/zscledkFW/KbnyGg==
+eslint-plugin-jest@24.1.3:
+ version "24.1.3"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz#fa3db864f06c5623ff43485ca6c0e8fc5fe8ba0c"
+ integrity sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg==
dependencies:
"@typescript-eslint/experimental-utils" "^4.0.1"
-eslint-plugin-jsx-a11y@6.3.1:
- version "6.3.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.3.1.tgz#99ef7e97f567cc6a5b8dd5ab95a94a67058a2660"
- integrity sha512-i1S+P+c3HOlBJzMFORRbC58tHa65Kbo8b52/TwCwSKLohwvpfT5rm2GjGWzOHTEuq4xxf2aRlHHTtmExDQOP+g==
+eslint-plugin-jsx-a11y@6.4.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd"
+ integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==
dependencies:
- "@babel/runtime" "^7.10.2"
+ "@babel/runtime" "^7.11.2"
aria-query "^4.2.2"
array-includes "^3.1.1"
ast-types-flow "^0.0.7"
- axe-core "^3.5.4"
- axobject-query "^2.1.2"
+ axe-core "^4.0.2"
+ axobject-query "^2.2.0"
damerau-levenshtein "^1.0.6"
emoji-regex "^9.0.0"
has "^1.0.3"
- jsx-ast-utils "^2.4.1"
+ jsx-ast-utils "^3.1.0"
language-tags "^1.0.5"
eslint-plugin-node@11.1.0:
resolve "^1.10.1"
semver "^6.1.0"
-eslint-plugin-prettier@3.1.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2"
- integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==
+eslint-plugin-prettier@3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz#61e295349a65688ffac0b7808ef0a8244bdd8d40"
+ integrity sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==
dependencies:
prettier-linter-helpers "^1.0.0"
resolve "^1.18.1"
string.prototype.matchall "^4.0.2"
-eslint-plugin-unicorn@21.0.0:
- version "21.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-21.0.0.tgz#7e3a8b0f725f003619e1f40d769939ecd8d708d0"
- integrity sha512-S8v7+v4gZTQPj4pKKvexhgSUaLQSyItvxW2SVZDaX9Iu5IjlAmF2eni+L6w8a2aqshxgU8Lle4FIAVDtuejSKQ==
+eslint-plugin-unicorn@24.0.0:
+ version "24.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-24.0.0.tgz#08017ccd7ac704777d459cff6e13a35f54cbcab1"
+ integrity sha512-NfLjIZas/ZUwc3S+pUtbTRqgCkODxPEkJBJ5ZR8wIu90BmX4jmXp10hoOZMScR2CR1NYTtrx0OX4BQvBnbzZzA==
dependencies:
ci-info "^2.0.0"
clean-regexp "^1.0.0"
eslint-ast-utils "^1.1.0"
- eslint-template-visitor "^2.0.0"
+ eslint-template-visitor "^2.2.1"
eslint-utils "^2.1.0"
import-modules "^2.0.0"
- lodash "^4.17.15"
+ lodash "^4.17.20"
pluralize "^8.0.0"
read-pkg-up "^7.0.1"
regexp-tree "^0.1.21"
reserved-words "^0.1.2"
safe-regex "^2.1.1"
- semver "^7.3.2"
+ semver "^7.3.4"
eslint-rule-composer@^0.3.0:
version "0.3.0"
esrecurse "^4.3.0"
estraverse "^4.1.1"
-eslint-template-visitor@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/eslint-template-visitor/-/eslint-template-visitor-2.2.1.tgz#2dccb1ab28fa7429e56ba6dd0144def2d89bc2d6"
- integrity sha512-q3SxoBXz0XjPGkUpwGVAwIwIPIxzCAJX1uwfVc8tW3v7u/zS7WXNH3I2Mu2MDz2NgSITAyKLRaQFPHu/iyKxDQ==
+eslint-template-visitor@^2.2.1:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-template-visitor/-/eslint-template-visitor-2.2.2.tgz#46cd2b06eca5c1d97369aadd96e131df88fdd59c"
+ integrity sha512-SkcLjzKw3JjKTWHacRDeLBa2gxb600zbCKTkXj/V97QnZ9yxkknoPL8vc8PFueqbFXP7mYNTQzjCjcMpTRdRaA==
dependencies:
babel-eslint "^10.1.0"
- eslint-visitor-keys "^1.3.0"
+ eslint-visitor-keys "^2.0.0"
esquery "^1.3.1"
multimap "^1.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint@^7.15.0:
- version "7.15.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.15.0.tgz#eb155fb8ed0865fcf5d903f76be2e5b6cd7e0bc7"
- integrity sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==
+eslint@^7.16.0:
+ version "7.16.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092"
+ integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==
dependencies:
"@babel/code-frame" "^7.0.0"
"@eslint/eslintrc" "^0.2.2"
semver "^7.2.1"
strip-ansi "^6.0.0"
strip-json-comments "^3.1.0"
- table "^5.2.3"
+ table "^6.0.4"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-intrinsic@^1.0.0, get-intrinsic@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
+ integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+
get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
-get-stdin@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
- integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
-
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
dependencies:
ms "^2.0.0"
-husky@^4.3.5:
- version "4.3.5"
- resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.5.tgz#ab8d2a0eb6b62fef2853ee3d442c927d89290902"
- integrity sha512-E5S/1HMoDDaqsH8kDF5zeKEQbYqe3wL9zJDyqyYqc8I4vHBtAoxkDBGXox0lZ9RI+k5GyB728vZdmnM4bYap+g==
+husky@^4.3.6:
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.6.tgz#ebd9dd8b9324aa851f1587318db4cccb7665a13c"
+ integrity sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==
dependencies:
chalk "^4.0.0"
ci-info "^2.0.0"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
+is-callable@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
+ integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
+
is-ci@^1.0.10:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
json-schema "0.2.3"
verror "1.10.0"
-jsx-ast-utils@^2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
- integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==
- dependencies:
- array-includes "^3.1.1"
- object.assign "^4.1.0"
-
"jsx-ast-utils@^2.4.1 || ^3.0.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz#642f1d7b88aa6d7eb9d8f2210e166478444fa891"
array-includes "^3.1.1"
object.assign "^4.1.1"
+jsx-ast-utils@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
+ integrity sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==
+ dependencies:
+ array-includes "^3.1.2"
+ object.assign "^4.1.2"
+
jwt-decode@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
dependencies:
invert-kv "^1.0.0"
-lemmy-js-client@^1.0.16:
- version "1.0.16"
- resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.16.tgz#84bf094c246d987f2f192bfac75340430821fee9"
- integrity sha512-WvEEGrYNA2dzfzlufWB9LhUcll0O06WaUjSfBn5lYY/SFFsvBW5ImD42P/QwvN8Sgj6xVQiboe+Z8T++iAjKVw==
+lemmy-js-client@1.0.17-beta6:
+ version "1.0.17-beta6"
+ resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.17-beta6.tgz#afe1e1da13172a161c4d976b1ee58fe81eb22829"
+ integrity sha512-+oX7J7wht8nH4a5NQngK1GNner3TDv6ZOhQQVI5KcK7vynVVIcgveC5KBJArHBAl5acXpLs3Khmx0ZEb+sErJA==
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"
integrity sha1-y5yf+RpSVawI8/09YyhuFd8KH8M=
-markdown-it@^12.0.3:
- version "12.0.3"
- resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.3.tgz#8d1e47daf1d716d63610495eb93f6665573e4abe"
- integrity sha512-M57RsMv+QQmJHz1yCu0gTJRMx/LlxRPtrrw+2kb/CpDVK/graCmWO0qfNnz/SE1FCNdyq3pkMMZ+itTnyT/YGA==
+markdown-it@^12.0.4:
+ version "12.0.4"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.4.tgz#eec8247d296327eac3ba9746bdeec9cfcc751e33"
+ integrity sha512-34RwOXZT8kyuOJy25oJNJoulO8L0bTHYWXcdZBYZqFnjIy3NgjeoM3FmPXIOFQ26/lSHYMr8oc62B6adxXcb3Q==
dependencies:
argparse "^2.0.1"
entities "~2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-mini-css-extract-plugin@^1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.2.tgz#e2c9c0ef3f7c1a516916a3ab7b073a761e5b1d26"
- integrity sha512-ofYJgCZNm1TToSv02pGANe1lfb31g7ULwNV5Nt31d2dAnVLxFHoguDUAj6U0BLEO7Nrztq4mdtL1yFDaeW7J+A==
+mini-css-extract-plugin@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.3.tgz#7802e62b34199aa7d1a62e654395859a836486a0"
+ integrity sha512-7lvliDSMiuZc81kI+5/qxvn47SCM7BehXex3f2c6l/pR3Goj58IQxZh9nuPQ3AkGQgoETyXuIqLDaO5Oa0TyBw==
dependencies:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-minipass-collect@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
- integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
- dependencies:
- minipass "^3.0.0"
-
-minipass-flush@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
- integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
- dependencies:
- minipass "^3.0.0"
-
-minipass-pipeline@^1.2.2:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
- integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
- dependencies:
- minipass "^3.0.0"
-
minipass@^2.3.3, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
safe-buffer "^5.1.2"
yallist "^3.0.0"
-minipass@^3.0.0, minipass@^3.1.1:
+minipass@^3.0.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd"
integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==
dependencies:
minimist "^1.2.5"
-mkdirp@^1.0.3, mkdirp@^1.0.4:
+mkdirp@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.64.tgz#71b4ae988e9b1dd7c1ffce58dd9e561752dfebc5"
integrity sha512-Iec8O9166/x2HRMJyLLLWkd0sFFLrFNy+Xf+JQfSQsdBJzPcHpNl3JQ9gD4j+aJxmCa25jNsIbM4bmACtSbkSg==
-node-releases@^1.1.66:
+node-releases@^1.1.67:
version "1.1.67"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12"
integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==
has-symbols "^1.0.1"
object-keys "^1.1.1"
+object.assign@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+ integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+ has-symbols "^1.0.1"
+ object-keys "^1.1.1"
+
object.entries@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
unicode-match-property-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript "^1.2.0"
-register-service-worker@^1.7.1:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/register-service-worker/-/register-service-worker-1.7.1.tgz#6308347ac6c0af0f6c0b22ea5d59d25e836bc932"
- integrity sha512-IdTfUZ4u8iJL8o1w8es8l6UMGPmkwHolUdT+UmM1UypC80IB4KbpuIlvwWVj8UDS7eJwkEYRcKRgfRX+oTmJsw==
+register-service-worker@^1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/register-service-worker/-/register-service-worker-1.7.2.tgz#6516983e1ef790a98c4225af1216bc80941a4bd2"
+ integrity sha512-CiD3ZSanZqcMPRhtfct5K9f7i3OLCcBBWsJjLh1gW9RO/nS94sVzY59iS+fgYBOBqaBpf4EzfqUF3j9IG+xo8A==
registry-auth-token@^3.0.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.8.1:
+resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+semver@^7.3.4:
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
+ integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
+ dependencies:
+ lru-cache "^6.0.0"
+
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
-slice-ansi@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
- integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
- dependencies:
- ansi-styles "^3.2.0"
- astral-regex "^1.0.0"
- is-fullwidth-code-point "^2.0.0"
-
slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
from2 "^1.3.0"
stream-iterate "^1.1.0"
-sortpack@^2.1.10:
- version "2.1.10"
- resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.1.10.tgz#eb23257ff2db47954b0a7c3e4c84f71f1e32fac1"
- integrity sha512-gJcTUZoIZoFDxyVhy+aJeUoknzs27K+EAuO+gTkWqxLZuiQYlgL1yu7u0B9cqMqavZcFMXcpmPBgovsDJXe3Fw==
+sortpack@^2.1.11:
+ version "2.1.11"
+ resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.1.11.tgz#afef2312f411f646707150b6659b4fb3499a7422"
+ integrity sha512-gm8tL0UDg4lO5KM6m/lWxoXYSNEJT4jEXuvxaqsc6kScOqJECU7tcmxWhgUY1tiQFhOO6jY4RaYUn2HPmZVSYA==
source-list-map@^2.0.0, source-list-map@^2.0.1:
version "2.0.1"
dependencies:
figgy-pudding "^3.5.1"
-ssri@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808"
- integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==
- dependencies:
- minipass "^3.1.1"
-
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
typical "^5.2.0"
wordwrapjs "^4.0.0"
-table@^5.2.3:
- version "5.4.6"
- resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
- integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+table@^6.0.4:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/table/-/table-6.0.4.tgz#c523dd182177e926c723eb20e1b341238188aa0d"
+ integrity sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==
dependencies:
- ajv "^6.10.2"
- lodash "^4.17.14"
- slice-ansi "^2.1.0"
- string-width "^3.0.0"
+ ajv "^6.12.4"
+ lodash "^4.17.20"
+ slice-ansi "^4.0.0"
+ string-width "^4.2.0"
tapable@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9"
- integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==
+typescript@^4.1.3:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7"
+ integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
typical@^5.0.0, typical@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d"
integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==
-webpack-sources@^1.1.0, webpack-sources@^1.4.3:
+webpack-sources@^1.1.0:
version "1.4.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
source-list-map "^2.0.1"
source-map "^0.6.1"
-webpack@5.10.0:
- version "5.10.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.10.0.tgz#6f77c31522a2c525152d9c344f9765d168b3df08"
- integrity sha512-P0bHAXmIz0zsNcHNLqFmLY1ZtrT+jtBr7FqpuDtA2o7GiHC+zBsfhgK7SmJ1HG7BAEb3G9JoMdSVi7mEDvG3Zg==
+webpack@5.11.0:
+ version "5.11.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.11.0.tgz#1647abc060441d86d01d8835b8f0fc1dae2fe76f"
+ integrity sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.45"
- "@webassemblyjs/ast" "1.9.0"
- "@webassemblyjs/helper-module-context" "1.9.0"
- "@webassemblyjs/wasm-edit" "1.9.0"
- "@webassemblyjs/wasm-parser" "1.9.0"
+ "@webassemblyjs/ast" "1.9.1"
+ "@webassemblyjs/helper-module-context" "1.9.1"
+ "@webassemblyjs/wasm-edit" "1.9.1"
+ "@webassemblyjs/wasm-parser" "1.9.1"
acorn "^8.0.4"
browserslist "^4.14.5"
chrome-trace-event "^1.0.2"