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