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