mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-25 15:39:25 +00:00
Adding new site setup fields. (#840)
This commit is contained in:
parent
8fdbaf4499
commit
24548ccba8
32
dev.dockerfile
Normal file
32
dev.dockerfile
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
FROM node:alpine as builder
|
||||||
|
RUN apk update && apk add curl yarn python3 build-base gcc wget git --no-cache
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Cache deps
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
RUN yarn install --ignore-scripts --prefer-offline --pure-lockfile
|
||||||
|
|
||||||
|
# Build
|
||||||
|
COPY generate_translations.js \
|
||||||
|
tsconfig.json \
|
||||||
|
webpack.config.js \
|
||||||
|
.babelrc \
|
||||||
|
./
|
||||||
|
|
||||||
|
COPY lemmy-translations lemmy-translations
|
||||||
|
COPY src src
|
||||||
|
|
||||||
|
# Set UI version
|
||||||
|
RUN echo "export const VERSION = 'dev';" > "src/shared/version.ts"
|
||||||
|
|
||||||
|
RUN yarn install --ignore-scripts --prefer-offline
|
||||||
|
RUN yarn build:dev
|
||||||
|
|
||||||
|
FROM node:alpine as runner
|
||||||
|
COPY --from=builder /usr/src/app/dist /app/dist
|
||||||
|
COPY --from=builder /usr/src/app/node_modules /app/node_modules
|
||||||
|
|
||||||
|
EXPOSE 1234
|
||||||
|
WORKDIR /app
|
||||||
|
CMD node dist/js/server.js
|
|
@ -1 +1 @@
|
||||||
Subproject commit 94b9b5debdaa40facf13a852cb096ef0cbd34ad7
|
Subproject commit 46f4b3e8676c23d4a8100ce78330eceed7bcf053
|
|
@ -24,7 +24,6 @@
|
||||||
"@babel/preset-typescript": "^7.18.6",
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@babel/runtime": "^7.18.9",
|
"@babel/runtime": "^7.18.9",
|
||||||
"@sniptt/monads": "^0.5.10",
|
"@sniptt/monads": "^0.5.10",
|
||||||
"@typescript-eslint/parser": "^5.31.0",
|
|
||||||
"autosize": "^5.0.1",
|
"autosize": "^5.0.1",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"babel-plugin-inferno": "^6.5.0",
|
"babel-plugin-inferno": "^6.5.0",
|
||||||
|
@ -48,7 +47,7 @@
|
||||||
"inferno-server": "^8.0.3",
|
"inferno-server": "^8.0.3",
|
||||||
"isomorphic-cookie": "^1.2.4",
|
"isomorphic-cookie": "^1.2.4",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"lemmy-js-client": "0.17.0-rc.46",
|
"lemmy-js-client": "0.17.0-rc.51",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"markdown-it-container": "^3.0.0",
|
"markdown-it-container": "^3.0.0",
|
||||||
"markdown-it-footnote": "^3.0.3",
|
"markdown-it-footnote": "^3.0.3",
|
||||||
|
@ -82,6 +81,7 @@
|
||||||
"@types/node-fetch": "^2.6.2",
|
"@types/node-fetch": "^2.6.2",
|
||||||
"@types/serialize-javascript": "^5.0.1",
|
"@types/serialize-javascript": "^5.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
||||||
|
"@typescript-eslint/parser": "^5.31.0",
|
||||||
"bootstrap": "^5.2.0",
|
"bootstrap": "^5.2.0",
|
||||||
"bootswatch": "^5.2.0",
|
"bootswatch": "^5.2.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.20.0",
|
||||||
|
|
|
@ -24,23 +24,21 @@ export class App extends Component<any, any> {
|
||||||
<>
|
<>
|
||||||
<Provider i18next={i18n}>
|
<Provider i18next={i18n}>
|
||||||
<div>
|
<div>
|
||||||
<Theme defaultTheme={siteView.map(s => s.site.default_theme)} />
|
<Theme defaultTheme={siteView.local_site.default_theme} />
|
||||||
{siteView
|
{siteView.site.icon.match({
|
||||||
.andThen(s => s.site.icon)
|
some: icon => (
|
||||||
.match({
|
<Helmet>
|
||||||
some: icon => (
|
<link
|
||||||
<Helmet>
|
id="favicon"
|
||||||
<link
|
rel="shortcut icon"
|
||||||
id="favicon"
|
type="image/x-icon"
|
||||||
rel="shortcut icon"
|
href={icon || favIconUrl}
|
||||||
type="image/x-icon"
|
/>
|
||||||
href={icon || favIconUrl}
|
<link rel="apple-touch-icon" href={icon || favIconPngUrl} />
|
||||||
/>
|
</Helmet>
|
||||||
<link rel="apple-touch-icon" href={icon || favIconPngUrl} />
|
),
|
||||||
</Helmet>
|
none: <></>,
|
||||||
),
|
})}
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
<Navbar siteRes={siteRes} />
|
<Navbar siteRes={siteRes} />
|
||||||
<div className="mt-4 p-0 fl-1">
|
<div className="mt-4 p-0 fl-1">
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
|
@ -32,9 +32,7 @@ export class Footer extends Component<FooterProps, any> {
|
||||||
{i18n.t("modlog")}
|
{i18n.t("modlog")}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
{this.props.site.site_view
|
{this.props.site.site_view.local_site.legal_information.isSome() && (
|
||||||
.andThen(s => s.site.legal_information)
|
|
||||||
.isSome() && (
|
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<NavLink className="nav-link" to="/legal">
|
<NavLink className="nav-link" to="/legal">
|
||||||
{i18n.t("legal_information")}
|
{i18n.t("legal_information")}
|
||||||
|
|
|
@ -90,9 +90,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.props.siteRes.site_view.isSome()) {
|
this.fetchUnreads();
|
||||||
this.fetchUnreads();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.requestNotificationPermission();
|
this.requestNotificationPermission();
|
||||||
|
@ -144,27 +142,22 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
|
|
||||||
// TODO class active corresponding to current page
|
// TODO class active corresponding to current page
|
||||||
navbar() {
|
navbar() {
|
||||||
|
let siteView = this.props.siteRes.site_view;
|
||||||
return (
|
return (
|
||||||
<nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
|
<nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
|
||||||
<div className="container-lg">
|
<div className="container-lg">
|
||||||
{this.props.siteRes.site_view.match({
|
<NavLink
|
||||||
some: siteView => (
|
to="/"
|
||||||
<NavLink
|
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
|
||||||
to="/"
|
title={siteView.site.description.unwrapOr(siteView.site.name)}
|
||||||
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
|
className="d-flex align-items-center navbar-brand mr-md-3"
|
||||||
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 />,
|
||||||
{siteView.site.icon.match({
|
none: <></>,
|
||||||
some: icon =>
|
})}
|
||||||
showAvatars() && <PictrsImage src={icon} icon />,
|
{siteView.site.name}
|
||||||
none: <></>,
|
</NavLink>
|
||||||
})}
|
|
||||||
{siteView.site.name}
|
|
||||||
</NavLink>
|
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
{UserService.Instance.myUserInfo.isSome() && (
|
{UserService.Instance.myUserInfo.isSome() && (
|
||||||
<>
|
<>
|
||||||
<ul className="navbar-nav ml-auto">
|
<ul className="navbar-nav ml-auto">
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { Option } from "@sniptt/monads";
|
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { UserService } from "../../services";
|
import { UserService } from "../../services";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
defaultTheme: Option<string>;
|
defaultTheme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Theme extends Component<Props> {
|
export class Theme extends Component<Props> {
|
||||||
|
@ -26,16 +25,13 @@ export class Theme extends Component<Props> {
|
||||||
/>
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (this.props.defaultTheme != "browser") {
|
||||||
this.props.defaultTheme.isSome() &&
|
|
||||||
this.props.defaultTheme.unwrap() != "browser"
|
|
||||||
) {
|
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
href={`/css/themes/${this.props.defaultTheme.unwrap()}.css`}
|
href={`/css/themes/${this.props.defaultTheme}.css`}
|
||||||
/>
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
);
|
);
|
||||||
|
|
|
@ -109,10 +109,9 @@ export class Communities extends Component<any, CommunitiesState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("communities")} - ${
|
||||||
some: siteView => `${i18n.t("communities")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -272,11 +272,7 @@ export class Community extends Component<any, State> {
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.communityRes.match({
|
return this.state.communityRes.match({
|
||||||
some: res =>
|
some: res =>
|
||||||
this.state.siteRes.site_view.match({
|
`${res.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`,
|
||||||
some: siteView =>
|
|
||||||
`${res.community_view.community.title} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,9 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("create_community")} - ${
|
||||||
some: siteView => `${i18n.t("create_community")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { None, Some } from "@sniptt/monads";
|
import { None } from "@sniptt/monads";
|
||||||
import autosize from "autosize";
|
import autosize from "autosize";
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import {
|
import {
|
||||||
|
@ -96,10 +96,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("admin_settings")} - ${
|
||||||
some: siteView => `${i18n.t("admin_settings")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -118,15 +117,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
||||||
description={None}
|
description={None}
|
||||||
image={None}
|
image={None}
|
||||||
/>
|
/>
|
||||||
{this.state.siteRes.site_view.match({
|
<SiteForm
|
||||||
some: siteView => (
|
siteRes={this.state.siteRes}
|
||||||
<SiteForm
|
showLocal={showLocal(this.isoData)}
|
||||||
site={Some(siteView.site)}
|
/>
|
||||||
showLocal={showLocal(this.isoData)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
{this.admins()}
|
{this.admins()}
|
||||||
|
@ -201,7 +195,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
||||||
return;
|
return;
|
||||||
} else if (op == UserOperation.EditSite) {
|
} else if (op == UserOperation.EditSite) {
|
||||||
let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
|
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"));
|
toast(i18n.t("site_saved"));
|
||||||
} else if (op == UserOperation.GetBannedPersons) {
|
} else if (op == UserOperation.GetBannedPersons) {
|
||||||
let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
|
let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
|
||||||
|
|
|
@ -131,10 +131,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
listingType: getListingTypeFromProps(
|
listingType: getListingTypeFromProps(
|
||||||
this.props,
|
this.props,
|
||||||
ListingType[
|
ListingType[
|
||||||
this.isoData.site_res.site_view.match({
|
this.isoData.site_res.site_view.local_site.default_post_listing_type
|
||||||
some: type_ => type_.site.default_post_listing_type,
|
|
||||||
none: ListingType.Local,
|
|
||||||
})
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
dataType: getDataTypeFromProps(this.props),
|
dataType: getDataTypeFromProps(this.props),
|
||||||
|
@ -199,7 +196,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// This means it hasn't been set up yet
|
// 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");
|
this.context.router.history.push("/setup");
|
||||||
}
|
}
|
||||||
setupTippy();
|
setupTippy();
|
||||||
|
@ -313,13 +310,10 @@ export class Home extends Component<any, HomeState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
let siteView = this.state.siteRes.site_view;
|
||||||
some: siteView =>
|
return this.state.siteRes.site_view.site.description.match({
|
||||||
siteView.site.description.match({
|
some: desc => `${siteView.site.name} - ${desc}`,
|
||||||
some: desc => `${siteView.site.name} - ${desc}`,
|
none: siteView.site.name,
|
||||||
none: siteView.site.name,
|
|
||||||
}),
|
|
||||||
none: "Lemmy",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +326,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
description={None}
|
description={None}
|
||||||
image={None}
|
image={None}
|
||||||
/>
|
/>
|
||||||
{this.state.siteRes.site_view.isSome() && (
|
{this.state.siteRes.site_view.local_site.site_setup && (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<main role="main" className="col-12 col-md-8">
|
<main role="main" className="col-12 col-md-8">
|
||||||
<div className="d-block d-md-none">{this.mobileView()}</div>
|
<div className="d-block d-md-none">{this.mobileView()}</div>
|
||||||
|
@ -356,6 +350,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
|
|
||||||
mobileView() {
|
mobileView() {
|
||||||
let siteRes = this.state.siteRes;
|
let siteRes = this.state.siteRes;
|
||||||
|
let siteView = siteRes.site_view;
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
|
@ -399,19 +394,15 @@ export class Home extends Component<any, HomeState> {
|
||||||
classes="icon-inline"
|
classes="icon-inline"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
{this.state.showSidebarMobile &&
|
{this.state.showSidebarMobile && (
|
||||||
siteRes.site_view.match({
|
<SiteSidebar
|
||||||
some: siteView => (
|
site={siteView.site}
|
||||||
<SiteSidebar
|
admins={Some(siteRes.admins)}
|
||||||
site={siteView.site}
|
counts={Some(siteView.counts)}
|
||||||
admins={Some(siteRes.admins)}
|
online={Some(siteRes.online)}
|
||||||
counts={Some(siteView.counts)}
|
showLocal={showLocal(this.isoData)}
|
||||||
online={Some(siteRes.online)}
|
/>
|
||||||
showLocal={showLocal(this.isoData)}
|
)}
|
||||||
/>
|
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
{this.state.showTrendingMobile && (
|
{this.state.showTrendingMobile && (
|
||||||
<div className="col-12 card border-secondary mb-3">
|
<div className="col-12 card border-secondary mb-3">
|
||||||
<div className="card-body">{this.trendingCommunities()}</div>
|
<div className="card-body">{this.trendingCommunities()}</div>
|
||||||
|
@ -429,6 +420,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
|
|
||||||
mySidebar() {
|
mySidebar() {
|
||||||
let siteRes = this.state.siteRes;
|
let siteRes = this.state.siteRes;
|
||||||
|
let siteView = siteRes.site_view;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{!this.state.loading && (
|
{!this.state.loading && (
|
||||||
|
@ -441,18 +433,13 @@ export class Home extends Component<any, HomeState> {
|
||||||
{this.exploreCommunitiesButton()}
|
{this.exploreCommunitiesButton()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{siteRes.site_view.match({
|
<SiteSidebar
|
||||||
some: siteView => (
|
site={siteView.site}
|
||||||
<SiteSidebar
|
admins={Some(siteRes.admins)}
|
||||||
site={siteView.site}
|
counts={Some(siteView.counts)}
|
||||||
admins={Some(siteRes.admins)}
|
online={Some(siteRes.online)}
|
||||||
counts={Some(siteView.counts)}
|
showLocal={showLocal(this.isoData)}
|
||||||
online={Some(siteRes.online)}
|
/>
|
||||||
showLocal={showLocal(this.isoData)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
{this.hasFollows && (
|
{this.hasFollows && (
|
||||||
<div className="card border-secondary mb-3">
|
<div className="card border-secondary mb-3">
|
||||||
<div className="card-body">{this.subscribedCommunities()}</div>
|
<div className="card-body">{this.subscribedCommunities()}</div>
|
||||||
|
@ -749,7 +736,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
this.setState({ trendingCommunities: data.communities });
|
this.setState({ trendingCommunities: data.communities });
|
||||||
} else if (op == UserOperation.EditSite) {
|
} else if (op == UserOperation.EditSite) {
|
||||||
let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
|
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"));
|
toast(i18n.t("site_saved"));
|
||||||
} else if (op == UserOperation.GetPosts) {
|
} else if (op == UserOperation.GetPosts) {
|
||||||
let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
|
let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
|
||||||
|
|
|
@ -21,10 +21,7 @@ export class Instances extends Component<any, InstancesState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
|
||||||
some: siteView => `${i18n.t("instances")} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -33,17 +33,10 @@ export class Legal extends Component<any, LegalState> {
|
||||||
description={None}
|
description={None}
|
||||||
image={None}
|
image={None}
|
||||||
/>
|
/>
|
||||||
{this.state.siteRes.site_view.match({
|
{this.state.siteRes.site_view.local_site.legal_information.match({
|
||||||
some: siteView =>
|
some: legal => (
|
||||||
siteView.site.legal_information.match({
|
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(legal)} />
|
||||||
some: legal => (
|
),
|
||||||
<div
|
|
||||||
className="md-div"
|
|
||||||
dangerouslySetInnerHTML={mdToHtml(legal)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
}),
|
|
||||||
none: <></>,
|
none: <></>,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -69,10 +69,7 @@ export class Login extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("login")} - ${this.state.siteRes.site_view.site.name}`;
|
||||||
some: siteView => `${i18n.t("login")} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLemmyMl(): boolean {
|
get isLemmyMl(): boolean {
|
||||||
|
@ -194,6 +191,8 @@ export class Login extends Component<any, State> {
|
||||||
let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
|
let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
|
||||||
this.setState(this.emptyState);
|
this.setState(this.emptyState);
|
||||||
UserService.Instance.login(data);
|
UserService.Instance.login(data);
|
||||||
|
this.props.history.push("/");
|
||||||
|
location.reload();
|
||||||
} else if (op == UserOperation.PasswordReset) {
|
} else if (op == UserOperation.PasswordReset) {
|
||||||
toast(i18n.t("reset_password_mail_sent"));
|
toast(i18n.t("reset_password_mail_sent"));
|
||||||
} else if (op == UserOperation.GetSite) {
|
} else if (op == UserOperation.GetSite) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { None, Some } from "@sniptt/monads";
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import {
|
import {
|
||||||
|
GetSiteResponse,
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
Register,
|
Register,
|
||||||
toUndefined,
|
toUndefined,
|
||||||
|
@ -13,7 +14,7 @@ import { Subscription } from "rxjs";
|
||||||
import { delay, retryWhen, take } from "rxjs/operators";
|
import { delay, retryWhen, take } from "rxjs/operators";
|
||||||
import { i18n } from "../../i18next";
|
import { i18n } from "../../i18next";
|
||||||
import { UserService, WebSocketService } from "../../services";
|
import { UserService, WebSocketService } from "../../services";
|
||||||
import { toast, wsClient } from "../../utils";
|
import { setIsoData, toast, wsClient } from "../../utils";
|
||||||
import { Spinner } from "../common/icon";
|
import { Spinner } from "../common/icon";
|
||||||
import { SiteForm } from "./site-form";
|
import { SiteForm } from "./site-form";
|
||||||
|
|
||||||
|
@ -21,10 +22,12 @@ interface State {
|
||||||
userForm: Register;
|
userForm: Register;
|
||||||
doneRegisteringUser: boolean;
|
doneRegisteringUser: boolean;
|
||||||
userLoading: boolean;
|
userLoading: boolean;
|
||||||
|
siteRes: GetSiteResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Setup extends Component<any, State> {
|
export class Setup extends Component<any, State> {
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
|
private isoData = setIsoData(this.context);
|
||||||
|
|
||||||
private emptyState: State = {
|
private emptyState: State = {
|
||||||
userForm: new Register({
|
userForm: new Register({
|
||||||
|
@ -41,6 +44,7 @@ export class Setup extends Component<any, State> {
|
||||||
}),
|
}),
|
||||||
doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
|
doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
|
||||||
userLoading: false,
|
userLoading: false,
|
||||||
|
siteRes: this.isoData.site_res,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
|
@ -75,7 +79,7 @@ export class Setup extends Component<any, State> {
|
||||||
{!this.state.doneRegisteringUser ? (
|
{!this.state.doneRegisteringUser ? (
|
||||||
this.registerUser()
|
this.registerUser()
|
||||||
) : (
|
) : (
|
||||||
<SiteForm site={None} showLocal />
|
<SiteForm siteRes={this.state.siteRes} showLocal />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -111,14 +111,14 @@ export class Signup extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
let siteView = this.state.siteRes.site_view;
|
||||||
some: siteView => `${this.titleName(siteView)} - ${siteView.site.name}`,
|
return `${this.titleName(siteView)} - ${siteView.site.name}`;
|
||||||
none: "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
titleName(siteView: SiteView): string {
|
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 {
|
get isLemmyMl(): boolean {
|
||||||
|
@ -144,248 +144,238 @@ export class Signup extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerForm() {
|
registerForm() {
|
||||||
return this.state.siteRes.site_view.match({
|
let siteView = this.state.siteRes.site_view;
|
||||||
some: siteView => (
|
return (
|
||||||
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
|
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
|
||||||
<h5>{this.titleName(siteView)}</h5>
|
<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>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
{this.isLemmyMl && (
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<label
|
<div className="mt-2 mb-0 alert alert-warning" role="alert">
|
||||||
className="col-sm-2 col-form-label"
|
<T i18nKey="lemmy_ml_registration_message">
|
||||||
htmlFor="register-username"
|
#<a href={joinLemmyUrl}>#</a>
|
||||||
>
|
</T>
|
||||||
{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>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<label className="col-sm-2 col-form-label" htmlFor="register-email">
|
<label
|
||||||
{i18n.t("email")}
|
className="col-sm-2 col-form-label"
|
||||||
</label>
|
htmlFor="register-username"
|
||||||
<div className="col-sm-10">
|
>
|
||||||
<input
|
{i18n.t("username")}
|
||||||
type="email"
|
</label>
|
||||||
id="register-email"
|
|
||||||
className="form-control"
|
<div className="col-sm-10">
|
||||||
placeholder={
|
<input
|
||||||
siteView.site.require_email_verification
|
type="text"
|
||||||
? i18n.t("required")
|
id="register-username"
|
||||||
: i18n.t("optional")
|
className="form-control"
|
||||||
}
|
value={this.state.registerForm.username}
|
||||||
value={toUndefined(this.state.registerForm.email)}
|
onInput={linkEvent(this, this.handleRegisterUsernameChange)}
|
||||||
autoComplete="email"
|
required
|
||||||
onInput={linkEvent(this, this.handleRegisterEmailChange)}
|
minLength={3}
|
||||||
required={siteView.site.require_email_verification}
|
pattern="[a-zA-Z0-9_]+"
|
||||||
minLength={3}
|
title={i18n.t("community_reqs")}
|
||||||
/>
|
/>
|
||||||
{!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>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<label
|
<label className="col-sm-2 col-form-label" htmlFor="register-email">
|
||||||
className="col-sm-2 col-form-label"
|
{i18n.t("email")}
|
||||||
htmlFor="register-password"
|
</label>
|
||||||
>
|
<div className="col-sm-10">
|
||||||
{i18n.t("password")}
|
<input
|
||||||
</label>
|
type="email"
|
||||||
<div className="col-sm-10">
|
id="register-email"
|
||||||
<input
|
className="form-control"
|
||||||
type="password"
|
placeholder={
|
||||||
id="register-password"
|
siteView.local_site.require_email_verification
|
||||||
value={this.state.registerForm.password}
|
? i18n.t("required")
|
||||||
autoComplete="new-password"
|
: i18n.t("optional")
|
||||||
onInput={linkEvent(this, this.handleRegisterPasswordChange)}
|
}
|
||||||
minLength={10}
|
value={toUndefined(this.state.registerForm.email)}
|
||||||
maxLength={60}
|
autoComplete="email"
|
||||||
className="form-control"
|
onInput={linkEvent(this, this.handleRegisterEmailChange)}
|
||||||
required
|
required={siteView.local_site.require_email_verification}
|
||||||
/>
|
minLength={3}
|
||||||
{this.state.registerForm.password && (
|
/>
|
||||||
<div className={this.passwordColorClass}>
|
{!siteView.local_site.require_email_verification &&
|
||||||
{i18n.t(this.passwordStrength as I18nKeys)}
|
!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>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<label
|
<label
|
||||||
className="col-sm-2 col-form-label"
|
className="col-sm-2 col-form-label"
|
||||||
htmlFor="register-verify-password"
|
htmlFor="register-password"
|
||||||
>
|
>
|
||||||
{i18n.t("verify_password")}
|
{i18n.t("password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="col-sm-10">
|
<div className="col-sm-10">
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
id="register-verify-password"
|
id="register-password"
|
||||||
value={this.state.registerForm.password_verify}
|
value={this.state.registerForm.password}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
onInput={linkEvent(
|
onInput={linkEvent(this, this.handleRegisterPasswordChange)}
|
||||||
this,
|
minLength={10}
|
||||||
this.handleRegisterPasswordVerifyChange
|
maxLength={60}
|
||||||
)}
|
className="form-control"
|
||||||
maxLength={60}
|
required
|
||||||
className="form-control"
|
/>
|
||||||
required
|
{this.state.registerForm.password && (
|
||||||
/>
|
<div className={this.passwordColorClass}>
|
||||||
</div>
|
{i18n.t(this.passwordStrength as I18nKeys)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{siteView.site.require_application && (
|
<div className="form-group row">
|
||||||
<>
|
<label
|
||||||
<div className="form-group row">
|
className="col-sm-2 col-form-label"
|
||||||
<div className="offset-sm-2 col-sm-10">
|
htmlFor="register-verify-password"
|
||||||
<div className="mt-2 alert alert-warning" role="alert">
|
>
|
||||||
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
|
{i18n.t("verify_password")}
|
||||||
{i18n.t("fill_out_application")}
|
</label>
|
||||||
</div>
|
<div className="col-sm-10">
|
||||||
{siteView.site.application_question.match({
|
<input
|
||||||
some: question => (
|
type="password"
|
||||||
<div
|
id="register-verify-password"
|
||||||
className="md-div"
|
value={this.state.registerForm.password_verify}
|
||||||
dangerouslySetInnerHTML={mdToHtml(question)}
|
autoComplete="new-password"
|
||||||
/>
|
onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
|
||||||
),
|
maxLength={60}
|
||||||
none: <></>,
|
className="form-control"
|
||||||
})}
|
required
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-group row">
|
{siteView.local_site.require_application && (
|
||||||
<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">
|
<div className="form-group row">
|
||||||
<label className="col-sm-2" htmlFor="register-captcha">
|
<div className="offset-sm-2 col-sm-10">
|
||||||
<span className="mr-2">{i18n.t("enter_code")}</span>
|
<div className="mt-2 alert alert-warning" role="alert">
|
||||||
<button
|
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
|
||||||
type="button"
|
{i18n.t("fill_out_application")}
|
||||||
className="btn btn-secondary"
|
</div>
|
||||||
onClick={linkEvent(this, this.handleRegenCaptcha)}
|
{siteView.local_site.application_question.match({
|
||||||
aria-label={i18n.t("captcha")}
|
some: question => (
|
||||||
>
|
<div
|
||||||
<Icon icon="refresh-cw" classes="icon-refresh-cw" />
|
className="md-div"
|
||||||
</button>
|
dangerouslySetInnerHTML={mdToHtml(question)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
none: <></>,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group row">
|
||||||
|
<label
|
||||||
|
className="col-sm-2 col-form-label"
|
||||||
|
htmlFor="application_answer"
|
||||||
|
>
|
||||||
|
{i18n.t("answer")}
|
||||||
</label>
|
</label>
|
||||||
{this.showCaptcha()}
|
<div className="col-sm-10">
|
||||||
<div className="col-sm-6">
|
<MarkdownTextArea
|
||||||
<input
|
initialContent={None}
|
||||||
type="text"
|
initialLanguageId={None}
|
||||||
className="form-control"
|
placeholder={None}
|
||||||
id="register-captcha"
|
buttonTitle={None}
|
||||||
value={toUndefined(this.state.registerForm.captcha_answer)}
|
maxLength={None}
|
||||||
onInput={linkEvent(
|
onContentChange={this.handleAnswerChange}
|
||||||
this,
|
hideNavigationWarnings
|
||||||
this.handleRegisterCaptchaAnswerChange
|
allLanguages={[]}
|
||||||
)}
|
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</>
|
||||||
{siteView.site.enable_nsfw && (
|
)}
|
||||||
<div className="form-group row">
|
|
||||||
<div className="col-sm-10">
|
{this.state.captcha.isSome() && (
|
||||||
<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="form-group row">
|
||||||
<div className="col-sm-10">
|
<label className="col-sm-2" htmlFor="register-captcha">
|
||||||
<button type="submit" className="btn btn-secondary">
|
<span className="mr-2">{i18n.t("enter_code")}</span>
|
||||||
{this.state.registerLoading ? (
|
<button
|
||||||
<Spinner />
|
type="button"
|
||||||
) : (
|
className="btn btn-secondary"
|
||||||
this.titleName(siteView)
|
onClick={linkEvent(this, this.handleRegenCaptcha)}
|
||||||
)}
|
aria-label={i18n.t("captcha")}
|
||||||
|
>
|
||||||
|
<Icon icon="refresh-cw" classes="icon-refresh-cw" />
|
||||||
</button>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
)}
|
||||||
),
|
{siteView.local_site.enable_nsfw && (
|
||||||
none: <></>,
|
<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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showCaptcha() {
|
showCaptcha() {
|
||||||
|
@ -545,6 +535,7 @@ export class Signup extends Component<any, State> {
|
||||||
if (data.jwt.isSome()) {
|
if (data.jwt.isSome()) {
|
||||||
UserService.Instance.login(data);
|
UserService.Instance.login(data);
|
||||||
this.props.history.push("/communities");
|
this.props.history.push("/communities");
|
||||||
|
location.reload();
|
||||||
} else {
|
} else {
|
||||||
if (data.verify_email_sent) {
|
if (data.verify_email_sent) {
|
||||||
toast(i18n.t("verify_email_sent"));
|
toast(i18n.t("verify_email_sent"));
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { Prompt } from "inferno-router";
|
||||||
import {
|
import {
|
||||||
CreateSite,
|
CreateSite,
|
||||||
EditSite,
|
EditSite,
|
||||||
|
GetSiteResponse,
|
||||||
ListingType,
|
ListingType,
|
||||||
Site,
|
|
||||||
toUndefined,
|
toUndefined,
|
||||||
} from "lemmy-js-client";
|
} from "lemmy-js-client";
|
||||||
import { i18n } from "../../i18next";
|
import { i18n } from "../../i18next";
|
||||||
|
@ -18,14 +18,13 @@ import {
|
||||||
} from "../../utils";
|
} from "../../utils";
|
||||||
import { Spinner } from "../common/icon";
|
import { Spinner } from "../common/icon";
|
||||||
import { ImageUploadForm } from "../common/image-upload-form";
|
import { ImageUploadForm } from "../common/image-upload-form";
|
||||||
|
import { LanguageSelect } from "../common/language-select";
|
||||||
import { ListingTypeSelect } from "../common/listing-type-select";
|
import { ListingTypeSelect } from "../common/listing-type-select";
|
||||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||||
|
|
||||||
interface SiteFormProps {
|
interface SiteFormProps {
|
||||||
site: Option<Site>; // If a site is given, that means this is an edit
|
siteRes: GetSiteResponse;
|
||||||
showLocal?: boolean;
|
showLocal?: boolean;
|
||||||
onCancel?(): void;
|
|
||||||
onEdit?(): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SiteFormState {
|
interface SiteFormState {
|
||||||
|
@ -37,9 +36,9 @@ interface SiteFormState {
|
||||||
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
private emptyState: SiteFormState = {
|
private emptyState: SiteFormState = {
|
||||||
siteForm: new EditSite({
|
siteForm: new EditSite({
|
||||||
enable_downvotes: Some(true),
|
enable_downvotes: None,
|
||||||
open_registration: Some(true),
|
open_registration: None,
|
||||||
enable_nsfw: Some(true),
|
enable_nsfw: None,
|
||||||
name: None,
|
name: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
|
@ -54,8 +53,32 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
description: None,
|
description: None,
|
||||||
community_creation_admin_only: None,
|
community_creation_admin_only: None,
|
||||||
application_email_admins: 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,
|
auth: undefined,
|
||||||
hide_modlog_mod_names: Some(true),
|
|
||||||
}),
|
}),
|
||||||
loading: false,
|
loading: false,
|
||||||
themeList: None,
|
themeList: None,
|
||||||
|
@ -79,35 +102,66 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
this.handleDefaultPostListingTypeChange =
|
this.handleDefaultPostListingTypeChange =
|
||||||
this.handleDefaultPostListingTypeChange.bind(this);
|
this.handleDefaultPostListingTypeChange.bind(this);
|
||||||
|
|
||||||
if (this.props.site.isSome()) {
|
this.handleDiscussionLanguageChange =
|
||||||
let site = this.props.site.unwrap();
|
this.handleDiscussionLanguageChange.bind(this);
|
||||||
this.state = {
|
|
||||||
...this.state,
|
let site = this.props.siteRes.site_view.site;
|
||||||
siteForm: new EditSite({
|
let ls = this.props.siteRes.site_view.local_site;
|
||||||
name: Some(site.name),
|
let lsrl = this.props.siteRes.site_view.local_site_rate_limit;
|
||||||
sidebar: site.sidebar,
|
this.state = {
|
||||||
description: site.description,
|
...this.state,
|
||||||
enable_downvotes: Some(site.enable_downvotes),
|
siteForm: new EditSite({
|
||||||
open_registration: Some(site.open_registration),
|
name: Some(site.name),
|
||||||
enable_nsfw: Some(site.enable_nsfw),
|
sidebar: site.sidebar,
|
||||||
community_creation_admin_only: Some(
|
description: site.description,
|
||||||
site.community_creation_admin_only
|
enable_downvotes: Some(ls.enable_downvotes),
|
||||||
),
|
open_registration: Some(ls.open_registration),
|
||||||
icon: site.icon,
|
enable_nsfw: Some(ls.enable_nsfw),
|
||||||
banner: site.banner,
|
community_creation_admin_only: Some(ls.community_creation_admin_only),
|
||||||
require_email_verification: Some(site.require_email_verification),
|
icon: site.icon,
|
||||||
require_application: Some(site.require_application),
|
banner: site.banner,
|
||||||
application_question: site.application_question,
|
require_email_verification: Some(ls.require_email_verification),
|
||||||
private_instance: Some(site.private_instance),
|
require_application: Some(ls.require_application),
|
||||||
default_theme: Some(site.default_theme),
|
application_question: ls.application_question,
|
||||||
default_post_listing_type: Some(site.default_post_listing_type),
|
private_instance: Some(ls.private_instance),
|
||||||
legal_information: site.legal_information,
|
default_theme: Some(ls.default_theme),
|
||||||
application_email_admins: Some(site.application_email_admins),
|
default_post_listing_type: Some(ls.default_post_listing_type),
|
||||||
hide_modlog_mod_names: site.hide_modlog_mod_names,
|
legal_information: ls.legal_information,
|
||||||
auth: undefined,
|
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() {
|
async componentDidMount() {
|
||||||
|
@ -122,7 +176,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
if (
|
if (
|
||||||
!this.state.loading &&
|
!this.state.loading &&
|
||||||
this.props.site.isNone() &&
|
!this.props.siteRes.site_view.local_site.site_setup &&
|
||||||
(this.state.siteForm.name ||
|
(this.state.siteForm.name ||
|
||||||
this.state.siteForm.sidebar ||
|
this.state.siteForm.sidebar ||
|
||||||
this.state.siteForm.application_question ||
|
this.state.siteForm.application_question ||
|
||||||
|
@ -139,12 +193,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let siteSetup = this.props.siteRes.site_view.local_site.site_setup;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Prompt
|
<Prompt
|
||||||
when={
|
when={
|
||||||
!this.state.loading &&
|
!this.state.loading &&
|
||||||
this.props.site.isNone() &&
|
!siteSetup &&
|
||||||
(this.state.siteForm.name ||
|
(this.state.siteForm.name ||
|
||||||
this.state.siteForm.sidebar ||
|
this.state.siteForm.sidebar ||
|
||||||
this.state.siteForm.application_question ||
|
this.state.siteForm.application_question ||
|
||||||
|
@ -154,7 +209,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
/>
|
/>
|
||||||
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
|
<form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
|
||||||
<h5>{`${
|
<h5>{`${
|
||||||
this.props.site.isSome()
|
siteSetup
|
||||||
? capitalizeFirstLetter(i18n.t("save"))
|
? capitalizeFirstLetter(i18n.t("save"))
|
||||||
: capitalizeFirstLetter(i18n.t("name"))
|
: capitalizeFirstLetter(i18n.t("name"))
|
||||||
} ${i18n.t("your_site")}`}</h5>
|
} ${i18n.t("your_site")}`}</h5>
|
||||||
|
@ -496,6 +551,487 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="form-group row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<button
|
<button
|
||||||
|
@ -505,21 +1041,12 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
>
|
>
|
||||||
{this.state.loading ? (
|
{this.state.loading ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : this.props.site.isSome() ? (
|
) : siteSetup ? (
|
||||||
capitalizeFirstLetter(i18n.t("save"))
|
capitalizeFirstLetter(i18n.t("save"))
|
||||||
) : (
|
) : (
|
||||||
capitalizeFirstLetter(i18n.t("create"))
|
capitalizeFirstLetter(i18n.t("create"))
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
{this.props.site.isSome() && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-secondary"
|
|
||||||
onClick={linkEvent(this, this.handleCancel)}
|
|
||||||
>
|
|
||||||
{i18n.t("cancel")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -532,9 +1059,8 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
i.setState({ loading: true });
|
i.setState({ loading: true });
|
||||||
i.setState(s => ((s.siteForm.auth = auth().unwrap()), s));
|
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));
|
WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
|
||||||
i.props.onEdit();
|
|
||||||
} else {
|
} else {
|
||||||
let sForm = i.state.siteForm;
|
let sForm = i.state.siteForm;
|
||||||
let form = new CreateSite({
|
let form = new CreateSite({
|
||||||
|
@ -556,12 +1082,52 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
application_email_admins: sForm.application_email_admins,
|
application_email_admins: sForm.application_email_admins,
|
||||||
auth: auth().unwrap(),
|
auth: auth().unwrap(),
|
||||||
hide_modlog_mod_names: sForm.hide_modlog_mod_names,
|
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));
|
WebSocketService.Instance.send(wsClient.createSite(form));
|
||||||
}
|
}
|
||||||
i.setState(i.state);
|
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) {
|
handleSiteNameChange(i: SiteForm, event: any) {
|
||||||
i.state.siteForm.name = Some(event.target.value);
|
i.state.siteForm.name = Some(event.target.value);
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
|
@ -634,10 +1200,6 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancel(i: SiteForm) {
|
|
||||||
i.props.onCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleIconUpload(url: string) {
|
handleIconUpload(url: string) {
|
||||||
this.setState(s => ((s.siteForm.icon = Some(url)), s));
|
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));
|
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) {
|
handleDefaultPostListingTypeChange(val: ListingType) {
|
||||||
this.setState(
|
this.setState(
|
||||||
s => (
|
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([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import { None, Option, Some } from "@sniptt/monads";
|
import { None, Option } from "@sniptt/monads";
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import { Link } from "inferno-router";
|
import { Link } from "inferno-router";
|
||||||
import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client";
|
import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client";
|
||||||
import { i18n } from "../../i18next";
|
import { i18n } from "../../i18next";
|
||||||
import { amAdmin, mdToHtml, numToSI } from "../../utils";
|
import { mdToHtml, numToSI } from "../../utils";
|
||||||
import { BannerIconHeader } from "../common/banner-icon-header";
|
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||||
import { Icon } from "../common/icon";
|
import { Icon } from "../common/icon";
|
||||||
import { PersonListing } from "../person/person-listing";
|
import { PersonListing } from "../person/person-listing";
|
||||||
import { SiteForm } from "./site-form";
|
|
||||||
|
|
||||||
interface SiteSidebarProps {
|
interface SiteSidebarProps {
|
||||||
site: Site;
|
site: Site;
|
||||||
|
@ -19,58 +18,40 @@ interface SiteSidebarProps {
|
||||||
|
|
||||||
interface SiteSidebarState {
|
interface SiteSidebarState {
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
showEdit: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
|
export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
|
||||||
private emptyState: SiteSidebarState = {
|
private emptyState: SiteSidebarState = {
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
showEdit: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.handleEditCancel = this.handleEditCancel.bind(this);
|
|
||||||
this.handleEditSite = this.handleEditSite.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let site = this.props.site;
|
|
||||||
return (
|
return (
|
||||||
<div className="card border-secondary mb-3">
|
<div className="card border-secondary mb-3">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
{!this.state.showEdit ? (
|
<div>
|
||||||
<div>
|
<div className="mb-2">{this.siteName()}</div>
|
||||||
<div className="mb-2">
|
{!this.state.collapsed && (
|
||||||
{this.siteName()}
|
<>
|
||||||
{this.props.admins.isSome() && this.adminButtons()}
|
<BannerIconHeader banner={this.props.site.banner} icon={None} />
|
||||||
</div>
|
{this.siteInfo()}
|
||||||
{!this.state.collapsed && (
|
</>
|
||||||
<>
|
)}
|
||||||
<BannerIconHeader banner={site.banner} icon={None} />
|
</div>
|
||||||
{this.siteInfo()}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<SiteForm
|
|
||||||
site={Some(site)}
|
|
||||||
showLocal={this.props.showLocal}
|
|
||||||
onEdit={this.handleEditSite}
|
|
||||||
onCancel={this.handleEditCancel}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
siteName() {
|
siteName() {
|
||||||
let site = this.props.site;
|
|
||||||
return (
|
return (
|
||||||
<h5 className="mb-0 d-inline">
|
<h5 className="mb-0 d-inline">
|
||||||
{site.name}
|
{this.props.site.name}
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm text-muted"
|
className="btn btn-sm text-muted"
|
||||||
onClick={linkEvent(this, this.handleCollapseSidebar)}
|
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) {
|
siteSidebar(sidebar: string) {
|
||||||
return (
|
return (
|
||||||
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(sidebar)} />
|
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(sidebar)} />
|
||||||
|
@ -248,16 +210,4 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
|
||||||
handleCollapseSidebar(i: SiteSidebar) {
|
handleCollapseSidebar(i: SiteSidebar) {
|
||||||
i.setState({ collapsed: !i.state.collapsed });
|
i.setState({ collapsed: !i.state.collapsed });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditClick(i: SiteSidebar) {
|
|
||||||
i.setState({ showEdit: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditSite() {
|
|
||||||
this.setState({ showEdit: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEditCancel() {
|
|
||||||
this.setState({ showEdit: false });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -632,10 +632,7 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `Modlog - ${this.state.siteRes.site_view.site.name}`;
|
||||||
some: siteView => `Modlog - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -708,21 +705,18 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{this.state.siteRes.site_view.match({
|
{!this.state.siteRes.site_view.local_site
|
||||||
some: site_view =>
|
.hide_modlog_mod_names && (
|
||||||
!site_view.site.hide_modlog_mod_names.unwrapOr(false) && (
|
<div className="form-group col-sm-6">
|
||||||
<div className="form-group col-sm-6">
|
<select
|
||||||
<select
|
id="filter-mod"
|
||||||
id="filter-mod"
|
className="form-control"
|
||||||
className="form-control"
|
value={toUndefined(this.state.filter_mod)}
|
||||||
value={toUndefined(this.state.filter_mod)}
|
>
|
||||||
>
|
<option>{i18n.t("filter_by_mod")}</option>
|
||||||
<option>{i18n.t("filter_by_mod")}</option>
|
</select>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
)}
|
||||||
),
|
|
||||||
none: <></>,
|
|
||||||
})}
|
|
||||||
<div className="form-group col-sm-6">
|
<div className="form-group col-sm-6">
|
||||||
<select
|
<select
|
||||||
id="filter-user"
|
id="filter-user"
|
||||||
|
|
|
@ -153,15 +153,11 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return UserService.Instance.myUserInfo.match({
|
||||||
some: siteView =>
|
some: mui =>
|
||||||
UserService.Instance.myUserInfo.match({
|
`@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
|
||||||
some: mui =>
|
this.state.siteRes.site_view.site.name
|
||||||
`@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
|
}`,
|
||||||
siteView.site.name
|
|
||||||
}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,9 @@ export class PasswordChange extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("password_change")} - ${
|
||||||
some: siteView => `${i18n.t("password_change")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -164,6 +163,7 @@ export class PasswordChange extends Component<any, State> {
|
||||||
this.setState(this.emptyState);
|
this.setState(this.emptyState);
|
||||||
UserService.Instance.login(data);
|
UserService.Instance.login(data);
|
||||||
this.props.history.push("/");
|
this.props.history.push("/");
|
||||||
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,13 +238,9 @@ export class Profile extends Component<any, ProfileState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return this.state.personRes.match({
|
||||||
some: siteView =>
|
some: res =>
|
||||||
this.state.personRes.match({
|
`@${res.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`,
|
||||||
some: res =>
|
|
||||||
`@${res.person_view.person.name} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,15 +98,11 @@ export class RegistrationApplications extends Component<
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return UserService.Instance.myUserInfo.match({
|
||||||
some: siteView =>
|
some: mui =>
|
||||||
UserService.Instance.myUserInfo.match({
|
`@${mui.local_user_view.person.name} ${i18n.t(
|
||||||
some: mui =>
|
"registration_applications"
|
||||||
`@${mui.local_user_view.person.name} ${i18n.t(
|
)} - ${this.state.siteRes.site_view.site.name}`,
|
||||||
"registration_applications"
|
|
||||||
)} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,15 +150,11 @@ export class Reports extends Component<any, ReportsState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return UserService.Instance.myUserInfo.match({
|
||||||
some: siteView =>
|
some: mui =>
|
||||||
UserService.Instance.myUserInfo.match({
|
`@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
|
||||||
some: mui =>
|
this.state.siteRes.site_view.site.name
|
||||||
`@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
|
}`,
|
||||||
siteView.site.name
|
|
||||||
}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1214,6 +1214,7 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
} else if (op == UserOperation.SaveUserSettings) {
|
} else if (op == UserOperation.SaveUserSettings) {
|
||||||
let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
|
let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
|
||||||
UserService.Instance.login(data);
|
UserService.Instance.login(data);
|
||||||
|
location.reload();
|
||||||
this.setState({ saveUserSettingsLoading: false });
|
this.setState({ saveUserSettingsLoading: false });
|
||||||
toast(i18n.t("saved"));
|
toast(i18n.t("saved"));
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
|
|
@ -58,10 +58,9 @@ export class VerifyEmail extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("verify_email")} - ${
|
||||||
some: siteView => `${i18n.t("verify_email")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -119,10 +119,9 @@ export class CreatePost extends Component<any, CreatePostState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
return `${i18n.t("create_post")} - ${
|
||||||
some: siteView => `${i18n.t("create_post")} - ${siteView.site.name}`,
|
this.state.siteRes.site_view.site.name
|
||||||
none: "",
|
}`;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -317,11 +317,7 @@ export class Post extends Component<any, PostState> {
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.postRes.match({
|
return this.state.postRes.match({
|
||||||
some: res =>
|
some: res =>
|
||||||
this.state.siteRes.site_view.match({
|
`${res.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`,
|
||||||
some: siteView =>
|
|
||||||
`${res.post_view.post.name} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
}),
|
|
||||||
none: "",
|
none: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,13 +379,10 @@ export class Search extends Component<any, SearchState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return this.state.siteRes.site_view.match({
|
let siteName = this.state.siteRes.site_view.site.name;
|
||||||
some: siteView =>
|
return this.state.q
|
||||||
this.state.q
|
? `${i18n.t("search")} - ${this.state.q} - ${siteName}`
|
||||||
? `${i18n.t("search")} - ${this.state.q} - ${siteView.site.name}`
|
: `${i18n.t("search")} - ${siteName}`;
|
||||||
: `${i18n.t("search")} - ${siteView.site.name}`,
|
|
||||||
none: "",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -42,7 +42,6 @@ export class UserService {
|
||||||
toast(i18n.t("logged_in"));
|
toast(i18n.t("logged_in"));
|
||||||
IsomorphicCookie.save("jwt", jwt, { expires, secure: isHttps });
|
IsomorphicCookie.save("jwt", jwt, { expires, secure: isHttps });
|
||||||
this.setJwtInfo();
|
this.setJwtInfo();
|
||||||
location.reload();
|
|
||||||
},
|
},
|
||||||
none: void 0,
|
none: void 0,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1425,11 +1425,11 @@ export function auth(throwErr = true): Result<string, string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function enableDownvotes(siteRes: GetSiteResponse): boolean {
|
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 {
|
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 {
|
export function postToCommentSortType(sort: SortType): CommentSortType {
|
||||||
|
@ -1467,9 +1467,7 @@ export function canCreateCommunity(
|
||||||
siteRes: GetSiteResponse,
|
siteRes: GetSiteResponse,
|
||||||
myUserInfo = UserService.Instance.myUserInfo
|
myUserInfo = UserService.Instance.myUserInfo
|
||||||
): boolean {
|
): boolean {
|
||||||
let adminOnly = siteRes.site_view
|
let adminOnly = siteRes.site_view.local_site.community_creation_admin_only;
|
||||||
.map(s => s.site.community_creation_admin_only)
|
|
||||||
.unwrapOr(false);
|
|
||||||
return !adminOnly || amAdmin(myUserInfo);
|
return !adminOnly || amAdmin(myUserInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"strictNullChecks": false,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|
|
@ -4879,10 +4879,10 @@ lcid@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
invert-kv "^1.0.0"
|
invert-kv "^1.0.0"
|
||||||
|
|
||||||
lemmy-js-client@0.17.0-rc.46:
|
lemmy-js-client@0.17.0-rc.51:
|
||||||
version "0.17.0-rc.46"
|
version "0.17.0-rc.51"
|
||||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.46.tgz#c2820821ca46394fd17d1045e54c00a04b15700c"
|
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.51.tgz#adf554b8837741bc9bb419df090744fc2ef8a1fa"
|
||||||
integrity sha512-9HqKKsvToSB397ywXpl0jPa7KIhDaULWel0g35CgmfOkylvuTlpF8UZW20vMXr02Br9qvbRf0hRvi9s5uaji+Q==
|
integrity sha512-AGXzQptVrdYim/5YrpAnlqAElZl5aTwqZcwffTrzXs4tL91b/APkdoPLUKASGt/5lRng2CP4cQTbykldZyjQRA==
|
||||||
|
|
||||||
levn@^0.4.1:
|
levn@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
|
|
Loading…
Reference in a new issue