diff options
author | Dessalines <tyhou13@gmx.com> | 2020-04-10 16:55:57 -0400 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-04-10 16:55:57 -0400 |
commit | bb287cbd076940bd09f6afb61b642370d020f91e (patch) | |
tree | f3fe3afa29b6445fbb2232a8c5a9133b8d691a91 /ui/src/components/admin-settings.tsx | |
parent | ed264aba3c12243352f68c2de6a5f21f23778bd0 (diff) |
Adding an admin settings page.
- Fixes #620
- Adding a UserListing component. Fixes #627
Diffstat (limited to 'ui/src/components/admin-settings.tsx')
-rw-r--r-- | ui/src/components/admin-settings.tsx | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/ui/src/components/admin-settings.tsx b/ui/src/components/admin-settings.tsx new file mode 100644 index 00000000..56af7114 --- /dev/null +++ b/ui/src/components/admin-settings.tsx @@ -0,0 +1,241 @@ +import { Component, linkEvent } from 'inferno'; +import { Subscription } from 'rxjs'; +import { retryWhen, delay, take } from 'rxjs/operators'; +import { + UserOperation, + SiteResponse, + GetSiteResponse, + SiteConfigForm, + GetSiteConfigResponse, + WebSocketJsonResponse, +} from '../interfaces'; +import { WebSocketService } from '../services'; +import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; +import autosize from 'autosize'; +import { SiteForm } from './site-form'; +import { UserListing } from './user-listing'; +import { i18n } from '../i18next'; + +interface AdminSettingsState { + siteRes: GetSiteResponse; + siteConfigRes: GetSiteConfigResponse; + siteConfigForm: SiteConfigForm; + loading: boolean; + siteConfigLoading: boolean; +} + +export class AdminSettings extends Component<any, AdminSettingsState> { + private siteConfigTextAreaId = `site-config-${randomStr()}`; + private subscription: Subscription; + private emptyState: AdminSettingsState = { + siteRes: { + site: { + id: null, + name: null, + creator_id: null, + creator_name: null, + published: null, + number_of_users: null, + number_of_posts: null, + number_of_comments: null, + number_of_communities: null, + enable_downvotes: null, + open_registration: null, + enable_nsfw: null, + }, + admins: [], + banned: [], + online: null, + }, + siteConfigForm: { + config_hjson: null, + auth: null, + }, + siteConfigRes: { + config_hjson: null, + }, + loading: true, + siteConfigLoading: null, + }; + + constructor(props: any, context: any) { + super(props, context); + + this.state = this.emptyState; + + this.subscription = WebSocketService.Instance.subject + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) + .subscribe( + msg => this.parseMessage(msg), + err => console.error(err), + () => console.log('complete') + ); + + WebSocketService.Instance.getSite(); + WebSocketService.Instance.getSiteConfig(); + } + + componentWillUnmount() { + this.subscription.unsubscribe(); + } + + render() { + return ( + <div class="container"> + {this.state.loading ? ( + <h5> + <svg class="icon icon-spinner spin"> + <use xlinkHref="#icon-spinner"></use> + </svg> + </h5> + ) : ( + <div class="row"> + <div class="col-12 col-md-6"> + <SiteForm site={this.state.siteRes.site} /> + {this.admins()} + {this.bannedUsers()} + </div> + <div class="col-12 col-md-6">{this.adminSettings()}</div> + </div> + )} + </div> + ); + } + + admins() { + return ( + <> + <h5>{capitalizeFirstLetter(i18n.t('admins'))}</h5> + <ul class="list-unstyled"> + {this.state.siteRes.admins.map(admin => ( + <li class="list-inline-item"> + <UserListing + user={{ + name: admin.name, + avatar: admin.avatar, + }} + /> + </li> + ))} + </ul> + </> + ); + } + + bannedUsers() { + return ( + <> + <h5>{i18n.t('banned_users')}</h5> + <ul class="list-unstyled"> + {this.state.siteRes.banned.map(banned => ( + <li class="list-inline-item"> + <UserListing + user={{ + name: banned.name, + avatar: banned.avatar, + }} + /> + </li> + ))} + </ul> + </> + ); + } + + adminSettings() { + return ( + <div> + <h5>{i18n.t('admin_settings')}</h5> + <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}> + <div class="form-group row"> + <label + class="col-12 col-form-label" + htmlFor={this.siteConfigTextAreaId} + > + {i18n.t('site_config')} + </label> + <div class="col-12"> + <textarea + id={this.siteConfigTextAreaId} + value={this.state.siteConfigForm.config_hjson} + onInput={linkEvent(this, this.handleSiteConfigHjsonChange)} + class="form-control text-monospace" + rows={3} + /> + </div> + </div> + <div class="form-group row"> + <div class="col-12"> + <button type="submit" class="btn btn-secondary mr-2"> + {this.state.siteConfigLoading ? ( + <svg class="icon icon-spinner spin"> + <use xlinkHref="#icon-spinner"></use> + </svg> + ) : ( + capitalizeFirstLetter(i18n.t('save')) + )} + </button> + </div> + </div> + </form> + </div> + ); + } + + handleSiteConfigSubmit(i: AdminSettings, event: any) { + event.preventDefault(); + i.state.siteConfigLoading = true; + WebSocketService.Instance.saveSiteConfig(i.state.siteConfigForm); + i.setState(i.state); + } + + handleSiteConfigHjsonChange(i: AdminSettings, event: any) { + i.state.siteConfigForm.config_hjson = event.target.value; + i.setState(i.state); + } + + parseMessage(msg: WebSocketJsonResponse) { + console.log(msg); + let res = wsJsonToRes(msg); + if (msg.error) { + toast(i18n.t(msg.error), 'danger'); + this.context.router.history.push('/'); + this.state.loading = false; + this.setState(this.state); + return; + } else if (msg.reconnect) { + } else if (res.op == UserOperation.GetSite) { + let data = res.data as GetSiteResponse; + + // This means it hasn't been set up yet + if (!data.site) { + this.context.router.history.push('/setup'); + } + this.state.siteRes = data; + this.setState(this.state); + document.title = `${i18n.t('admin_settings')} - ${ + this.state.siteRes.site.name + }`; + } else if (res.op == UserOperation.EditSite) { + let data = res.data as SiteResponse; + this.state.siteRes.site = data.site; + this.setState(this.state); + toast(i18n.t('site_saved')); + } else if (res.op == UserOperation.GetSiteConfig) { + let data = res.data as GetSiteConfigResponse; + this.state.siteConfigRes = data; + this.state.loading = false; + this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson; + this.setState(this.state); + var textarea: any = document.getElementById(this.siteConfigTextAreaId); + autosize(textarea); + } else if (res.op == UserOperation.SaveSiteConfig) { + let data = res.data as GetSiteConfigResponse; + this.state.siteConfigRes = data; + this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson; + this.state.siteConfigLoading = false; + toast(i18n.t('site_saved')); + this.setState(this.state); + } + } +} |