From d905c91e1b0487f3bcfd0595f6cab62906f1aead Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 21 Jun 2022 17:42:29 -0400 Subject: [PATCH] Adding option types 2 (#689) * Not working, because of wrong API types. * Adding Rust-style Result and Option types. - Fixes #646 * Updating to use new lemmy-js-client with Options. --- package.json | 6 +- src/client/index.tsx | 7 +- src/server/index.tsx | 19 +- src/shared/components/app/app.tsx | 57 +- src/shared/components/app/footer.tsx | 4 +- src/shared/components/app/navbar.tsx | 383 ++++---- src/shared/components/app/theme.tsx | 22 +- .../components/comment/comment-form.tsx | 101 +- .../components/comment/comment-node.tsx | 862 +++++++++-------- .../components/comment/comment-nodes.tsx | 17 +- .../components/comment/comment-report.tsx | 47 +- .../components/common/banner-icon-header.tsx | 31 +- src/shared/components/common/html-tags.tsx | 16 +- .../components/common/image-upload-form.tsx | 48 +- .../components/common/listing-type-select.tsx | 8 +- .../components/common/markdown-textarea.tsx | 167 ++-- src/shared/components/common/moment-time.tsx | 36 +- .../common/registration-application.tsx | 75 +- .../components/community/communities.tsx | 186 ++-- .../components/community/community-form.tsx | 184 ++-- .../components/community/community-link.tsx | 10 +- src/shared/components/community/community.tsx | 460 +++++---- .../components/community/create-community.tsx | 27 +- src/shared/components/community/sidebar.tsx | 136 ++- src/shared/components/home/admin-settings.tsx | 108 ++- src/shared/components/home/home.tsx | 434 +++++---- src/shared/components/home/instances.tsx | 53 +- src/shared/components/home/legal.tsx | 22 +- src/shared/components/home/login.tsx | 37 +- src/shared/components/home/setup.tsx | 31 +- src/shared/components/home/signup.tsx | 565 ++++++----- src/shared/components/home/site-form.tsx | 227 +++-- src/shared/components/home/site-sidebar.tsx | 96 +- src/shared/components/modlog.tsx | 210 ++--- src/shared/components/person/inbox.tsx | 368 +++++--- .../components/person/password-change.tsx | 24 +- .../components/person/person-details.tsx | 17 +- .../components/person/person-listing.tsx | 18 +- src/shared/components/person/profile.tsx | 884 ++++++++++-------- .../person/registration-applications.tsx | 119 ++- src/shared/components/person/reports.tsx | 205 ++-- src/shared/components/person/settings.tsx | 354 ++++--- src/shared/components/person/verify-email.tsx | 24 +- src/shared/components/post/create-post.tsx | 187 ++-- src/shared/components/post/metadata-card.tsx | 115 ++- src/shared/components/post/post-form.tsx | 506 +++++----- src/shared/components/post/post-listing.tsx | 660 +++++++------ src/shared/components/post/post-listings.tsx | 86 +- src/shared/components/post/post-report.tsx | 45 +- src/shared/components/post/post.tsx | 544 ++++++----- .../create-private-message.tsx | 97 +- .../private_message/private-message-form.tsx | 68 +- .../private_message/private-message.tsx | 55 +- src/shared/components/search.tsx | 474 ++++++---- src/shared/interfaces.ts | 17 +- src/shared/services/UserService.ts | 57 +- src/shared/services/WebSocketService.ts | 6 +- src/shared/utils.ts | 497 ++++++---- tsconfig.json | 3 +- yarn.lock | 148 ++- 60 files changed, 5834 insertions(+), 4436 deletions(-) diff --git a/package.json b/package.json index a76700b..f6ea01c 100644 --- a/package.json +++ b/package.json @@ -52,11 +52,13 @@ }, "devDependencies": { "@babel/core": "^7.17.9", + "@babel/plugin-proposal-decorators": "^7.18.2", "@babel/plugin-transform-runtime": "^7.17.0", "@babel/plugin-transform-typescript": "^7.16.1", "@babel/preset-env": "7.16.11", "@babel/preset-typescript": "^7.16.0", "@babel/runtime": "^7.17.9", + "@sniptt/monads": "^0.5.10", "@types/autosize": "^4.0.0", "@types/express": "^4.17.13", "@types/node": "^17.0.29", @@ -67,6 +69,7 @@ "babel-plugin-inferno": "^6.4.0", "bootstrap": "^5.1.3", "bootswatch": "^5.1.3", + "class-transformer": "^0.5.1", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^10.2.4", "css-loader": "^6.7.1", @@ -74,7 +77,7 @@ "eslint-plugin-prettier": "^4.0.0", "husky": "^7.0.4", "import-sort-style-module": "^6.0.0", - "lemmy-js-client": "0.16.4", + "lemmy-js-client": "0.17.0-rc.30", "lint-staged": "^12.4.1", "mini-css-extract-plugin": "^2.6.0", "node-fetch": "^2.6.1", @@ -82,6 +85,7 @@ "prettier-plugin-import-sort": "^0.0.7", "prettier-plugin-organize-imports": "^2.3.4", "prettier-plugin-packagejson": "^2.2.17", + "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "run-node-webpack-plugin": "^1.3.0", "sass-loader": "^12.6.0", diff --git a/src/client/index.tsx b/src/client/index.tsx index d5773b4..3838dca 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -1,14 +1,15 @@ import { hydrate } from "inferno-hydrate"; import { BrowserRouter } from "inferno-router"; +import { GetSiteResponse } from "lemmy-js-client"; import { App } from "../shared/components/app/app"; -import { initializeSite } from "../shared/utils"; +import { convertWindowJson, initializeSite } from "../shared/utils"; -const site = window.isoData.site_res; +const site = convertWindowJson(GetSiteResponse, window.isoData.site_res); initializeSite(site); const wrapper = ( - + ); diff --git a/src/server/index.tsx b/src/server/index.tsx index 65f7308..374fb03 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -1,3 +1,5 @@ +import { None, Option } from "@sniptt/monads"; +import { serialize as serializeO } from "class-transformer"; import express from "express"; import fs from "fs"; import { IncomingHttpHeaders } from "http"; @@ -5,7 +7,7 @@ import { Helmet } from "inferno-helmet"; import { matchPath, StaticRouter } from "inferno-router"; import { renderToString } from "inferno-server"; import IsomorphicCookie from "isomorphic-cookie"; -import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client"; +import { GetSite, GetSiteResponse, LemmyHttp, toOption } from "lemmy-js-client"; import path from "path"; import process from "process"; import serialize from "serialize-javascript"; @@ -18,7 +20,7 @@ import { IsoData, } from "../shared/interfaces"; import { routes } from "../shared/routes"; -import { initializeSite, setOptionalAuth } from "../shared/utils"; +import { initializeSite } from "../shared/utils"; const server = express(); const [hostname, port] = process.env["LEMMY_UI_HOST"] @@ -115,10 +117,9 @@ server.get("/*", async (req, res) => { try { const activeRoute = routes.find(route => matchPath(req.path, route)) || {}; const context = {} as any; - let auth: string = IsomorphicCookie.load("jwt", req); + let auth: Option = toOption(IsomorphicCookie.load("jwt", req)); - let getSiteForm: GetSite = {}; - setOptionalAuth(getSiteForm, auth); + let getSiteForm = new GetSite({ auth }); let promises: Promise[] = []; @@ -138,8 +139,8 @@ server.get("/*", async (req, res) => { console.error( "Incorrect JWT token, skipping auth so frontend can remove jwt cookie" ); - delete getSiteForm.auth; - delete initialFetchReq.auth; + getSiteForm.auth = None; + initialFetchReq.auth = None; try_site = await initialFetchReq.client.getSite(getSiteForm); } let site: GetSiteResponse = try_site; @@ -170,7 +171,7 @@ server.get("/*", async (req, res) => { const wrapper = ( - + ); if (context.url) { @@ -194,7 +195,7 @@ server.get("/*", async (req, res) => { - + diff --git a/src/shared/components/app/app.tsx b/src/shared/components/app/app.tsx index 9ddff69..72119a8 100644 --- a/src/shared/components/app/app.tsx +++ b/src/shared/components/app/app.tsx @@ -2,53 +2,46 @@ import { Component } from "inferno"; import { Helmet } from "inferno-helmet"; import { Provider } from "inferno-i18next-dess"; import { Route, Switch } from "inferno-router"; -import { GetSiteResponse } from "lemmy-js-client"; import { i18n } from "../../i18next"; import { routes } from "../../routes"; -import { favIconPngUrl, favIconUrl } from "../../utils"; +import { favIconPngUrl, favIconUrl, setIsoData } from "../../utils"; import { Footer } from "./footer"; import { Navbar } from "./navbar"; import { NoMatch } from "./no-match"; import "./styles.scss"; import { Theme } from "./theme"; -export interface AppProps { - siteRes: GetSiteResponse; -} - -export class App extends Component { +export class App extends Component { + private isoData = setIsoData(this.context); constructor(props: any, context: any) { super(props, context); } render() { - let siteRes = this.props.siteRes; + let siteRes = this.isoData.site_res; + let siteView = siteRes.site_view; + return ( <>
- - {siteRes && - siteRes.site_view && - this.props.siteRes.site_view.site.icon && ( - - - - - )} - + s.site.default_theme)} /> + {siteView + .andThen(s => s.site.icon) + .match({ + some: icon => ( + + + + + ), + none: <>, + })} +
{routes.map(({ path, exact, component: C, ...rest }) => ( @@ -62,7 +55,7 @@ export class App extends Component { } />
-
+
diff --git a/src/shared/components/app/footer.tsx b/src/shared/components/app/footer.tsx index 601551b..e5e1db5 100644 --- a/src/shared/components/app/footer.tsx +++ b/src/shared/components/app/footer.tsx @@ -32,7 +32,9 @@ export class Footer extends Component { {i18n.t("modlog")} - {this.props.site.site_view?.site.legal_information && ( + {this.props.site.site_view + .andThen(s => s.site.legal_information) + .isSome() && (
  • {i18n.t("legal_information")} diff --git a/src/shared/components/app/navbar.tsx b/src/shared/components/app/navbar.tsx index 9ab3b65..604a90a 100644 --- a/src/shared/components/app/navbar.tsx +++ b/src/shared/components/app/navbar.tsx @@ -1,3 +1,4 @@ +import { None, Some } from "@sniptt/monads"; import { Component, createRef, linkEvent, RefObject } from "inferno"; import { NavLink } from "inferno-router"; import { @@ -11,12 +12,15 @@ import { GetUnreadRegistrationApplicationCountResponse, PrivateMessageResponse, UserOperation, + wsJsonToRes, + wsUserOp, } from "lemmy-js-client"; import { Subscription } from "rxjs"; import { i18n } from "../../i18next"; import { UserService, WebSocketService } from "../../services"; import { - authField, + amAdmin, + auth, donateLemmyUrl, getLanguages, isBrowser, @@ -27,19 +31,16 @@ import { showAvatars, toast, wsClient, - wsJsonToRes, wsSubscribe, - wsUserOp, } from "../../utils"; import { Icon } from "../common/icon"; import { PictrsImage } from "../common/pictrs-image"; interface NavbarProps { - site_res: GetSiteResponse; + siteRes: GetSiteResponse; } interface NavbarState { - isLoggedIn: boolean; expanded: boolean; unreadInboxCount: number; unreadReportCount: number; @@ -58,7 +59,6 @@ export class Navbar extends Component { private unreadApplicationCountSub: Subscription; private searchTextField: RefObject; emptyState: NavbarState = { - isLoggedIn: !!this.props.site_res.my_user, unreadInboxCount: 0, unreadReportCount: 0, unreadApplicationCount: 0, @@ -81,18 +81,13 @@ export class Navbar extends Component { // Subscribe to jwt changes if (isBrowser()) { this.searchTextField = createRef(); - console.log(`isLoggedIn = ${this.state.isLoggedIn}`); // On the first load, check the unreads - if (this.state.isLoggedIn == false) { - // setTheme(data.my_user.theme, true); - // i18n.changeLanguage(getLanguage()); - // i18n.changeLanguage('de'); - } else { + if (UserService.Instance.myUserInfo.isSome()) { this.requestNotificationPermission(); WebSocketService.Instance.send( wsClient.userJoin({ - auth: authField(), + auth: auth().unwrap(), }) ); this.fetchUnreads(); @@ -100,13 +95,11 @@ export class Navbar extends Component { this.userSub = UserService.Instance.jwtSub.subscribe(res => { // A login - if (res !== undefined) { + if (res.isSome()) { this.requestNotificationPermission(); WebSocketService.Instance.send( - wsClient.getSite({ auth: authField() }) + wsClient.getSite({ auth: res.map(r => r.jwt) }) ); - } else { - this.setState({ isLoggedIn: false }); } }); @@ -157,32 +150,28 @@ export class Navbar extends Component { // TODO class active corresponding to current page navbar() { - let myUserInfo = - UserService.Instance.myUserInfo || this.props.site_res.my_user; - let person = myUserInfo?.local_user_view.person; return ( -
  • - - )} - - + + ), + none: <>, + })} ) : (