]> Untitled Git - lemmy-ui.git/commitdiff
Adding new site setup fields. (#840)
authorDessalines <dessalines@users.noreply.github.com>
Wed, 9 Nov 2022 19:53:07 +0000 (14:53 -0500)
committerGitHub <noreply@github.com>
Wed, 9 Nov 2022 19:53:07 +0000 (14:53 -0500)
34 files changed:
dev.dockerfile [new file with mode: 0644]
lemmy-translations
package.json
src/shared/components/app/app.tsx
src/shared/components/app/footer.tsx
src/shared/components/app/navbar.tsx
src/shared/components/app/theme.tsx
src/shared/components/community/communities.tsx
src/shared/components/community/community.tsx
src/shared/components/community/create-community.tsx
src/shared/components/home/admin-settings.tsx
src/shared/components/home/home.tsx
src/shared/components/home/instances.tsx
src/shared/components/home/legal.tsx
src/shared/components/home/login.tsx
src/shared/components/home/setup.tsx
src/shared/components/home/signup.tsx
src/shared/components/home/site-form.tsx
src/shared/components/home/site-sidebar.tsx
src/shared/components/modlog.tsx
src/shared/components/person/inbox.tsx
src/shared/components/person/password-change.tsx
src/shared/components/person/profile.tsx
src/shared/components/person/registration-applications.tsx
src/shared/components/person/reports.tsx
src/shared/components/person/settings.tsx
src/shared/components/person/verify-email.tsx
src/shared/components/post/create-post.tsx
src/shared/components/post/post.tsx
src/shared/components/search.tsx
src/shared/services/UserService.ts
src/shared/utils.ts
tsconfig.json
yarn.lock

diff --git a/dev.dockerfile b/dev.dockerfile
new file mode 100644 (file)
index 0000000..51bcd26
--- /dev/null
@@ -0,0 +1,32 @@
+FROM node:alpine as builder\r
+RUN apk update && apk add curl yarn python3 build-base gcc wget git --no-cache\r
+\r
+WORKDIR /usr/src/app\r
+\r
+# Cache deps\r
+COPY package.json yarn.lock ./\r
+RUN yarn install --ignore-scripts --prefer-offline --pure-lockfile\r
+\r
+# Build\r
+COPY generate_translations.js \\r
+  tsconfig.json \\r
+  webpack.config.js \\r
+  .babelrc \\r
+  ./\r
+\r
+COPY lemmy-translations lemmy-translations\r
+COPY src src\r
+\r
+# Set UI version \r
+RUN echo "export const VERSION = 'dev';" > "src/shared/version.ts"\r
+\r
+RUN yarn install --ignore-scripts --prefer-offline\r
+RUN yarn build:dev\r
+\r
+FROM node:alpine as runner\r
+COPY --from=builder /usr/src/app/dist /app/dist\r
+COPY --from=builder /usr/src/app/node_modules /app/node_modules\r
+\r
+EXPOSE 1234\r
+WORKDIR /app\r
+CMD node dist/js/server.js\r
index 94b9b5debdaa40facf13a852cb096ef0cbd34ad7..46f4b3e8676c23d4a8100ce78330eceed7bcf053 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 94b9b5debdaa40facf13a852cb096ef0cbd34ad7
+Subproject commit 46f4b3e8676c23d4a8100ce78330eceed7bcf053
index 1c1c8ff8627c5aa14acfabc2657eaf23c58424d4..8b64e5a746942f6ef0dcc8d29ecda2d5972d6baa 100644 (file)
@@ -24,7 +24,6 @@
     "@babel/preset-typescript": "^7.18.6",
     "@babel/runtime": "^7.18.9",
     "@sniptt/monads": "^0.5.10",
-    "@typescript-eslint/parser": "^5.31.0",
     "autosize": "^5.0.1",
     "babel-loader": "^8.2.5",
     "babel-plugin-inferno": "^6.5.0",
@@ -48,7 +47,7 @@
     "inferno-server": "^8.0.3",
     "isomorphic-cookie": "^1.2.4",
     "jwt-decode": "^3.1.2",
-    "lemmy-js-client": "0.17.0-rc.46",
+    "lemmy-js-client": "0.17.0-rc.51",
     "markdown-it": "^13.0.1",
     "markdown-it-container": "^3.0.0",
     "markdown-it-footnote": "^3.0.3",
@@ -82,6 +81,7 @@
     "@types/node-fetch": "^2.6.2",
     "@types/serialize-javascript": "^5.0.1",
     "@typescript-eslint/eslint-plugin": "^5.31.0",
+    "@typescript-eslint/parser": "^5.31.0",
     "bootstrap": "^5.2.0",
     "bootswatch": "^5.2.0",
     "eslint": "^8.20.0",
index 960f6badda7b4e50c8ca3058e7c612716c02daa2..70e21a93b62499d70448753f169522d6199c4838 100644 (file)
@@ -24,23 +24,21 @@ export class App extends Component<any, any> {
       <>
         <Provider i18next={i18n}>
           <div>
-            <Theme defaultTheme={siteView.map(s => s.site.default_theme)} />
-            {siteView
-              .andThen(s => s.site.icon)
-              .match({
-                some: icon => (
-                  <Helmet>
-                    <link
-                      id="favicon"
-                      rel="shortcut icon"
-                      type="image/x-icon"
-                      href={icon || favIconUrl}
-                    />
-                    <link rel="apple-touch-icon" href={icon || favIconPngUrl} />
-                  </Helmet>
-                ),
-                none: <></>,
-              })}
+            <Theme defaultTheme={siteView.local_site.default_theme} />
+            {siteView.site.icon.match({
+              some: icon => (
+                <Helmet>
+                  <link
+                    id="favicon"
+                    rel="shortcut icon"
+                    type="image/x-icon"
+                    href={icon || favIconUrl}
+                  />
+                  <link rel="apple-touch-icon" href={icon || favIconPngUrl} />
+                </Helmet>
+              ),
+              none: <></>,
+            })}
             <Navbar siteRes={siteRes} />
             <div className="mt-4 p-0 fl-1">
               <Switch>
index b40d7285b3c85458aeb1d75cc06327bd8d57deca..8a7f3bd9a8ba614707be548485657e5efb7d1f71 100644 (file)
@@ -32,9 +32,7 @@ export class Footer extends Component<FooterProps, any> {
                 {i18n.t("modlog")}
               </NavLink>
             </li>
-            {this.props.site.site_view
-              .andThen(s => s.site.legal_information)
-              .isSome() && (
+            {this.props.site.site_view.local_site.legal_information.isSome() && (
               <li className="nav-item">
                 <NavLink className="nav-link" to="/legal">
                   {i18n.t("legal_information")}
index 4607b5adfcfa81b34dea6727ef6f23e6124c1f1d..ec68e99b27b457f3351d754aea9a8254a34afe6d 100644 (file)
@@ -90,9 +90,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
           })
         );
 
-        if (this.props.siteRes.site_view.isSome()) {
-          this.fetchUnreads();
-        }
+        this.fetchUnreads();
       }
 
       this.requestNotificationPermission();
@@ -144,27 +142,22 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
 
   // TODO class active corresponding to current page
   navbar() {
+    let siteView = this.props.siteRes.site_view;
     return (
       <nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
         <div className="container-lg">
-          {this.props.siteRes.site_view.match({
-            some: siteView => (
-              <NavLink
-                to="/"
-                onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
-                title={siteView.site.description.unwrapOr(siteView.site.name)}
-                className="d-flex align-items-center navbar-brand mr-md-3"
-              >
-                {siteView.site.icon.match({
-                  some: icon =>
-                    showAvatars() && <PictrsImage src={icon} icon />,
-                  none: <></>,
-                })}
-                {siteView.site.name}
-              </NavLink>
-            ),
-            none: <></>,
-          })}
+          <NavLink
+            to="/"
+            onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+            title={siteView.site.description.unwrapOr(siteView.site.name)}
+            className="d-flex align-items-center navbar-brand mr-md-3"
+          >
+            {siteView.site.icon.match({
+              some: icon => showAvatars() && <PictrsImage src={icon} icon />,
+              none: <></>,
+            })}
+            {siteView.site.name}
+          </NavLink>
           {UserService.Instance.myUserInfo.isSome() && (
             <>
               <ul className="navbar-nav ml-auto">
index a30358fe9786daa2163f08a3b3fca09f68a541e2..0f2a08302c2eab94ba8ab50b8e0534c236d4e036 100644 (file)
@@ -1,10 +1,9 @@
-import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
 import { Helmet } from "inferno-helmet";
 import { UserService } from "../../services";
 
 interface Props {
-  defaultTheme: Option<string>;
+  defaultTheme: string;
 }
 
 export class Theme extends Component<Props> {
@@ -26,16 +25,13 @@ export class Theme extends Component<Props> {
           />
         </Helmet>
       );
-    } else if (
-      this.props.defaultTheme.isSome() &&
-      this.props.defaultTheme.unwrap() != "browser"
-    ) {
+    } else if (this.props.defaultTheme != "browser") {
       return (
         <Helmet>
           <link
             rel="stylesheet"
             type="text/css"
-            href={`/css/themes/${this.props.defaultTheme.unwrap()}.css`}
+            href={`/css/themes/${this.props.defaultTheme}.css`}
           />
         </Helmet>
       );
index 25eb2a5f953690e2f7f068debad11f3a745ec394..c33963a08c7afa18a1dc6f2353deb57cc3ea9b49 100644 (file)
@@ -109,10 +109,9 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("communities")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("communities")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
index f01c584429b1dea517b5f8b581baab16849c9fd2..af0f7e6aaa515f3b928acb3592c9b85cbec5c0fd 100644 (file)
@@ -272,11 +272,7 @@ export class Community extends Component<any, State> {
   get documentTitle(): string {
     return this.state.communityRes.match({
       some: res =>
-        this.state.siteRes.site_view.match({
-          some: siteView =>
-            `${res.community_view.community.title} - ${siteView.site.name}`,
-          none: "",
-        }),
+        `${res.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`,
       none: "",
     });
   }
index 66bbe946183dd1c805384bbbed3d2489e330bab3..5065665a8c59f1b18e326f321c8075669565ed17 100644 (file)
@@ -48,10 +48,9 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("create_community")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("create_community")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
index be244e550ca9aa5cb559e6f11dcaf3745fec0e32..b077e8e720d276b85e23329785c6fcf3e381ef20 100644 (file)
@@ -1,4 +1,4 @@
-import { None, Some } from "@sniptt/monads";
+import { None } from "@sniptt/monads";
 import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
 import {
@@ -96,10 +96,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("admin_settings")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("admin_settings")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
@@ -118,15 +117,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
                 description={None}
                 image={None}
               />
-              {this.state.siteRes.site_view.match({
-                some: siteView => (
-                  <SiteForm
-                    site={Some(siteView.site)}
-                    showLocal={showLocal(this.isoData)}
-                  />
-                ),
-                none: <></>,
-              })}
+              <SiteForm
+                siteRes={this.state.siteRes}
+                showLocal={showLocal(this.isoData)}
+              />
             </div>
             <div className="col-12 col-md-6">
               {this.admins()}
@@ -201,7 +195,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
       return;
     } else if (op == UserOperation.EditSite) {
       let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
-      this.setState(s => ((s.siteRes.site_view = Some(data.site_view)), s));
+      this.setState(s => ((s.siteRes.site_view = data.site_view), s));
       toast(i18n.t("site_saved"));
     } else if (op == UserOperation.GetBannedPersons) {
       let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
index 6c2cc0a69e45b2f26738d2f0eee451ef0cdfc9a5..08176bb6ca9d6a33b9132419dff37b90a9289907 100644 (file)
@@ -131,10 +131,7 @@ export class Home extends Component<any, HomeState> {
     listingType: getListingTypeFromProps(
       this.props,
       ListingType[
-        this.isoData.site_res.site_view.match({
-          some: type_ => type_.site.default_post_listing_type,
-          none: ListingType.Local,
-        })
+        this.isoData.site_res.site_view.local_site.default_post_listing_type
       ]
     ),
     dataType: getDataTypeFromProps(this.props),
@@ -199,7 +196,7 @@ export class Home extends Component<any, HomeState> {
 
   componentDidMount() {
     // This means it hasn't been set up yet
-    if (this.state.siteRes.site_view.isNone()) {
+    if (!this.state.siteRes.site_view.local_site.site_setup) {
       this.context.router.history.push("/setup");
     }
     setupTippy();
@@ -313,13 +310,10 @@ export class Home extends Component<any, HomeState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        siteView.site.description.match({
-          some: desc => `${siteView.site.name} - ${desc}`,
-          none: siteView.site.name,
-        }),
-      none: "Lemmy",
+    let siteView = this.state.siteRes.site_view;
+    return this.state.siteRes.site_view.site.description.match({
+      some: desc => `${siteView.site.name} - ${desc}`,
+      none: siteView.site.name,
     });
   }
 
@@ -332,7 +326,7 @@ export class Home extends Component<any, HomeState> {
           description={None}
           image={None}
         />
-        {this.state.siteRes.site_view.isSome() && (
+        {this.state.siteRes.site_view.local_site.site_setup && (
           <div className="row">
             <main role="main" className="col-12 col-md-8">
               <div className="d-block d-md-none">{this.mobileView()}</div>
@@ -356,6 +350,7 @@ export class Home extends Component<any, HomeState> {
 
   mobileView() {
     let siteRes = this.state.siteRes;
+    let siteView = siteRes.site_view;
     return (
       <div className="row">
         <div className="col-12">
@@ -399,19 +394,15 @@ export class Home extends Component<any, HomeState> {
               classes="icon-inline"
             />
           </button>
-          {this.state.showSidebarMobile &&
-            siteRes.site_view.match({
-              some: siteView => (
-                <SiteSidebar
-                  site={siteView.site}
-                  admins={Some(siteRes.admins)}
-                  counts={Some(siteView.counts)}
-                  online={Some(siteRes.online)}
-                  showLocal={showLocal(this.isoData)}
-                />
-              ),
-              none: <></>,
-            })}
+          {this.state.showSidebarMobile && (
+            <SiteSidebar
+              site={siteView.site}
+              admins={Some(siteRes.admins)}
+              counts={Some(siteView.counts)}
+              online={Some(siteRes.online)}
+              showLocal={showLocal(this.isoData)}
+            />
+          )}
           {this.state.showTrendingMobile && (
             <div className="col-12 card border-secondary mb-3">
               <div className="card-body">{this.trendingCommunities()}</div>
@@ -429,6 +420,7 @@ export class Home extends Component<any, HomeState> {
 
   mySidebar() {
     let siteRes = this.state.siteRes;
+    let siteView = siteRes.site_view;
     return (
       <div>
         {!this.state.loading && (
@@ -441,18 +433,13 @@ export class Home extends Component<any, HomeState> {
                 {this.exploreCommunitiesButton()}
               </div>
             </div>
-            {siteRes.site_view.match({
-              some: siteView => (
-                <SiteSidebar
-                  site={siteView.site}
-                  admins={Some(siteRes.admins)}
-                  counts={Some(siteView.counts)}
-                  online={Some(siteRes.online)}
-                  showLocal={showLocal(this.isoData)}
-                />
-              ),
-              none: <></>,
-            })}
+            <SiteSidebar
+              site={siteView.site}
+              admins={Some(siteRes.admins)}
+              counts={Some(siteView.counts)}
+              online={Some(siteRes.online)}
+              showLocal={showLocal(this.isoData)}
+            />
             {this.hasFollows && (
               <div className="card border-secondary mb-3">
                 <div className="card-body">{this.subscribedCommunities()}</div>
@@ -749,7 +736,7 @@ export class Home extends Component<any, HomeState> {
       this.setState({ trendingCommunities: data.communities });
     } else if (op == UserOperation.EditSite) {
       let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
-      this.setState(s => ((s.siteRes.site_view = Some(data.site_view)), s));
+      this.setState(s => ((s.siteRes.site_view = data.site_view), s));
       toast(i18n.t("site_saved"));
     } else if (op == UserOperation.GetPosts) {
       let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
index bd56c484eb60d2e1c36e1224de696bf78afb9627..434fae9237e8504dfea8c8692064f2a0ac4c1ce3 100644 (file)
@@ -21,10 +21,7 @@ export class Instances extends Component<any, InstancesState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("instances")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
   }
 
   render() {
index bd07c406a386336f604e7783a66cedf59d2c7e8a..3930db20e40e58fda111716e9343ce1802ea2cc3 100644 (file)
@@ -33,17 +33,10 @@ export class Legal extends Component<any, LegalState> {
           description={None}
           image={None}
         />
-        {this.state.siteRes.site_view.match({
-          some: siteView =>
-            siteView.site.legal_information.match({
-              some: legal => (
-                <div
-                  className="md-div"
-                  dangerouslySetInnerHTML={mdToHtml(legal)}
-                />
-              ),
-              none: <></>,
-            }),
+        {this.state.siteRes.site_view.local_site.legal_information.match({
+          some: legal => (
+            <div className="md-div" dangerouslySetInnerHTML={mdToHtml(legal)} />
+          ),
           none: <></>,
         })}
       </div>
index 4cf9d4a67bbe7c8ff4574cfa187b9d3b1d099a80..650b3173201926c195c2d95b8d67c29ae5051ae7 100644 (file)
@@ -69,10 +69,7 @@ export class Login extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("login")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("login")} - ${this.state.siteRes.site_view.site.name}`;
   }
 
   get isLemmyMl(): boolean {
@@ -194,6 +191,8 @@ export class Login extends Component<any, State> {
         let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
         this.setState(this.emptyState);
         UserService.Instance.login(data);
+        this.props.history.push("/");
+        location.reload();
       } else if (op == UserOperation.PasswordReset) {
         toast(i18n.t("reset_password_mail_sent"));
       } else if (op == UserOperation.GetSite) {
index a288e2a134217989b1a5fbe22ce91854014648e9..8da196ca403426ecdad178d6e742144ee25a3e8d 100644 (file)
@@ -2,6 +2,7 @@ import { None, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Helmet } from "inferno-helmet";
 import {
+  GetSiteResponse,
   LoginResponse,
   Register,
   toUndefined,
@@ -13,7 +14,7 @@ import { Subscription } from "rxjs";
 import { delay, retryWhen, take } from "rxjs/operators";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
-import { toast, wsClient } from "../../utils";
+import { setIsoData, toast, wsClient } from "../../utils";
 import { Spinner } from "../common/icon";
 import { SiteForm } from "./site-form";
 
@@ -21,10 +22,12 @@ interface State {
   userForm: Register;
   doneRegisteringUser: boolean;
   userLoading: boolean;
+  siteRes: GetSiteResponse;
 }
 
 export class Setup extends Component<any, State> {
   private subscription: Subscription;
+  private isoData = setIsoData(this.context);
 
   private emptyState: State = {
     userForm: new Register({
@@ -41,6 +44,7 @@ export class Setup extends Component<any, State> {
     }),
     doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
     userLoading: false,
+    siteRes: this.isoData.site_res,
   };
 
   constructor(props: any, context: any) {
@@ -75,7 +79,7 @@ export class Setup extends Component<any, State> {
             {!this.state.doneRegisteringUser ? (
               this.registerUser()
             ) : (
-              <SiteForm site={None} showLocal />
+              <SiteForm siteRes={this.state.siteRes} showLocal />
             )}
           </div>
         </div>
index 53162114b7d418b8dbc9ddfa307d55226471eb97..2f6285033f620ae1cffa61c96116cf3d18645b87 100644 (file)
@@ -111,14 +111,14 @@ export class Signup extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${this.titleName(siteView)} - ${siteView.site.name}`,
-      none: "",
-    });
+    let siteView = this.state.siteRes.site_view;
+    return `${this.titleName(siteView)} - ${siteView.site.name}`;
   }
 
   titleName(siteView: SiteView): string {
-    return i18n.t(siteView.site.private_instance ? "apply_to_join" : "sign_up");
+    return i18n.t(
+      siteView.local_site.private_instance ? "apply_to_join" : "sign_up"
+    );
   }
 
   get isLemmyMl(): boolean {
@@ -144,248 +144,238 @@ export class Signup extends Component<any, State> {
   }
 
   registerForm() {
-    return this.state.siteRes.site_view.match({
-      some: siteView => (
-        <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
-          <h5>{this.titleName(siteView)}</h5>
+    let siteView = this.state.siteRes.site_view;
+    return (
+      <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
+        <h5>{this.titleName(siteView)}</h5>
 
-          {this.isLemmyMl && (
-            <div className="form-group row">
-              <div className="mt-2 mb-0 alert alert-warning" role="alert">
-                <T i18nKey="lemmy_ml_registration_message">
-                  #<a href={joinLemmyUrl}>#</a>
-                </T>
-              </div>
+        {this.isLemmyMl && (
+          <div className="form-group row">
+            <div className="mt-2 mb-0 alert alert-warning" role="alert">
+              <T i18nKey="lemmy_ml_registration_message">
+                #<a href={joinLemmyUrl}>#</a>
+              </T>
             </div>
-          )}
+          </div>
+        )}
+
+        <div className="form-group row">
+          <label
+            className="col-sm-2 col-form-label"
+            htmlFor="register-username"
+          >
+            {i18n.t("username")}
+          </label>
+
+          <div className="col-sm-10">
+            <input
+              type="text"
+              id="register-username"
+              className="form-control"
+              value={this.state.registerForm.username}
+              onInput={linkEvent(this, this.handleRegisterUsernameChange)}
+              required
+              minLength={3}
+              pattern="[a-zA-Z0-9_]+"
+              title={i18n.t("community_reqs")}
+            />
+          </div>
+        </div>
 
-          <div className="form-group row">
-            <label
-              className="col-sm-2 col-form-label"
-              htmlFor="register-username"
-            >
-              {i18n.t("username")}
-            </label>
+        <div className="form-group row">
+          <label className="col-sm-2 col-form-label" htmlFor="register-email">
+            {i18n.t("email")}
+          </label>
+          <div className="col-sm-10">
+            <input
+              type="email"
+              id="register-email"
+              className="form-control"
+              placeholder={
+                siteView.local_site.require_email_verification
+                  ? i18n.t("required")
+                  : i18n.t("optional")
+              }
+              value={toUndefined(this.state.registerForm.email)}
+              autoComplete="email"
+              onInput={linkEvent(this, this.handleRegisterEmailChange)}
+              required={siteView.local_site.require_email_verification}
+              minLength={3}
+            />
+            {!siteView.local_site.require_email_verification &&
+              !this.state.registerForm.email.map(validEmail).unwrapOr(true) && (
+                <div className="mt-2 mb-0 alert alert-warning" role="alert">
+                  <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+                  {i18n.t("no_password_reset")}
+                </div>
+              )}
+          </div>
+        </div>
 
-            <div className="col-sm-10">
-              <input
-                type="text"
-                id="register-username"
-                className="form-control"
-                value={this.state.registerForm.username}
-                onInput={linkEvent(this, this.handleRegisterUsernameChange)}
-                required
-                minLength={3}
-                pattern="[a-zA-Z0-9_]+"
-                title={i18n.t("community_reqs")}
-              />
-            </div>
+        <div className="form-group row">
+          <label
+            className="col-sm-2 col-form-label"
+            htmlFor="register-password"
+          >
+            {i18n.t("password")}
+          </label>
+          <div className="col-sm-10">
+            <input
+              type="password"
+              id="register-password"
+              value={this.state.registerForm.password}
+              autoComplete="new-password"
+              onInput={linkEvent(this, this.handleRegisterPasswordChange)}
+              minLength={10}
+              maxLength={60}
+              className="form-control"
+              required
+            />
+            {this.state.registerForm.password && (
+              <div className={this.passwordColorClass}>
+                {i18n.t(this.passwordStrength as I18nKeys)}
+              </div>
+            )}
           </div>
+        </div>
 
-          <div className="form-group row">
-            <label className="col-sm-2 col-form-label" htmlFor="register-email">
-              {i18n.t("email")}
-            </label>
-            <div className="col-sm-10">
-              <input
-                type="email"
-                id="register-email"
-                className="form-control"
-                placeholder={
-                  siteView.site.require_email_verification
-                    ? i18n.t("required")
-                    : i18n.t("optional")
-                }
-                value={toUndefined(this.state.registerForm.email)}
-                autoComplete="email"
-                onInput={linkEvent(this, this.handleRegisterEmailChange)}
-                required={siteView.site.require_email_verification}
-                minLength={3}
-              />
-              {!siteView.site.require_email_verification &&
-                !this.state.registerForm.email
-                  .map(validEmail)
-                  .unwrapOr(true) && (
-                  <div className="mt-2 mb-0 alert alert-warning" role="alert">
-                    <Icon icon="alert-triangle" classes="icon-inline mr-2" />
-                    {i18n.t("no_password_reset")}
-                  </div>
-                )}
-            </div>
+        <div className="form-group row">
+          <label
+            className="col-sm-2 col-form-label"
+            htmlFor="register-verify-password"
+          >
+            {i18n.t("verify_password")}
+          </label>
+          <div className="col-sm-10">
+            <input
+              type="password"
+              id="register-verify-password"
+              value={this.state.registerForm.password_verify}
+              autoComplete="new-password"
+              onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
+              maxLength={60}
+              className="form-control"
+              required
+            />
           </div>
+        </div>
 
-          <div className="form-group row">
-            <label
-              className="col-sm-2 col-form-label"
-              htmlFor="register-password"
-            >
-              {i18n.t("password")}
-            </label>
-            <div className="col-sm-10">
-              <input
-                type="password"
-                id="register-password"
-                value={this.state.registerForm.password}
-                autoComplete="new-password"
-                onInput={linkEvent(this, this.handleRegisterPasswordChange)}
-                minLength={10}
-                maxLength={60}
-                className="form-control"
-                required
-              />
-              {this.state.registerForm.password && (
-                <div className={this.passwordColorClass}>
-                  {i18n.t(this.passwordStrength as I18nKeys)}
+        {siteView.local_site.require_application && (
+          <>
+            <div className="form-group row">
+              <div className="offset-sm-2 col-sm-10">
+                <div className="mt-2 alert alert-warning" role="alert">
+                  <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+                  {i18n.t("fill_out_application")}
                 </div>
-              )}
+                {siteView.local_site.application_question.match({
+                  some: question => (
+                    <div
+                      className="md-div"
+                      dangerouslySetInnerHTML={mdToHtml(question)}
+                    />
+                  ),
+                  none: <></>,
+                })}
+              </div>
             </div>
-          </div>
 
+            <div className="form-group row">
+              <label
+                className="col-sm-2 col-form-label"
+                htmlFor="application_answer"
+              >
+                {i18n.t("answer")}
+              </label>
+              <div className="col-sm-10">
+                <MarkdownTextArea
+                  initialContent={None}
+                  initialLanguageId={None}
+                  placeholder={None}
+                  buttonTitle={None}
+                  maxLength={None}
+                  onContentChange={this.handleAnswerChange}
+                  hideNavigationWarnings
+                  allLanguages={[]}
+                />
+              </div>
+            </div>
+          </>
+        )}
+
+        {this.state.captcha.isSome() && (
           <div className="form-group row">
-            <label
-              className="col-sm-2 col-form-label"
-              htmlFor="register-verify-password"
-            >
-              {i18n.t("verify_password")}
+            <label className="col-sm-2" htmlFor="register-captcha">
+              <span className="mr-2">{i18n.t("enter_code")}</span>
+              <button
+                type="button"
+                className="btn btn-secondary"
+                onClick={linkEvent(this, this.handleRegenCaptcha)}
+                aria-label={i18n.t("captcha")}
+              >
+                <Icon icon="refresh-cw" classes="icon-refresh-cw" />
+              </button>
             </label>
-            <div className="col-sm-10">
+            {this.showCaptcha()}
+            <div className="col-sm-6">
               <input
-                type="password"
-                id="register-verify-password"
-                value={this.state.registerForm.password_verify}
-                autoComplete="new-password"
+                type="text"
+                className="form-control"
+                id="register-captcha"
+                value={toUndefined(this.state.registerForm.captcha_answer)}
                 onInput={linkEvent(
                   this,
-                  this.handleRegisterPasswordVerifyChange
+                  this.handleRegisterCaptchaAnswerChange
                 )}
-                maxLength={60}
-                className="form-control"
                 required
               />
             </div>
           </div>
-
-          {siteView.site.require_application && (
-            <>
-              <div className="form-group row">
-                <div className="offset-sm-2 col-sm-10">
-                  <div className="mt-2 alert alert-warning" role="alert">
-                    <Icon icon="alert-triangle" classes="icon-inline mr-2" />
-                    {i18n.t("fill_out_application")}
-                  </div>
-                  {siteView.site.application_question.match({
-                    some: question => (
-                      <div
-                        className="md-div"
-                        dangerouslySetInnerHTML={mdToHtml(question)}
-                      />
-                    ),
-                    none: <></>,
-                  })}
-                </div>
-              </div>
-
-              <div className="form-group row">
+        )}
+        {siteView.local_site.enable_nsfw && (
+          <div className="form-group row">
+            <div className="col-sm-10">
+              <div className="form-check">
+                <input
+                  className="form-check-input"
+                  id="register-show-nsfw"
+                  type="checkbox"
+                  checked={this.state.registerForm.show_nsfw}
+                  onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
+                />
                 <label
-                  className="col-sm-2 col-form-label"
-                  htmlFor="application_answer"
+                  className="form-check-label"
+                  htmlFor="register-show-nsfw"
                 >
-                  {i18n.t("answer")}
+                  {i18n.t("show_nsfw")}
                 </label>
-                <div className="col-sm-10">
-                  <MarkdownTextArea
-                    initialContent={None}
-                    initialLanguageId={None}
-                    placeholder={None}
-                    buttonTitle={None}
-                    maxLength={None}
-                    onContentChange={this.handleAnswerChange}
-                    hideNavigationWarnings
-                    allLanguages={[]}
-                  />
-                </div>
               </div>
-            </>
-          )}
-
-          {this.state.captcha.isSome() && (
-            <div className="form-group row">
-              <label className="col-sm-2" htmlFor="register-captcha">
-                <span className="mr-2">{i18n.t("enter_code")}</span>
-                <button
-                  type="button"
-                  className="btn btn-secondary"
-                  onClick={linkEvent(this, this.handleRegenCaptcha)}
-                  aria-label={i18n.t("captcha")}
-                >
-                  <Icon icon="refresh-cw" classes="icon-refresh-cw" />
-                </button>
-              </label>
-              {this.showCaptcha()}
-              <div className="col-sm-6">
-                <input
-                  type="text"
-                  className="form-control"
-                  id="register-captcha"
-                  value={toUndefined(this.state.registerForm.captcha_answer)}
-                  onInput={linkEvent(
-                    this,
-                    this.handleRegisterCaptchaAnswerChange
-                  )}
-                  required
-                />
-              </div>
-            </div>
-          )}
-          {siteView.site.enable_nsfw && (
-            <div className="form-group row">
-              <div className="col-sm-10">
-                <div className="form-check">
-                  <input
-                    className="form-check-input"
-                    id="register-show-nsfw"
-                    type="checkbox"
-                    checked={this.state.registerForm.show_nsfw}
-                    onChange={linkEvent(
-                      this,
-                      this.handleRegisterShowNsfwChange
-                    )}
-                  />
-                  <label
-                    className="form-check-label"
-                    htmlFor="register-show-nsfw"
-                  >
-                    {i18n.t("show_nsfw")}
-                  </label>
-                </div>
-              </div>
-            </div>
-          )}
-          <input
-            tabIndex={-1}
-            autoComplete="false"
-            name="a_password"
-            type="text"
-            className="form-control honeypot"
-            id="register-honey"
-            value={toUndefined(this.state.registerForm.honeypot)}
-            onInput={linkEvent(this, this.handleHoneyPotChange)}
-          />
-          <div className="form-group row">
-            <div className="col-sm-10">
-              <button type="submit" className="btn btn-secondary">
-                {this.state.registerLoading ? (
-                  <Spinner />
-                ) : (
-                  this.titleName(siteView)
-                )}
-              </button>
             </div>
           </div>
-        </form>
-      ),
-      none: <></>,
-    });
+        )}
+        <input
+          tabIndex={-1}
+          autoComplete="false"
+          name="a_password"
+          type="text"
+          className="form-control honeypot"
+          id="register-honey"
+          value={toUndefined(this.state.registerForm.honeypot)}
+          onInput={linkEvent(this, this.handleHoneyPotChange)}
+        />
+        <div className="form-group row">
+          <div className="col-sm-10">
+            <button type="submit" className="btn btn-secondary">
+              {this.state.registerLoading ? (
+                <Spinner />
+              ) : (
+                this.titleName(siteView)
+              )}
+            </button>
+          </div>
+        </div>
+      </form>
+    );
   }
 
   showCaptcha() {
@@ -545,6 +535,7 @@ export class Signup extends Component<any, State> {
         if (data.jwt.isSome()) {
           UserService.Instance.login(data);
           this.props.history.push("/communities");
+          location.reload();
         } else {
           if (data.verify_email_sent) {
             toast(i18n.t("verify_email_sent"));
index bc0072c48a1e8d47aaa742c1382da99356066a96..982afd589479d0cf9973096c079d1212ef086793 100644 (file)
@@ -4,8 +4,8 @@ import { Prompt } from "inferno-router";
 import {
   CreateSite,
   EditSite,
+  GetSiteResponse,
   ListingType,
-  Site,
   toUndefined,
 } from "lemmy-js-client";
 import { i18n } from "../../i18next";
@@ -18,14 +18,13 @@ import {
 } from "../../utils";
 import { Spinner } from "../common/icon";
 import { ImageUploadForm } from "../common/image-upload-form";
+import { LanguageSelect } from "../common/language-select";
 import { ListingTypeSelect } from "../common/listing-type-select";
 import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface SiteFormProps {
-  site: Option<Site>; // If a site is given, that means this is an edit
+  siteRes: GetSiteResponse;
   showLocal?: boolean;
-  onCancel?(): void;
-  onEdit?(): void;
 }
 
 interface SiteFormState {
@@ -37,9 +36,9 @@ interface SiteFormState {
 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   private emptyState: SiteFormState = {
     siteForm: new EditSite({
-      enable_downvotes: Some(true),
-      open_registration: Some(true),
-      enable_nsfw: Some(true),
+      enable_downvotes: None,
+      open_registration: None,
+      enable_nsfw: None,
       name: None,
       icon: None,
       banner: None,
@@ -54,8 +53,32 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
       description: None,
       community_creation_admin_only: None,
       application_email_admins: None,
+      hide_modlog_mod_names: None,
+      discussion_languages: None,
+      slur_filter_regex: None,
+      actor_name_max_length: None,
+      rate_limit_message: None,
+      rate_limit_message_per_second: None,
+      rate_limit_comment: None,
+      rate_limit_comment_per_second: None,
+      rate_limit_image: None,
+      rate_limit_image_per_second: None,
+      rate_limit_post: None,
+      rate_limit_post_per_second: None,
+      rate_limit_register: None,
+      rate_limit_register_per_second: None,
+      rate_limit_search: None,
+      rate_limit_search_per_second: None,
+      federation_enabled: None,
+      federation_debug: None,
+      federation_worker_count: None,
+      federation_strict_allowlist: None,
+      federation_http_fetch_retry_limit: None,
+      captcha_enabled: None,
+      captcha_difficulty: None,
+      allowed_instances: None,
+      blocked_instances: None,
       auth: undefined,
-      hide_modlog_mod_names: Some(true),
     }),
     loading: false,
     themeList: None,
@@ -79,35 +102,66 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     this.handleDefaultPostListingTypeChange =
       this.handleDefaultPostListingTypeChange.bind(this);
 
-    if (this.props.site.isSome()) {
-      let site = this.props.site.unwrap();
-      this.state = {
-        ...this.state,
-        siteForm: new EditSite({
-          name: Some(site.name),
-          sidebar: site.sidebar,
-          description: site.description,
-          enable_downvotes: Some(site.enable_downvotes),
-          open_registration: Some(site.open_registration),
-          enable_nsfw: Some(site.enable_nsfw),
-          community_creation_admin_only: Some(
-            site.community_creation_admin_only
-          ),
-          icon: site.icon,
-          banner: site.banner,
-          require_email_verification: Some(site.require_email_verification),
-          require_application: Some(site.require_application),
-          application_question: site.application_question,
-          private_instance: Some(site.private_instance),
-          default_theme: Some(site.default_theme),
-          default_post_listing_type: Some(site.default_post_listing_type),
-          legal_information: site.legal_information,
-          application_email_admins: Some(site.application_email_admins),
-          hide_modlog_mod_names: site.hide_modlog_mod_names,
-          auth: undefined,
-        }),
-      };
-    }
+    this.handleDiscussionLanguageChange =
+      this.handleDiscussionLanguageChange.bind(this);
+
+    let site = this.props.siteRes.site_view.site;
+    let ls = this.props.siteRes.site_view.local_site;
+    let lsrl = this.props.siteRes.site_view.local_site_rate_limit;
+    this.state = {
+      ...this.state,
+      siteForm: new EditSite({
+        name: Some(site.name),
+        sidebar: site.sidebar,
+        description: site.description,
+        enable_downvotes: Some(ls.enable_downvotes),
+        open_registration: Some(ls.open_registration),
+        enable_nsfw: Some(ls.enable_nsfw),
+        community_creation_admin_only: Some(ls.community_creation_admin_only),
+        icon: site.icon,
+        banner: site.banner,
+        require_email_verification: Some(ls.require_email_verification),
+        require_application: Some(ls.require_application),
+        application_question: ls.application_question,
+        private_instance: Some(ls.private_instance),
+        default_theme: Some(ls.default_theme),
+        default_post_listing_type: Some(ls.default_post_listing_type),
+        legal_information: ls.legal_information,
+        application_email_admins: Some(ls.application_email_admins),
+        hide_modlog_mod_names: Some(ls.hide_modlog_mod_names),
+        discussion_languages: Some(this.props.siteRes.discussion_languages),
+        slur_filter_regex: ls.slur_filter_regex,
+        actor_name_max_length: Some(ls.actor_name_max_length),
+        rate_limit_message: Some(lsrl.message),
+        rate_limit_message_per_second: Some(lsrl.message_per_second),
+        rate_limit_comment: Some(lsrl.comment),
+        rate_limit_comment_per_second: Some(lsrl.comment_per_second),
+        rate_limit_image: Some(lsrl.image),
+        rate_limit_image_per_second: Some(lsrl.image_per_second),
+        rate_limit_post: Some(lsrl.post),
+        rate_limit_post_per_second: Some(lsrl.post_per_second),
+        rate_limit_register: Some(lsrl.register),
+        rate_limit_register_per_second: Some(lsrl.register_per_second),
+        rate_limit_search: Some(lsrl.search),
+        rate_limit_search_per_second: Some(lsrl.search_per_second),
+        federation_enabled: Some(ls.federation_enabled),
+        federation_debug: Some(ls.federation_debug),
+        federation_worker_count: Some(ls.federation_worker_count),
+        federation_strict_allowlist: Some(ls.federation_strict_allowlist),
+        federation_http_fetch_retry_limit: Some(
+          ls.federation_http_fetch_retry_limit
+        ),
+        captcha_enabled: Some(ls.captcha_enabled),
+        captcha_difficulty: Some(ls.captcha_difficulty),
+        allowed_instances: this.props.siteRes.federated_instances.andThen(
+          f => f.allowed
+        ),
+        blocked_instances: this.props.siteRes.federated_instances.andThen(
+          f => f.blocked
+        ),
+        auth: undefined,
+      }),
+    };
   }
 
   async componentDidMount() {
@@ -122,7 +176,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   componentDidUpdate() {
     if (
       !this.state.loading &&
-      this.props.site.isNone() &&
+      !this.props.siteRes.site_view.local_site.site_setup &&
       (this.state.siteForm.name ||
         this.state.siteForm.sidebar ||
         this.state.siteForm.application_question ||
@@ -139,12 +193,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   }
 
   render() {
+    let siteSetup = this.props.siteRes.site_view.local_site.site_setup;
     return (
       <>
         <Prompt
           when={
             !this.state.loading &&
-            this.props.site.isNone() &&
+            !siteSetup &&
             (this.state.siteForm.name ||
               this.state.siteForm.sidebar ||
               this.state.siteForm.application_question ||
@@ -154,7 +209,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
         />
         <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
           <h5>{`${
-            this.props.site.isSome()
+            siteSetup
               ? capitalizeFirstLetter(i18n.t("save"))
               : capitalizeFirstLetter(i18n.t("name"))
           } ${i18n.t("your_site")}`}</h5>
@@ -496,6 +551,487 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
               </div>
             </div>
           </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-slur-filter-regex"
+            >
+              {i18n.t("slur_filter_regex")}
+            </label>
+            <div className="col-12">
+              <input
+                type="text"
+                id="create-site-slur-filter-regex"
+                placeholder="(word1|word2)"
+                className="form-control"
+                value={toUndefined(this.state.siteForm.slur_filter_regex)}
+                onInput={linkEvent(this, this.handleSiteSlurFilterRegex)}
+                minLength={3}
+              />
+            </div>
+          </div>
+          <LanguageSelect
+            allLanguages={this.props.siteRes.all_languages}
+            selectedLanguageIds={this.state.siteForm.discussion_languages}
+            multiple={true}
+            onChange={this.handleDiscussionLanguageChange}
+          />
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-actor-name"
+            >
+              {i18n.t("actor_name_max_length")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-actor-name"
+                className="form-control"
+                min={5}
+                value={toUndefined(this.state.siteForm.actor_name_max_length)}
+                onInput={linkEvent(this, this.handleSiteActorNameMaxLength)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <div className="col-12">
+              <div className="form-check">
+                <input
+                  className="form-check-input"
+                  id="create-site-federation-enabled"
+                  type="checkbox"
+                  checked={toUndefined(this.state.siteForm.federation_enabled)}
+                  onChange={linkEvent(this, this.handleSiteFederationEnabled)}
+                />
+                <label
+                  className="form-check-label"
+                  htmlFor="create-site-federation-enabled"
+                >
+                  {i18n.t("federation_enabled")}
+                </label>
+              </div>
+            </div>
+          </div>
+          {this.state.siteForm.federation_enabled.unwrapOr(false) && (
+            <>
+              <div className="form-group row">
+                <label
+                  className="col-12 col-form-label"
+                  htmlFor="create-site-allowed-instances"
+                >
+                  {i18n.t("allowed_instances")}
+                </label>
+                <div className="col-12">
+                  <input
+                    type="text"
+                    placeholder="instance1.tld,instance2.tld"
+                    id="create-site-allowed-instances"
+                    className="form-control"
+                    value={this.instancesToString(
+                      this.state.siteForm.allowed_instances
+                    )}
+                    onInput={linkEvent(this, this.handleSiteAllowedInstances)}
+                  />
+                </div>
+              </div>
+              <div className="form-group row">
+                <label
+                  className="col-12 col-form-label"
+                  htmlFor="create-site-blocked-instances"
+                >
+                  {i18n.t("blocked_instances")}
+                </label>
+                <div className="col-12">
+                  <input
+                    type="text"
+                    placeholder="instance1.tld,instance2.tld"
+                    id="create-site-blocked-instances"
+                    className="form-control"
+                    value={this.instancesToString(
+                      this.state.siteForm.blocked_instances
+                    )}
+                    onInput={linkEvent(this, this.handleSiteBlockedInstances)}
+                  />
+                </div>
+              </div>
+              <div className="form-group row">
+                <div className="col-12">
+                  <div className="form-check">
+                    <input
+                      className="form-check-input"
+                      id="create-site-federation-debug"
+                      type="checkbox"
+                      checked={toUndefined(
+                        this.state.siteForm.federation_debug
+                      )}
+                      onChange={linkEvent(this, this.handleSiteFederationDebug)}
+                    />
+                    <label
+                      className="form-check-label"
+                      htmlFor="create-site-federation-debug"
+                    >
+                      {i18n.t("federation_debug")}
+                    </label>
+                  </div>
+                </div>
+              </div>
+              <div className="form-group row">
+                <div className="col-12">
+                  <div className="form-check">
+                    <input
+                      className="form-check-input"
+                      id="create-site-federation-strict-allowlist"
+                      type="checkbox"
+                      checked={toUndefined(
+                        this.state.siteForm.federation_strict_allowlist
+                      )}
+                      onChange={linkEvent(
+                        this,
+                        this.handleSiteFederationStrictAllowList
+                      )}
+                    />
+                    <label
+                      className="form-check-label"
+                      htmlFor="create-site-federation-strict-allowlist"
+                    >
+                      {i18n.t("federation_strict_allowlist")}
+                    </label>
+                  </div>
+                </div>
+              </div>
+              <div className="form-group row">
+                <label
+                  className="col-12 col-form-label"
+                  htmlFor="create-site-federation-http-fetch-retry-limit"
+                >
+                  {i18n.t("federation_http_fetch_retry_limit")}
+                </label>
+                <div className="col-12">
+                  <input
+                    type="number"
+                    id="create-site-federation-http-fetch-retry-limit"
+                    className="form-control"
+                    min={0}
+                    value={toUndefined(
+                      this.state.siteForm.federation_http_fetch_retry_limit
+                    )}
+                    onInput={linkEvent(
+                      this,
+                      this.handleSiteFederationHttpFetchRetryLimit
+                    )}
+                  />
+                </div>
+              </div>
+              <div className="form-group row">
+                <label
+                  className="col-12 col-form-label"
+                  htmlFor="create-site-federation-worker-count"
+                >
+                  {i18n.t("federation_worker_count")}
+                </label>
+                <div className="col-12">
+                  <input
+                    type="number"
+                    id="create-site-federation-worker-count"
+                    className="form-control"
+                    min={0}
+                    value={toUndefined(
+                      this.state.siteForm.federation_worker_count
+                    )}
+                    onInput={linkEvent(
+                      this,
+                      this.handleSiteFederationWorkerCount
+                    )}
+                  />
+                </div>
+              </div>
+            </>
+          )}
+          <div className="form-group row">
+            <div className="col-12">
+              <div className="form-check">
+                <input
+                  className="form-check-input"
+                  id="create-site-captcha-enabled"
+                  type="checkbox"
+                  checked={toUndefined(this.state.siteForm.captcha_enabled)}
+                  onChange={linkEvent(this, this.handleSiteCaptchaEnabled)}
+                />
+                <label
+                  className="form-check-label"
+                  htmlFor="create-site-captcha-enabled"
+                >
+                  {i18n.t("captcha_enabled")}
+                </label>
+              </div>
+            </div>
+          </div>
+          {this.state.siteForm.captcha_enabled.unwrapOr(false) && (
+            <div className="form-group row">
+              <div className="col-12">
+                <label
+                  className="form-check-label mr-2"
+                  htmlFor="create-site-captcha-difficulty"
+                >
+                  {i18n.t("captcha_difficulty")}
+                </label>
+                <select
+                  id="create-site-captcha-difficulty"
+                  value={toUndefined(this.state.siteForm.captcha_difficulty)}
+                  onChange={linkEvent(this, this.handleSiteCaptchaDifficulty)}
+                  className="custom-select w-auto"
+                >
+                  <option value="easy">{i18n.t("easy")}</option>
+                  <option value="medium">{i18n.t("medium")}</option>
+                  <option value="hard">{i18n.t("hard")}</option>
+                </select>
+              </div>
+            </div>
+          )}
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-message"
+            >
+              {i18n.t("rate_limit_message")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-message"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_message)}
+                onInput={linkEvent(this, this.handleSiteRateLimitMessage)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-message-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-message-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_message_per_second
+                )}
+                onInput={linkEvent(
+                  this,
+                  this.handleSiteRateLimitMessagePerSecond
+                )}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-post"
+            >
+              {i18n.t("rate_limit_post")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-post"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_post)}
+                onInput={linkEvent(this, this.handleSiteRateLimitPost)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-post-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-post-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_post_per_second
+                )}
+                onInput={linkEvent(this, this.handleSiteRateLimitPostPerSecond)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-register"
+            >
+              {i18n.t("rate_limit_register")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-register"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_register)}
+                onInput={linkEvent(this, this.handleSiteRateLimitRegister)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-register-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-register-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_register_per_second
+                )}
+                onInput={linkEvent(
+                  this,
+                  this.handleSiteRateLimitRegisterPerSecond
+                )}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-image"
+            >
+              {i18n.t("rate_limit_image")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-image"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_image)}
+                onInput={linkEvent(this, this.handleSiteRateLimitImage)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-image-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-image-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_image_per_second
+                )}
+                onInput={linkEvent(
+                  this,
+                  this.handleSiteRateLimitImagePerSecond
+                )}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-comment"
+            >
+              {i18n.t("rate_limit_comment")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-comment"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_comment)}
+                onInput={linkEvent(this, this.handleSiteRateLimitComment)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-comment-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-comment-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_comment_per_second
+                )}
+                onInput={linkEvent(
+                  this,
+                  this.handleSiteRateLimitCommentPerSecond
+                )}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-search"
+            >
+              {i18n.t("rate_limit_search")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-search"
+                className="form-control"
+                min={0}
+                value={toUndefined(this.state.siteForm.rate_limit_search)}
+                onInput={linkEvent(this, this.handleSiteRateLimitSearch)}
+              />
+            </div>
+          </div>
+          <div className="form-group row">
+            <label
+              className="col-12 col-form-label"
+              htmlFor="create-site-rate-limit-search-per-second"
+            >
+              {i18n.t("per_second")}
+            </label>
+            <div className="col-12">
+              <input
+                type="number"
+                id="create-site-rate-limit-search-per-second"
+                className="form-control"
+                min={0}
+                value={toUndefined(
+                  this.state.siteForm.rate_limit_search_per_second
+                )}
+                onInput={linkEvent(
+                  this,
+                  this.handleSiteRateLimitSearchPerSecond
+                )}
+              />
+            </div>
+          </div>
           <div className="form-group row">
             <div className="col-12">
               <button
@@ -505,21 +1041,12 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
               >
                 {this.state.loading ? (
                   <Spinner />
-                ) : this.props.site.isSome() ? (
+                ) : siteSetup ? (
                   capitalizeFirstLetter(i18n.t("save"))
                 ) : (
                   capitalizeFirstLetter(i18n.t("create"))
                 )}
               </button>
-              {this.props.site.isSome() && (
-                <button
-                  type="button"
-                  className="btn btn-secondary"
-                  onClick={linkEvent(this, this.handleCancel)}
-                >
-                  {i18n.t("cancel")}
-                </button>
-              )}
             </div>
           </div>
         </form>
@@ -532,9 +1059,8 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     i.setState({ loading: true });
     i.setState(s => ((s.siteForm.auth = auth().unwrap()), s));
 
-    if (i.props.site.isSome()) {
+    if (i.props.siteRes.site_view.local_site.site_setup) {
       WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
-      i.props.onEdit();
     } else {
       let sForm = i.state.siteForm;
       let form = new CreateSite({
@@ -556,12 +1082,52 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
         application_email_admins: sForm.application_email_admins,
         auth: auth().unwrap(),
         hide_modlog_mod_names: sForm.hide_modlog_mod_names,
+        legal_information: sForm.legal_information,
+        slur_filter_regex: sForm.slur_filter_regex,
+        actor_name_max_length: sForm.actor_name_max_length,
+        rate_limit_message: sForm.rate_limit_message,
+        rate_limit_message_per_second: sForm.rate_limit_message_per_second,
+        rate_limit_comment: sForm.rate_limit_comment,
+        rate_limit_comment_per_second: sForm.rate_limit_comment_per_second,
+        rate_limit_image: sForm.rate_limit_image,
+        rate_limit_image_per_second: sForm.rate_limit_image_per_second,
+        rate_limit_post: sForm.rate_limit_post,
+        rate_limit_post_per_second: sForm.rate_limit_post_per_second,
+        rate_limit_register: sForm.rate_limit_register,
+        rate_limit_register_per_second: sForm.rate_limit_register_per_second,
+        rate_limit_search: sForm.rate_limit_search,
+        rate_limit_search_per_second: sForm.rate_limit_search_per_second,
+        federation_enabled: sForm.federation_enabled,
+        federation_debug: sForm.federation_debug,
+        federation_worker_count: sForm.federation_worker_count,
+        federation_strict_allowlist: sForm.federation_strict_allowlist,
+        federation_http_fetch_retry_limit:
+          sForm.federation_http_fetch_retry_limit,
+        captcha_enabled: sForm.captcha_enabled,
+        captcha_difficulty: sForm.captcha_difficulty,
+        allowed_instances: sForm.allowed_instances,
+        blocked_instances: sForm.blocked_instances,
+        discussion_languages: sForm.discussion_languages,
       });
       WebSocketService.Instance.send(wsClient.createSite(form));
     }
     i.setState(i.state);
   }
 
+  instancesToString(opt: Option<string[]>): string {
+    return opt.map(list => list.join(",")).unwrapOr("");
+  }
+
+  handleSiteAllowedInstances(i: SiteForm, event: any) {
+    let list = splitToList(event.target.value);
+    i.setState(s => ((s.siteForm.allowed_instances = list), s));
+  }
+
+  handleSiteBlockedInstances(i: SiteForm, event: any) {
+    let list = splitToList(event.target.value);
+    i.setState(s => ((s.siteForm.blocked_instances = list), s));
+  }
+
   handleSiteNameChange(i: SiteForm, event: any) {
     i.state.siteForm.name = Some(event.target.value);
     i.setState(i.state);
@@ -634,10 +1200,6 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     i.setState(i.state);
   }
 
-  handleCancel(i: SiteForm) {
-    i.props.onCancel();
-  }
-
   handleIconUpload(url: string) {
     this.setState(s => ((s.siteForm.icon = Some(url)), s));
   }
@@ -654,6 +1216,180 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     this.setState(s => ((s.siteForm.banner = Some("")), s));
   }
 
+  handleSiteSlurFilterRegex(i: SiteForm, event: any) {
+    i.setState(
+      s => ((s.siteForm.slur_filter_regex = Some(event.target.value)), s)
+    );
+  }
+
+  handleSiteActorNameMaxLength(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.actor_name_max_length = Some(Number(event.target.value))), s
+      )
+    );
+  }
+
+  handleSiteRateLimitMessage(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_message = Some(Number(event.target.value))), s
+      )
+    );
+  }
+
+  handleSiteRateLimitMessagePerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_message_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteRateLimitPost(i: SiteForm, event: any) {
+    i.setState(
+      s => ((s.siteForm.rate_limit_post = Some(Number(event.target.value))), s)
+    );
+  }
+
+  handleSiteRateLimitPostPerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_post_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteRateLimitImage(i: SiteForm, event: any) {
+    i.setState(
+      s => ((s.siteForm.rate_limit_image = Some(Number(event.target.value))), s)
+    );
+  }
+
+  handleSiteRateLimitImagePerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_image_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteRateLimitComment(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_comment = Some(Number(event.target.value))), s
+      )
+    );
+  }
+
+  handleSiteRateLimitCommentPerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_comment_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteRateLimitSearch(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_search = Some(Number(event.target.value))), s
+      )
+    );
+  }
+
+  handleSiteRateLimitSearchPerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_search_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteRateLimitRegister(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_register = Some(Number(event.target.value))), s
+      )
+    );
+  }
+
+  handleSiteRateLimitRegisterPerSecond(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.rate_limit_register_per_second = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteFederationEnabled(i: SiteForm, event: any) {
+    i.state.siteForm.federation_enabled = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteFederationDebug(i: SiteForm, event: any) {
+    i.state.siteForm.federation_debug = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteFederationStrictAllowList(i: SiteForm, event: any) {
+    i.state.siteForm.federation_strict_allowlist = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteFederationWorkerCount(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.federation_worker_count = Some(Number(event.target.value))),
+        s
+      )
+    );
+  }
+
+  handleSiteFederationHttpFetchRetryLimit(i: SiteForm, event: any) {
+    i.setState(
+      s => (
+        (s.siteForm.federation_http_fetch_retry_limit = Some(
+          Number(event.target.value)
+        )),
+        s
+      )
+    );
+  }
+
+  handleSiteCaptchaEnabled(i: SiteForm, event: any) {
+    i.state.siteForm.captcha_enabled = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteCaptchaDifficulty(i: SiteForm, event: any) {
+    i.setState(
+      s => ((s.siteForm.captcha_difficulty = Some(event.target.value)), s)
+    );
+  }
+
+  handleDiscussionLanguageChange(val: number[]) {
+    this.setState(s => ((s.siteForm.discussion_languages = Some(val)), s));
+  }
+
   handleDefaultPostListingTypeChange(val: ListingType) {
     this.setState(
       s => (
@@ -665,3 +1401,12 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     );
   }
 }
+
+function splitToList(commaList: string): Option<string[]> {
+  if (commaList !== "") {
+    let list = commaList.trim().split(",");
+    return Some(list);
+  } else {
+    return Some([]);
+  }
+}
index e8642c78366e8da22ed206a5adbdb84fad8d8e1b..e321ae9f6b9b1218a6846d6e762fdf39302cd5d9 100644 (file)
@@ -1,13 +1,12 @@
-import { None, Option, Some } from "@sniptt/monads";
+import { None, Option } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client";
 import { i18n } from "../../i18next";
-import { amAdmin, mdToHtml, numToSI } from "../../utils";
+import { mdToHtml, numToSI } from "../../utils";
 import { BannerIconHeader } from "../common/banner-icon-header";
 import { Icon } from "../common/icon";
 import { PersonListing } from "../person/person-listing";
-import { SiteForm } from "./site-form";
 
 interface SiteSidebarProps {
   site: Site;
@@ -19,58 +18,40 @@ interface SiteSidebarProps {
 
 interface SiteSidebarState {
   collapsed: boolean;
-  showEdit: boolean;
 }
 
 export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
   private emptyState: SiteSidebarState = {
     collapsed: false,
-    showEdit: false,
   };
 
   constructor(props: any, context: any) {
     super(props, context);
     this.state = this.emptyState;
-    this.handleEditCancel = this.handleEditCancel.bind(this);
-    this.handleEditSite = this.handleEditSite.bind(this);
   }
 
   render() {
-    let site = this.props.site;
     return (
       <div className="card border-secondary mb-3">
         <div className="card-body">
-          {!this.state.showEdit ? (
-            <div>
-              <div className="mb-2">
-                {this.siteName()}
-                {this.props.admins.isSome() && this.adminButtons()}
-              </div>
-              {!this.state.collapsed && (
-                <>
-                  <BannerIconHeader banner={site.banner} icon={None} />
-                  {this.siteInfo()}
-                </>
-              )}
-            </div>
-          ) : (
-            <SiteForm
-              site={Some(site)}
-              showLocal={this.props.showLocal}
-              onEdit={this.handleEditSite}
-              onCancel={this.handleEditCancel}
-            />
-          )}
+          <div>
+            <div className="mb-2">{this.siteName()}</div>
+            {!this.state.collapsed && (
+              <>
+                <BannerIconHeader banner={this.props.site.banner} icon={None} />
+                {this.siteInfo()}
+              </>
+            )}
+          </div>
         </div>
       </div>
     );
   }
 
   siteName() {
-    let site = this.props.site;
     return (
       <h5 className="mb-0 d-inline">
-        {site.name}
+        {this.props.site.name}
         <button
           className="btn btn-sm text-muted"
           onClick={linkEvent(this, this.handleCollapseSidebar)}
@@ -111,25 +92,6 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
     );
   }
 
-  adminButtons() {
-    return (
-      amAdmin() && (
-        <ul className="list-inline mb-1 text-muted font-weight-bold">
-          <li className="list-inline-item-action">
-            <button
-              className="btn btn-link d-inline-block text-muted"
-              onClick={linkEvent(this, this.handleEditClick)}
-              aria-label={i18n.t("edit")}
-              data-tippy-content={i18n.t("edit")}
-            >
-              <Icon icon="edit" classes="icon-inline" />
-            </button>
-          </li>
-        </ul>
-      )
-    );
-  }
-
   siteSidebar(sidebar: string) {
     return (
       <div className="md-div" dangerouslySetInnerHTML={mdToHtml(sidebar)} />
@@ -248,16 +210,4 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
   handleCollapseSidebar(i: SiteSidebar) {
     i.setState({ collapsed: !i.state.collapsed });
   }
-
-  handleEditClick(i: SiteSidebar) {
-    i.setState({ showEdit: true });
-  }
-
-  handleEditSite() {
-    this.setState({ showEdit: false });
-  }
-
-  handleEditCancel() {
-    this.setState({ showEdit: false });
-  }
 }
index f34e6f3c448d4e62836f6d4434e558831fd1ac5a..e097d97214d5846ef6d382ff203d8190c2380caa 100644 (file)
@@ -632,10 +632,7 @@ export class Modlog extends Component<any, ModlogState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `Modlog - ${siteView.site.name}`,
-      none: "",
-    });
+    return `Modlog - ${this.state.siteRes.site_view.site.name}`;
   }
 
   render() {
@@ -708,21 +705,18 @@ export class Modlog extends Component<any, ModlogState> {
                   </option>
                 </select>
               </div>
-              {this.state.siteRes.site_view.match({
-                some: site_view =>
-                  !site_view.site.hide_modlog_mod_names.unwrapOr(false) && (
-                    <div className="form-group col-sm-6">
-                      <select
-                        id="filter-mod"
-                        className="form-control"
-                        value={toUndefined(this.state.filter_mod)}
-                      >
-                        <option>{i18n.t("filter_by_mod")}</option>
-                      </select>
-                    </div>
-                  ),
-                none: <></>,
-              })}
+              {!this.state.siteRes.site_view.local_site
+                .hide_modlog_mod_names && (
+                <div className="form-group col-sm-6">
+                  <select
+                    id="filter-mod"
+                    className="form-control"
+                    value={toUndefined(this.state.filter_mod)}
+                  >
+                    <option>{i18n.t("filter_by_mod")}</option>
+                  </select>
+                </div>
+              )}
               <div className="form-group col-sm-6">
                 <select
                   id="filter-user"
index 67569cb76c7b76b73cca73dedd27c1ba8c85cda7..40b2678e9544542780b3ba914d15f40c6240f7b9 100644 (file)
@@ -153,15 +153,11 @@ export class Inbox extends Component<any, InboxState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        UserService.Instance.myUserInfo.match({
-          some: mui =>
-            `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
-              siteView.site.name
-            }`,
-          none: "",
-        }),
+    return UserService.Instance.myUserInfo.match({
+      some: mui =>
+        `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
+          this.state.siteRes.site_view.site.name
+        }`,
       none: "",
     });
   }
index a0305f1f7acedf6dfb567190fca2bfdcdcd61e27..d3d81828834c856518d046f12b50ba130fa3d871 100644 (file)
@@ -58,10 +58,9 @@ export class PasswordChange extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("password_change")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("password_change")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
@@ -164,6 +163,7 @@ export class PasswordChange extends Component<any, State> {
       this.setState(this.emptyState);
       UserService.Instance.login(data);
       this.props.history.push("/");
+      location.reload();
     }
   }
 }
index 2b61a7ca031331d7070ae88dd3531b0201eb86d8..94d014b0558acb4505dcee842bc264eaae338823 100644 (file)
@@ -238,13 +238,9 @@ export class Profile extends Component<any, ProfileState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        this.state.personRes.match({
-          some: res =>
-            `@${res.person_view.person.name} - ${siteView.site.name}`,
-          none: "",
-        }),
+    return this.state.personRes.match({
+      some: res =>
+        `@${res.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`,
       none: "",
     });
   }
index e70c29d2c4e555fcd001d5ff1d979a2f3045d7ae..e5235082fb70993143223a49025d74e18220a884 100644 (file)
@@ -98,15 +98,11 @@ export class RegistrationApplications extends Component<
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        UserService.Instance.myUserInfo.match({
-          some: mui =>
-            `@${mui.local_user_view.person.name} ${i18n.t(
-              "registration_applications"
-            )} - ${siteView.site.name}`,
-          none: "",
-        }),
+    return UserService.Instance.myUserInfo.match({
+      some: mui =>
+        `@${mui.local_user_view.person.name} ${i18n.t(
+          "registration_applications"
+        )} - ${this.state.siteRes.site_view.site.name}`,
       none: "",
     });
   }
index 58e5ea1d9df38854cc509d66e493ebe29c81e58b..f28188e71f487395cdeb52d0c09856384a43db87 100644 (file)
@@ -150,15 +150,11 @@ export class Reports extends Component<any, ReportsState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        UserService.Instance.myUserInfo.match({
-          some: mui =>
-            `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
-              siteView.site.name
-            }`,
-          none: "",
-        }),
+    return UserService.Instance.myUserInfo.match({
+      some: mui =>
+        `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
+          this.state.siteRes.site_view.site.name
+        }`,
       none: "",
     });
   }
index 070be0d71ff91810d0b4f7a3c30690b852ed1a69..9c1e06ad0087e0e14cba14a38d2afc76157f8591 100644 (file)
@@ -1214,6 +1214,7 @@ export class Settings extends Component<any, SettingsState> {
     } else if (op == UserOperation.SaveUserSettings) {
       let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
       UserService.Instance.login(data);
+      location.reload();
       this.setState({ saveUserSettingsLoading: false });
       toast(i18n.t("saved"));
       window.scrollTo(0, 0);
index 7f2f1a355642a2ea98d95d80b4a0175e9f03c331..819db2923cdd886dc17b0bcb7c973561da0265e9 100644 (file)
@@ -58,10 +58,9 @@ export class VerifyEmail extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("verify_email")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("verify_email")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
index 0090c7168c6b7a06e022a1acc161d1a7cef03675..6d4122cef4deafd069277ee5bab5b0ffb9ddf529 100644 (file)
@@ -119,10 +119,9 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView => `${i18n.t("create_post")} - ${siteView.site.name}`,
-      none: "",
-    });
+    return `${i18n.t("create_post")} - ${
+      this.state.siteRes.site_view.site.name
+    }`;
   }
 
   render() {
index 6f5a6c40f7ad7e86b9c9b42aa4a43f6d4ddc1277..0fd25e2eed0ea05388385c16b54c14ee2efe24a8 100644 (file)
@@ -317,11 +317,7 @@ export class Post extends Component<any, PostState> {
   get documentTitle(): string {
     return this.state.postRes.match({
       some: res =>
-        this.state.siteRes.site_view.match({
-          some: siteView =>
-            `${res.post_view.post.name} - ${siteView.site.name}`,
-          none: "",
-        }),
+        `${res.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`,
       none: "",
     });
   }
index 792faac44bf85e593b3e77e7c89254fa58c7bfe4..52cd73b78a25417b0ff62b17085973502c6e57d2 100644 (file)
@@ -379,13 +379,10 @@ export class Search extends Component<any, SearchState> {
   }
 
   get documentTitle(): string {
-    return this.state.siteRes.site_view.match({
-      some: siteView =>
-        this.state.q
-          ? `${i18n.t("search")} - ${this.state.q} - ${siteView.site.name}`
-          : `${i18n.t("search")} - ${siteView.site.name}`,
-      none: "",
-    });
+    let siteName = this.state.siteRes.site_view.site.name;
+    return this.state.q
+      ? `${i18n.t("search")} - ${this.state.q} - ${siteName}`
+      : `${i18n.t("search")} - ${siteName}`;
   }
 
   render() {
index b97d5063f0b95d953ae0a30d25922cc65788fa35..02b74212a163ed1ad1c75b12bf322c513bd50174 100644 (file)
@@ -42,7 +42,6 @@ export class UserService {
         toast(i18n.t("logged_in"));
         IsomorphicCookie.save("jwt", jwt, { expires, secure: isHttps });
         this.setJwtInfo();
-        location.reload();
       },
       none: void 0,
     });
index afafdaa6846f767be1cd6ba43a7df7378bf369b7..473993b20adbab18b8be704da0aaac5b26f0d2cb 100644 (file)
@@ -1425,11 +1425,11 @@ export function auth(throwErr = true): Result<string, string> {
 }
 
 export function enableDownvotes(siteRes: GetSiteResponse): boolean {
-  return siteRes.site_view.map(s => s.site.enable_downvotes).unwrapOr(true);
+  return siteRes.site_view.local_site.enable_downvotes;
 }
 
 export function enableNsfw(siteRes: GetSiteResponse): boolean {
-  return siteRes.site_view.map(s => s.site.enable_nsfw).unwrapOr(false);
+  return siteRes.site_view.local_site.enable_nsfw;
 }
 
 export function postToCommentSortType(sort: SortType): CommentSortType {
@@ -1467,9 +1467,7 @@ export function canCreateCommunity(
   siteRes: GetSiteResponse,
   myUserInfo = UserService.Instance.myUserInfo
 ): boolean {
-  let adminOnly = siteRes.site_view
-    .map(s => s.site.community_creation_admin_only)
-    .unwrapOr(false);
+  let adminOnly = siteRes.site_view.local_site.community_creation_admin_only;
   return !adminOnly || amAdmin(myUserInfo);
 }
 
index c708247264f5d763eda62ce550c7198c1e0d0bec..c3dc6cf5b669a8c73272bcbbf8fd54732a941af5 100644 (file)
@@ -19,6 +19,7 @@
                "noUnusedParameters": true,\r
                "noImplicitReturns": true,\r
     "experimentalDecorators": true,\r
+    "strictNullChecks": false,\r
     "noFallthroughCasesInSwitch": true\r
        },\r
        "include": [\r
index a048c947d877bfdc62a26320d9d6704fd87c59ba..d0414dcda3464ae9984fa4dd68588404379dbb58 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -4879,10 +4879,10 @@ lcid@^1.0.0:
   dependencies:
     invert-kv "^1.0.0"
 
-lemmy-js-client@0.17.0-rc.46:
-  version "0.17.0-rc.46"
-  resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.46.tgz#c2820821ca46394fd17d1045e54c00a04b15700c"
-  integrity sha512-9HqKKsvToSB397ywXpl0jPa7KIhDaULWel0g35CgmfOkylvuTlpF8UZW20vMXr02Br9qvbRf0hRvi9s5uaji+Q==
+lemmy-js-client@0.17.0-rc.51:
+  version "0.17.0-rc.51"
+  resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.51.tgz#adf554b8837741bc9bb419df090744fc2ef8a1fa"
+  integrity sha512-AGXzQptVrdYim/5YrpAnlqAElZl5aTwqZcwffTrzXs4tL91b/APkdoPLUKASGt/5lRng2CP4cQTbykldZyjQRA==
 
 levn@^0.4.1:
   version "0.4.1"