From b1a7a679f011e11bb521efadf9b33a80a0b5b4a7 Mon Sep 17 00:00:00 2001 From: abias Date: Sat, 20 May 2023 15:39:12 -0400 Subject: [PATCH 1/6] Refactor tabs into reuseable component --- src/shared/components/common/tabs.tsx | 54 ++++++++ src/shared/components/home/admin-settings.tsx | 124 +++++++----------- .../components/home/rate-limit-form.tsx | 11 ++ src/shared/components/person/settings.tsx | 61 ++++----- 4 files changed, 134 insertions(+), 116 deletions(-) create mode 100644 src/shared/components/common/tabs.tsx create mode 100644 src/shared/components/home/rate-limit-form.tsx diff --git a/src/shared/components/common/tabs.tsx b/src/shared/components/common/tabs.tsx new file mode 100644 index 00000000..36e1a015 --- /dev/null +++ b/src/shared/components/common/tabs.tsx @@ -0,0 +1,54 @@ +import { Component, InfernoNode, linkEvent } from "inferno"; + +interface TabItem { + key: string; + getNode: () => InfernoNode; + label: string; +} + +interface TabsProps { + tabs: TabItem[]; +} + +interface TabsState { + currentTab: string; +} + +function handleSwitchTab({ ctx, tab }: { ctx: Tabs; tab: string }) { + console.log(tab); + ctx.setState({ currentTab: tab }); +} + +export default class Tabs extends Component { + constructor(props: TabsProps, context) { + super(props, context); + + this.state = { + currentTab: props.tabs.length > 0 ? props.tabs[0].key : "", + }; + } + + render() { + return ( +
+
    + {this.props.tabs.map(({ key, label }) => ( +
  • + +
  • + ))} +
+ {this.props.tabs + .find(tab => tab.key === this.state?.currentTab) + ?.getNode()} +
+ ); + } +} diff --git a/src/shared/components/home/admin-settings.tsx b/src/shared/components/home/admin-settings.tsx index ab897fe1..3a2238ba 100644 --- a/src/shared/components/home/admin-settings.tsx +++ b/src/shared/components/home/admin-settings.tsx @@ -28,6 +28,7 @@ import { } from "../../utils"; import { HtmlTags } from "../common/html-tags"; import { Spinner } from "../common/icon"; +import Tabs from "../common/tabs"; import { PersonListing } from "../person/person-listing"; import { EmojiForm } from "./emojis-form"; import { SiteForm } from "./site-form"; @@ -39,7 +40,6 @@ interface AdminSettingsState { banned: PersonView[]; loading: boolean; leaveAdminTeamLoading: boolean; - currentTab: string; } export class AdminSettings extends Component { @@ -51,7 +51,6 @@ export class AdminSettings extends Component { banned: [], loading: true, leaveAdminTeamLoading: false, - currentTab: "site", }; constructor(props: any, context: any) { @@ -119,83 +118,56 @@ export class AdminSettings extends Component { render() { return (
+ {this.state.loading ? (
) : ( -
- -
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
- {this.state.currentTab == "site" && ( -
-
- -
-
- {this.admins()} - {this.bannedUsers()} -
-
- )} - {this.state.currentTab == "taglines" && ( -
- -
- )} - {this.state.currentTab == "emojis" && ( -
- -
- )} -
+ ( +
+
+ +
+
+ {this.admins()} + {this.bannedUsers()} +
+
+ ), + }, + { + key: "taglines", + label: i18n.t("taglines"), + getNode: () => ( +
+ +
+ ), + }, + { + key: "emojis", + label: i18n.t("emojis"), + getNode: () => ( +
+ +
+ ), + }, + ]} + /> )}
); @@ -247,10 +219,6 @@ export class AdminSettings extends Component { ); } - handleSwitchTab(i: { ctx: AdminSettings; tab: string }) { - i.ctx.setState({ currentTab: i.tab }); - } - handleLeaveAdminTeam(i: AdminSettings) { let auth = myAuth(); if (auth) { diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx new file mode 100644 index 00000000..b99c2630 --- /dev/null +++ b/src/shared/components/home/rate-limit-form.tsx @@ -0,0 +1,11 @@ +import { Component } from "inferno"; + +export default class RateLimitForm extends Component { + constructor(props, context) { + super(props, context); + } + + render() { + return <>; + } +} diff --git a/src/shared/components/person/settings.tsx b/src/shared/components/person/settings.tsx index 95b25901..f6278f7c 100644 --- a/src/shared/components/person/settings.tsx +++ b/src/shared/components/person/settings.tsx @@ -54,6 +54,7 @@ import { ListingTypeSelect } from "../common/listing-type-select"; import { MarkdownTextArea } from "../common/markdown-textarea"; import { SearchableSelect } from "../common/searchable-select"; import { SortSelect } from "../common/sort-select"; +import Tabs from "../common/tabs"; import { CommunityLink } from "../community/community-link"; import { PersonListing } from "./person-listing"; @@ -176,6 +177,8 @@ export class Settings extends Component { this.handleBannerUpload = this.handleBannerUpload.bind(this); this.handleBannerRemove = this.handleBannerRemove.bind(this); + this.userSettings = this.userSettings.bind(this); + this.blockCards = this.blockCards.bind(this); this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); @@ -253,44 +256,26 @@ export class Settings extends Component { render() { return (
- <> - -
    -
  • - -
  • -
  • - -
  • -
- {this.state.currentTab == "settings" && this.userSettings()} - {this.state.currentTab == "blocks" && this.blockCards()} - + +
); } From 2e3c1a6cfa81ce0cb4e1ba81a80e8038e5800213 Mon Sep 17 00:00:00 2001 From: abias Date: Sun, 21 May 2023 09:07:22 -0400 Subject: [PATCH 2/6] Put rate limit options in its own tab --- src/shared/components/home/admin-settings.tsx | 12 + .../components/home/rate-limit-form.tsx | 158 +++++++- src/shared/components/home/site-form.tsx | 347 ------------------ 3 files changed, 166 insertions(+), 351 deletions(-) diff --git a/src/shared/components/home/admin-settings.tsx b/src/shared/components/home/admin-settings.tsx index 3a2238ba..8370bec9 100644 --- a/src/shared/components/home/admin-settings.tsx +++ b/src/shared/components/home/admin-settings.tsx @@ -31,6 +31,7 @@ import { Spinner } from "../common/icon"; import Tabs from "../common/tabs"; import { PersonListing } from "../person/person-listing"; import { EmojiForm } from "./emojis-form"; +import RateLimitForm from "./rate-limit-form"; import { SiteForm } from "./site-form"; import { TaglineForm } from "./tagline-form"; @@ -148,6 +149,17 @@ export class AdminSettings extends Component { ), }, + { + key: "rate_limiting", + label: "Rate Limiting", + getNode: () => ( + + ), + }, { key: "taglines", label: i18n.t("taglines"), diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx index b99c2630..95f7fee9 100644 --- a/src/shared/components/home/rate-limit-form.tsx +++ b/src/shared/components/home/rate-limit-form.tsx @@ -1,11 +1,161 @@ -import { Component } from "inferno"; +import { Component, FormEventHandler, linkEvent } from "inferno"; +import { LocalSiteRateLimit } from "lemmy-js-client"; +import { i18n } from "../../i18next"; +import Tabs from "../common/tabs"; -export default class RateLimitForm extends Component { - constructor(props, context) { +const rateLimitTypes = [ + "message", + "post", + "image", + "comment", + "search", + "register", +] as const; + +interface RateLimitsProps { + handleRateLimit: FormEventHandler; + handleRateLimitPerSecond: FormEventHandler; + rateLimitLabel: string; + rateLimitValue?: number; + rateLimitPerSecondValue?: number; +} + +interface RateLimitFormProps { + localSiteRateLimit: LocalSiteRateLimit; +} + +interface RateLimitFormState { + message?: number; + message_per_second?: number; + post?: number; + post_per_second?: number; + comment?: number; + comment_per_second?: number; + image?: number; + image_per_second?: number; + search?: number; + search_per_second?: number; + register?: number; + register_per_second?: number; +} + +function RateLimits({ + handleRateLimit, + handleRateLimitPerSecond, + rateLimitLabel, + rateLimitPerSecondValue, + rateLimitValue, +}: RateLimitsProps) { + return ( +
+ + + + +
+ ); +} + +function handleRateLimitChange( + { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm }, + event: any +) { + ctx.setState({ + [rateLimitType]: Number(event.target.value), + }); +} + +function handlePerSecondChange( + { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm }, + event: any +) { + ctx.setState({ + [`${rateLimitType}_per_second`]: Number(event.target.value), + }); +} + +export default class RateLimitsForm extends Component< + RateLimitFormProps, + RateLimitFormState +> { + state: RateLimitFormState = {}; + constructor(props: RateLimitFormProps, context) { super(props, context); + + const { + comment, + comment_per_second, + image, + image_per_second, + message, + message_per_second, + post, + post_per_second, + register, + register_per_second, + search, + search_per_second, + } = props.localSiteRateLimit; + + this.state = { + comment, + comment_per_second, + image, + image_per_second, + message, + message_per_second, + post, + post_per_second, + register, + register_per_second, + search, + search_per_second, + }; } render() { - return <>; + return ( + ({ + key: rateLimitType, + label: rateLimitType, + getNode: () => ( + + ), + }))} + /> + ); } } diff --git a/src/shared/components/home/site-form.tsx b/src/shared/components/home/site-form.tsx index ea4d25e8..d3d3679f 100644 --- a/src/shared/components/home/site-form.tsx +++ b/src/shared/components/home/site-form.tsx @@ -78,7 +78,6 @@ export class SiteForm extends Component { let site = this.props.siteRes.site_view.site; let ls = this.props.siteRes.site_view.local_site; - let lsrl = this.props.siteRes.site_view.local_site_rate_limit; this.state = { ...this.state, siteForm: { @@ -103,18 +102,6 @@ export class SiteForm extends Component { discussion_languages: this.props.siteRes.discussion_languages, slur_filter_regex: ls.slur_filter_regex, actor_name_max_length: ls.actor_name_max_length, - rate_limit_message: lsrl.message, - rate_limit_message_per_second: lsrl.message_per_second, - rate_limit_comment: lsrl.comment, - rate_limit_comment_per_second: lsrl.comment_per_second, - rate_limit_image: lsrl.image, - rate_limit_image_per_second: lsrl.image_per_second, - rate_limit_post: lsrl.post, - rate_limit_post_per_second: lsrl.post_per_second, - rate_limit_register: lsrl.register, - rate_limit_register_per_second: lsrl.register_per_second, - rate_limit_search: lsrl.search, - rate_limit_search_per_second: lsrl.search_per_second, federation_enabled: ls.federation_enabled, federation_debug: ls.federation_debug, federation_worker_count: ls.federation_worker_count, @@ -655,238 +642,6 @@ export class SiteForm extends Component { )} -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
+
+
+ ); } + + componentDidUpdate({ localSiteRateLimit }: RateLimitFormProps) { + if ( + this.state.loading && + Object.entries(localSiteRateLimit).some( + ([key, val]) => this.state.form[key] !== val + ) + ) { + this.setState({ loading: false }); + } + } } From 132f241e636e63833ec3b9368266780a9e4a947b Mon Sep 17 00:00:00 2001 From: abias Date: Sun, 21 May 2023 15:11:20 -0400 Subject: [PATCH 4/6] Remove console log --- src/shared/components/common/tabs.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/components/common/tabs.tsx b/src/shared/components/common/tabs.tsx index 61ed396e..17980a47 100644 --- a/src/shared/components/common/tabs.tsx +++ b/src/shared/components/common/tabs.tsx @@ -15,7 +15,6 @@ interface TabsState { } function handleSwitchTab({ ctx, tab }: { ctx: Tabs; tab: string }) { - console.log(tab); ctx.setState({ currentTab: tab }); } From 9998d64d754c05349549e2dcbb5b69ad026dd13b Mon Sep 17 00:00:00 2001 From: abias Date: Sun, 21 May 2023 15:31:42 -0400 Subject: [PATCH 5/6] Add heading tag to rate limit form --- src/shared/components/home/rate-limit-form.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx index db37090c..d4b68beb 100644 --- a/src/shared/components/home/rate-limit-form.tsx +++ b/src/shared/components/home/rate-limit-form.tsx @@ -171,6 +171,7 @@ export default class RateLimitsForm extends Component< render() { return (
+
Rate Limit Options
({ key: rateLimitType, From 98167b50dc5c5d9e93c2eb29af8df822e0a0d38f Mon Sep 17 00:00:00 2001 From: abias Date: Tue, 23 May 2023 19:31:33 -0400 Subject: [PATCH 6/6] Add translations --- src/shared/components/home/rate-limit-form.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx index d4b68beb..8f2a1a81 100644 --- a/src/shared/components/home/rate-limit-form.tsx +++ b/src/shared/components/home/rate-limit-form.tsx @@ -18,7 +18,6 @@ const rateLimitTypes = [ interface RateLimitsProps { handleRateLimit: FormEventHandler; handleRateLimitPerSecond: FormEventHandler; - rateLimitLabel: string; rateLimitValue?: number; rateLimitPerSecondValue?: number; } @@ -49,14 +48,13 @@ interface RateLimitFormState { function RateLimits({ handleRateLimit, handleRateLimitPerSecond, - rateLimitLabel, rateLimitPerSecondValue, rateLimitValue, }: RateLimitsProps) { return (
-
Rate Limit Options
+
{i18n.t("rate_limit_header")}
({ key: rateLimitType, - label: rateLimitType, + label: i18n.t(`rate_limit_${rateLimitType}`), getNode: () => (