]> Untitled Git - lemmy-ui.git/blob - src/shared/components/admin-settings.tsx
Merge remote-tracking branch 'origin/drone-ci' into drone-ci-dess
[lemmy-ui.git] / src / shared / components / admin-settings.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Subscription } from 'rxjs';
3 import {
4   UserOperation,
5   SiteResponse,
6   GetSiteResponse,
7   SaveSiteConfig,
8   GetSiteConfigResponse,
9   GetSiteConfig,
10 } from 'lemmy-js-client';
11 import { WebSocketService } from '../services';
12 import {
13   wsJsonToRes,
14   capitalizeFirstLetter,
15   toast,
16   randomStr,
17   setIsoData,
18   wsSubscribe,
19   isBrowser,
20   wsUserOp,
21   wsClient,
22   authField,
23 } from '../utils';
24 import autosize from 'autosize';
25 import { SiteForm } from './site-form';
26 import { UserListing } from './user-listing';
27 import { HtmlTags } from './html-tags';
28 import { i18n } from '../i18next';
29 import { InitialFetchRequest } from 'shared/interfaces';
30
31 interface AdminSettingsState {
32   siteRes: GetSiteResponse;
33   siteConfigRes: GetSiteConfigResponse;
34   siteConfigForm: SaveSiteConfig;
35   loading: boolean;
36   siteConfigLoading: boolean;
37 }
38
39 export class AdminSettings extends Component<any, AdminSettingsState> {
40   private siteConfigTextAreaId = `site-config-${randomStr()}`;
41   private isoData = setIsoData(this.context);
42   private subscription: Subscription;
43   private emptyState: AdminSettingsState = {
44     siteRes: this.isoData.site_res,
45     siteConfigForm: {
46       config_hjson: null,
47       auth: authField(),
48     },
49     siteConfigRes: {
50       config_hjson: null,
51     },
52     loading: true,
53     siteConfigLoading: null,
54   };
55
56   constructor(props: any, context: any) {
57     super(props, context);
58
59     this.state = this.emptyState;
60
61     this.parseMessage = this.parseMessage.bind(this);
62     this.subscription = wsSubscribe(this.parseMessage);
63
64     // Only fetch the data if coming from another route
65     if (this.isoData.path == this.context.router.route.match.url) {
66       this.state.siteConfigRes = this.isoData.routeData[0];
67       this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
68       this.state.siteConfigLoading = false;
69       this.state.loading = false;
70     } else {
71       WebSocketService.Instance.send(
72         wsClient.getSiteConfig({
73           auth: authField(),
74         })
75       );
76     }
77   }
78
79   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
80     let form: GetSiteConfig = { auth: req.auth };
81     return [req.client.getSiteConfig(form)];
82   }
83
84   componentDidMount() {
85     if (isBrowser()) {
86       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
87       autosize(textarea);
88     }
89   }
90
91   componentWillUnmount() {
92     if (isBrowser()) {
93       this.subscription.unsubscribe();
94     }
95   }
96
97   get documentTitle(): string {
98     return `${i18n.t('admin_settings')} - ${
99       this.state.siteRes.site_view.site.name
100     }`;
101   }
102
103   render() {
104     return (
105       <div class="container">
106         <HtmlTags
107           title={this.documentTitle}
108           path={this.context.router.route.match.url}
109         />
110         {this.state.loading ? (
111           <h5>
112             <svg class="icon icon-spinner spin">
113               <use xlinkHref="#icon-spinner"></use>
114             </svg>
115           </h5>
116         ) : (
117           <div class="row">
118             <div class="col-12 col-md-6">
119               {this.state.siteRes.site_view.site.id && (
120                 <SiteForm site={this.state.siteRes.site_view.site} />
121               )}
122               {this.admins()}
123               {this.bannedUsers()}
124             </div>
125             <div class="col-12 col-md-6">{this.adminSettings()}</div>
126           </div>
127         )}
128       </div>
129     );
130   }
131
132   admins() {
133     return (
134       <>
135         <h5>{capitalizeFirstLetter(i18n.t('admins'))}</h5>
136         <ul class="list-unstyled">
137           {this.state.siteRes.admins.map(admin => (
138             <li class="list-inline-item">
139               <UserListing user={admin.user} />
140             </li>
141           ))}
142         </ul>
143       </>
144     );
145   }
146
147   bannedUsers() {
148     return (
149       <>
150         <h5>{i18n.t('banned_users')}</h5>
151         <ul class="list-unstyled">
152           {this.state.siteRes.banned.map(banned => (
153             <li class="list-inline-item">
154               <UserListing user={banned.user} />
155             </li>
156           ))}
157         </ul>
158       </>
159     );
160   }
161
162   adminSettings() {
163     return (
164       <div>
165         <h5>{i18n.t('admin_settings')}</h5>
166         <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}>
167           <div class="form-group row">
168             <label
169               class="col-12 col-form-label"
170               htmlFor={this.siteConfigTextAreaId}
171             >
172               {i18n.t('site_config')}
173             </label>
174             <div class="col-12">
175               <textarea
176                 id={this.siteConfigTextAreaId}
177                 value={this.state.siteConfigForm.config_hjson}
178                 onInput={linkEvent(this, this.handleSiteConfigHjsonChange)}
179                 class="form-control text-monospace"
180                 rows={3}
181               />
182             </div>
183           </div>
184           <div class="form-group row">
185             <div class="col-12">
186               <button type="submit" class="btn btn-secondary mr-2">
187                 {this.state.siteConfigLoading ? (
188                   <svg class="icon icon-spinner spin">
189                     <use xlinkHref="#icon-spinner"></use>
190                   </svg>
191                 ) : (
192                   capitalizeFirstLetter(i18n.t('save'))
193                 )}
194               </button>
195             </div>
196           </div>
197         </form>
198       </div>
199     );
200   }
201
202   handleSiteConfigSubmit(i: AdminSettings, event: any) {
203     event.preventDefault();
204     i.state.siteConfigLoading = true;
205     WebSocketService.Instance.send(
206       wsClient.saveSiteConfig(i.state.siteConfigForm)
207     );
208     i.setState(i.state);
209   }
210
211   handleSiteConfigHjsonChange(i: AdminSettings, event: any) {
212     i.state.siteConfigForm.config_hjson = event.target.value;
213     i.setState(i.state);
214   }
215
216   parseMessage(msg: any) {
217     let op = wsUserOp(msg);
218     if (msg.error) {
219       toast(i18n.t(msg.error), 'danger');
220       this.context.router.history.push('/');
221       this.state.loading = false;
222       this.setState(this.state);
223       return;
224     } else if (msg.reconnect) {
225     } else if (op == UserOperation.EditSite) {
226       let data = wsJsonToRes<SiteResponse>(msg).data;
227       this.state.siteRes.site_view = data.site_view;
228       this.setState(this.state);
229       toast(i18n.t('site_saved'));
230     } else if (op == UserOperation.GetSiteConfig) {
231       let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
232       this.state.siteConfigRes = data;
233       this.state.loading = false;
234       this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
235       this.setState(this.state);
236       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
237       autosize(textarea);
238     } else if (op == UserOperation.SaveSiteConfig) {
239       let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
240       this.state.siteConfigRes = data;
241       this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
242       this.state.siteConfigLoading = false;
243       toast(i18n.t('site_saved'));
244       this.setState(this.state);
245     }
246   }
247 }