1 import { None, Option, Some } from "@sniptt/monads";
2 import autosize from "autosize";
3 import { Component, linkEvent } from "inferno";
17 } from "lemmy-js-client";
18 import { Subscription } from "rxjs";
19 import { i18n } from "../../i18next";
20 import { InitialFetchRequest } from "../../interfaces";
21 import { WebSocketService } from "../../services";
24 capitalizeFirstLetter,
33 import { HtmlTags } from "../common/html-tags";
34 import { Spinner } from "../common/icon";
35 import { PersonListing } from "../person/person-listing";
36 import { SiteForm } from "./site-form";
38 interface AdminSettingsState {
39 siteRes: GetSiteResponse;
40 siteConfigRes: Option<GetSiteConfigResponse>;
41 siteConfigHjson: Option<string>;
42 banned: PersonViewSafe[];
44 siteConfigLoading: boolean;
45 leaveAdminTeamLoading: boolean;
48 export class AdminSettings extends Component<any, AdminSettingsState> {
49 private siteConfigTextAreaId = `site-config-${randomStr()}`;
50 private isoData = setIsoData(
52 GetSiteConfigResponse,
55 private subscription: Subscription;
56 private emptyState: AdminSettingsState = {
57 siteRes: this.isoData.site_res,
58 siteConfigHjson: None,
62 siteConfigLoading: null,
63 leaveAdminTeamLoading: null,
66 constructor(props: any, context: any) {
67 super(props, context);
69 this.state = this.emptyState;
71 this.parseMessage = this.parseMessage.bind(this);
72 this.subscription = wsSubscribe(this.parseMessage);
74 // Only fetch the data if coming from another route
75 if (this.isoData.path == this.context.router.route.match.url) {
76 this.state.siteConfigRes = Some(
77 this.isoData.routeData[0] as GetSiteConfigResponse
79 this.state.siteConfigHjson = this.state.siteConfigRes.map(
83 this.isoData.routeData[1] as BannedPersonsResponse
85 this.state.siteConfigLoading = false;
86 this.state.loading = false;
88 WebSocketService.Instance.send(
89 wsClient.getSiteConfig({
90 auth: auth().unwrap(),
93 WebSocketService.Instance.send(
94 wsClient.getBannedPersons({
95 auth: auth().unwrap(),
101 static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
102 let promises: Promise<any>[] = [];
104 let siteConfigForm = new GetSiteConfig({ auth: req.auth.unwrap() });
105 promises.push(req.client.getSiteConfig(siteConfigForm));
107 let bannedPersonsForm = new GetBannedPersons({ auth: req.auth.unwrap() });
108 promises.push(req.client.getBannedPersons(bannedPersonsForm));
113 componentDidMount() {
115 var textarea: any = document.getElementById(this.siteConfigTextAreaId);
120 componentWillUnmount() {
122 this.subscription.unsubscribe();
126 get documentTitle(): string {
127 return this.state.siteRes.site_view.match({
128 some: siteView => `${i18n.t("admin_settings")} - ${siteView.site.name}`,
135 <div class="container">
136 {this.state.loading ? (
142 <div class="col-12 col-md-6">
144 title={this.documentTitle}
145 path={this.context.router.route.match.url}
149 {this.state.siteRes.site_view.match({
152 site={Some(siteView.site)}
153 showLocal={showLocal(this.isoData)}
161 <div class="col-12 col-md-6">{this.adminSettings()}</div>
171 <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
172 <ul class="list-unstyled">
173 {this.state.siteRes.admins.map(admin => (
174 <li class="list-inline-item">
175 <PersonListing person={admin.person} />
187 onClick={linkEvent(this, this.handleLeaveAdminTeam)}
188 class="btn btn-danger mb-2"
190 {this.state.leaveAdminTeamLoading ? (
193 i18n.t("leave_admin_team")
202 <h5>{i18n.t("banned_users")}</h5>
203 <ul class="list-unstyled">
204 {this.state.banned.map(banned => (
205 <li class="list-inline-item">
206 <PersonListing person={banned.person} />
217 <h5>{i18n.t("admin_settings")}</h5>
218 <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}>
219 <div class="form-group row">
221 class="col-12 col-form-label"
222 htmlFor={this.siteConfigTextAreaId}
224 {i18n.t("site_config")}
228 id={this.siteConfigTextAreaId}
229 value={toUndefined(this.state.siteConfigHjson)}
230 onInput={linkEvent(this, this.handleSiteConfigHjsonChange)}
231 class="form-control text-monospace"
236 <div class="form-group row">
238 <button type="submit" class="btn btn-secondary mr-2">
239 {this.state.siteConfigLoading ? (
242 capitalizeFirstLetter(i18n.t("save"))
252 handleSiteConfigSubmit(i: AdminSettings, event: any) {
253 event.preventDefault();
254 i.state.siteConfigLoading = true;
255 let form = new SaveSiteConfig({
256 config_hjson: toUndefined(i.state.siteConfigHjson),
257 auth: auth().unwrap(),
259 WebSocketService.Instance.send(wsClient.saveSiteConfig(form));
263 handleSiteConfigHjsonChange(i: AdminSettings, event: any) {
264 i.state.siteConfigHjson = event.target.value;
268 handleLeaveAdminTeam(i: AdminSettings) {
269 i.state.leaveAdminTeamLoading = true;
270 WebSocketService.Instance.send(
271 wsClient.leaveAdmin({ auth: auth().unwrap() })
276 parseMessage(msg: any) {
277 let op = wsUserOp(msg);
280 toast(i18n.t(msg.error), "danger");
281 this.context.router.history.push("/");
282 this.state.loading = false;
283 this.setState(this.state);
285 } else if (op == UserOperation.EditSite) {
286 let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
287 this.state.siteRes.site_view = Some(data.site_view);
288 this.setState(this.state);
289 toast(i18n.t("site_saved"));
290 } else if (op == UserOperation.GetBannedPersons) {
291 let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
292 this.state.banned = data.banned;
293 this.setState(this.state);
294 } else if (op == UserOperation.GetSiteConfig) {
295 let data = wsJsonToRes<GetSiteConfigResponse>(msg, GetSiteConfigResponse);
296 this.state.siteConfigRes = Some(data);
297 this.state.loading = false;
298 this.state.siteConfigHjson = this.state.siteConfigRes.map(
301 this.setState(this.state);
302 var textarea: any = document.getElementById(this.siteConfigTextAreaId);
304 } else if (op == UserOperation.LeaveAdmin) {
305 let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
306 this.state.siteRes.site_view = data.site_view;
307 this.setState(this.state);
308 this.state.leaveAdminTeamLoading = false;
309 toast(i18n.t("left_admin_team"));
310 this.setState(this.state);
311 this.context.router.history.push("/");
312 } else if (op == UserOperation.SaveSiteConfig) {
313 let data = wsJsonToRes<GetSiteConfigResponse>(msg, GetSiteConfigResponse);
314 this.state.siteConfigRes = Some(data);
315 this.state.siteConfigHjson = this.state.siteConfigRes.map(
318 this.state.siteConfigLoading = false;
319 toast(i18n.t("site_saved"));
320 this.setState(this.state);