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