]> Untitled Git - lemmy-ui.git/blob - src/shared/components/modlog.tsx
Adding a loading indicator for post community searching. Fixes #692 (#794)
[lemmy-ui.git] / src / shared / components / modlog.tsx
1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import { Link } from "inferno-router";
4 import {
5   AdminPurgeCommentView,
6   AdminPurgeCommunityView,
7   AdminPurgePersonView,
8   AdminPurgePostView,
9   CommunityModeratorView,
10   GetCommunity,
11   GetCommunityResponse,
12   GetModlog,
13   GetModlogResponse,
14   GetSiteResponse,
15   ModAddCommunityView,
16   ModAddView,
17   ModBanFromCommunityView,
18   ModBanView,
19   ModLockPostView,
20   ModlogActionType,
21   ModRemoveCommentView,
22   ModRemoveCommunityView,
23   ModRemovePostView,
24   ModStickyPostView,
25   ModTransferCommunityView,
26   PersonSafe,
27   toUndefined,
28   UserOperation,
29   wsJsonToRes,
30   wsUserOp,
31 } from "lemmy-js-client";
32 import moment from "moment";
33 import { Subscription } from "rxjs";
34 import { i18n } from "../i18next";
35 import { InitialFetchRequest } from "../interfaces";
36 import { WebSocketService } from "../services";
37 import {
38   amAdmin,
39   amMod,
40   auth,
41   choicesConfig,
42   debounce,
43   fetchLimit,
44   fetchUsers,
45   isBrowser,
46   setIsoData,
47   toast,
48   wsClient,
49   wsSubscribe,
50 } from "../utils";
51 import { HtmlTags } from "./common/html-tags";
52 import { Spinner } from "./common/icon";
53 import { MomentTime } from "./common/moment-time";
54 import { Paginator } from "./common/paginator";
55 import { CommunityLink } from "./community/community-link";
56 import { PersonListing } from "./person/person-listing";
57 type ModlogType = {
58   id: number;
59   type_: ModlogActionType;
60   moderator: Option<PersonSafe>;
61   view:
62     | ModRemovePostView
63     | ModLockPostView
64     | ModStickyPostView
65     | ModRemoveCommentView
66     | ModRemoveCommunityView
67     | ModBanFromCommunityView
68     | ModBanView
69     | ModAddCommunityView
70     | ModTransferCommunityView
71     | ModAddView
72     | AdminPurgePersonView
73     | AdminPurgeCommunityView
74     | AdminPurgePostView
75     | AdminPurgeCommentView;
76   when_: string;
77 };
78 var Choices: any;
79 if (isBrowser()) {
80   Choices = require("choices.js");
81 }
82
83 interface ModlogState {
84   res: Option<GetModlogResponse>;
85   communityId: Option<number>;
86   communityMods: Option<CommunityModeratorView[]>;
87   communityName: Option<string>;
88   page: number;
89   siteRes: GetSiteResponse;
90   loading: boolean;
91   filter_action: ModlogActionType;
92   filter_user: Option<number>;
93   filter_mod: Option<number>;
94 }
95
96 export class Modlog extends Component<any, ModlogState> {
97   private isoData = setIsoData(
98     this.context,
99     GetModlogResponse,
100     GetCommunityResponse
101   );
102   private subscription: Subscription;
103   private userChoices: any;
104   private modChoices: any;
105   private emptyState: ModlogState = {
106     res: None,
107     communityId: None,
108     communityMods: None,
109     communityName: None,
110     page: 1,
111     loading: true,
112     siteRes: this.isoData.site_res,
113     filter_action: ModlogActionType.All,
114     filter_user: None,
115     filter_mod: None,
116   };
117
118   constructor(props: any, context: any) {
119     super(props, context);
120     this.state = this.emptyState;
121     this.handlePageChange = this.handlePageChange.bind(this);
122
123     this.parseMessage = this.parseMessage.bind(this);
124     this.subscription = wsSubscribe(this.parseMessage);
125
126     this.state = {
127       ...this.state,
128       communityId: this.props.match.params.community_id
129         ? Some(Number(this.props.match.params.community_id))
130         : None,
131     };
132
133     // Only fetch the data if coming from another route
134     if (this.isoData.path == this.context.router.route.match.url) {
135       this.state = {
136         ...this.state,
137         res: Some(this.isoData.routeData[0] as GetModlogResponse),
138       };
139
140       if (this.isoData.routeData[1]) {
141         // Getting the moderators
142         let communityRes = Some(
143           this.isoData.routeData[1] as GetCommunityResponse
144         );
145         this.state = {
146           ...this.state,
147           communityMods: communityRes.map(c => c.moderators),
148         };
149       }
150
151       this.state = { ...this.state, loading: false };
152     } else {
153       this.refetch();
154     }
155   }
156
157   componentDidMount() {
158     this.setupUserFilter();
159     this.setupModFilter();
160   }
161
162   componentWillUnmount() {
163     if (isBrowser()) {
164       this.subscription.unsubscribe();
165     }
166   }
167
168   buildCombined(res: GetModlogResponse): ModlogType[] {
169     let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
170       id: r.mod_remove_post.id,
171       type_: ModlogActionType.ModRemovePost,
172       view: r,
173       moderator: r.moderator,
174       when_: r.mod_remove_post.when_,
175     }));
176
177     let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
178       id: r.mod_lock_post.id,
179       type_: ModlogActionType.ModLockPost,
180       view: r,
181       moderator: r.moderator,
182       when_: r.mod_lock_post.when_,
183     }));
184
185     let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
186       id: r.mod_sticky_post.id,
187       type_: ModlogActionType.ModStickyPost,
188       view: r,
189       moderator: r.moderator,
190       when_: r.mod_sticky_post.when_,
191     }));
192
193     let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
194       id: r.mod_remove_comment.id,
195       type_: ModlogActionType.ModRemoveComment,
196       view: r,
197       moderator: r.moderator,
198       when_: r.mod_remove_comment.when_,
199     }));
200
201     let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
202       id: r.mod_remove_community.id,
203       type_: ModlogActionType.ModRemoveCommunity,
204       view: r,
205       moderator: r.moderator,
206       when_: r.mod_remove_community.when_,
207     }));
208
209     let banned_from_community: ModlogType[] = res.banned_from_community.map(
210       r => ({
211         id: r.mod_ban_from_community.id,
212         type_: ModlogActionType.ModBanFromCommunity,
213         view: r,
214         moderator: r.moderator,
215         when_: r.mod_ban_from_community.when_,
216       })
217     );
218
219     let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
220       id: r.mod_add_community.id,
221       type_: ModlogActionType.ModAddCommunity,
222       view: r,
223       moderator: r.moderator,
224       when_: r.mod_add_community.when_,
225     }));
226
227     let transferred_to_community: ModlogType[] =
228       res.transferred_to_community.map(r => ({
229         id: r.mod_transfer_community.id,
230         type_: ModlogActionType.ModTransferCommunity,
231         view: r,
232         moderator: r.moderator,
233         when_: r.mod_transfer_community.when_,
234       }));
235
236     let added: ModlogType[] = res.added.map(r => ({
237       id: r.mod_add.id,
238       type_: ModlogActionType.ModAdd,
239       view: r,
240       moderator: r.moderator,
241       when_: r.mod_add.when_,
242     }));
243
244     let banned: ModlogType[] = res.banned.map(r => ({
245       id: r.mod_ban.id,
246       type_: ModlogActionType.ModBan,
247       view: r,
248       moderator: r.moderator,
249       when_: r.mod_ban.when_,
250     }));
251
252     let purged_persons: ModlogType[] = res.admin_purged_persons.map(r => ({
253       id: r.admin_purge_person.id,
254       type_: ModlogActionType.AdminPurgePerson,
255       view: r,
256       moderator: r.admin,
257       when_: r.admin_purge_person.when_,
258     }));
259
260     let purged_communities: ModlogType[] = res.admin_purged_communities.map(
261       r => ({
262         id: r.admin_purge_community.id,
263         type_: ModlogActionType.AdminPurgeCommunity,
264         view: r,
265         moderator: r.admin,
266         when_: r.admin_purge_community.when_,
267       })
268     );
269
270     let purged_posts: ModlogType[] = res.admin_purged_posts.map(r => ({
271       id: r.admin_purge_post.id,
272       type_: ModlogActionType.AdminPurgePost,
273       view: r,
274       moderator: r.admin,
275       when_: r.admin_purge_post.when_,
276     }));
277
278     let purged_comments: ModlogType[] = res.admin_purged_comments.map(r => ({
279       id: r.admin_purge_comment.id,
280       type_: ModlogActionType.AdminPurgeComment,
281       view: r,
282       moderator: r.admin,
283       when_: r.admin_purge_comment.when_,
284     }));
285
286     let combined: ModlogType[] = [];
287
288     combined.push(...removed_posts);
289     combined.push(...locked_posts);
290     combined.push(...stickied_posts);
291     combined.push(...removed_comments);
292     combined.push(...removed_communities);
293     combined.push(...banned_from_community);
294     combined.push(...added_to_community);
295     combined.push(...transferred_to_community);
296     combined.push(...added);
297     combined.push(...banned);
298     combined.push(...purged_persons);
299     combined.push(...purged_communities);
300     combined.push(...purged_posts);
301     combined.push(...purged_comments);
302
303     // Sort them by time
304     combined.sort((a, b) => b.when_.localeCompare(a.when_));
305
306     return combined;
307   }
308
309   renderModlogType(i: ModlogType) {
310     switch (i.type_) {
311       case ModlogActionType.ModRemovePost: {
312         let mrpv = i.view as ModRemovePostView;
313         return (
314           <>
315             <span>
316               {mrpv.mod_remove_post.removed.unwrapOr(false)
317                 ? "Removed "
318                 : "Restored "}
319             </span>
320             <span>
321               Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
322             </span>
323             <span>
324               {mrpv.mod_remove_post.reason.match({
325                 some: reason => <div>reason: {reason}</div>,
326                 none: <></>,
327               })}
328             </span>
329           </>
330         );
331       }
332       case ModlogActionType.ModLockPost: {
333         let mlpv = i.view as ModLockPostView;
334         return (
335           <>
336             <span>
337               {mlpv.mod_lock_post.locked.unwrapOr(false)
338                 ? "Locked "
339                 : "Unlocked "}
340             </span>
341             <span>
342               Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
343             </span>
344           </>
345         );
346       }
347       case ModlogActionType.ModStickyPost: {
348         let mspv = i.view as ModStickyPostView;
349         return (
350           <>
351             <span>
352               {mspv.mod_sticky_post.stickied.unwrapOr(false)
353                 ? "Stickied "
354                 : "Unstickied "}
355             </span>
356             <span>
357               Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
358             </span>
359           </>
360         );
361       }
362       case ModlogActionType.ModRemoveComment: {
363         let mrc = i.view as ModRemoveCommentView;
364         return (
365           <>
366             <span>
367               {mrc.mod_remove_comment.removed.unwrapOr(false)
368                 ? "Removed "
369                 : "Restored "}
370             </span>
371             <span>
372               Comment{" "}
373               <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
374                 {mrc.comment.content}
375               </Link>
376             </span>
377             <span>
378               {" "}
379               by <PersonListing person={mrc.commenter} />
380             </span>
381             <span>
382               {mrc.mod_remove_comment.reason.match({
383                 some: reason => <div>reason: {reason}</div>,
384                 none: <></>,
385               })}
386             </span>
387           </>
388         );
389       }
390       case ModlogActionType.ModRemoveCommunity: {
391         let mrco = i.view as ModRemoveCommunityView;
392         return (
393           <>
394             <span>
395               {mrco.mod_remove_community.removed.unwrapOr(false)
396                 ? "Removed "
397                 : "Restored "}
398             </span>
399             <span>
400               Community <CommunityLink community={mrco.community} />
401             </span>
402             <span>
403               {mrco.mod_remove_community.reason.match({
404                 some: reason => <div>reason: {reason}</div>,
405                 none: <></>,
406               })}
407             </span>
408             <span>
409               {mrco.mod_remove_community.expires.match({
410                 some: expires => (
411                   <div>expires: {moment.utc(expires).fromNow()}</div>
412                 ),
413                 none: <></>,
414               })}
415             </span>
416           </>
417         );
418       }
419       case ModlogActionType.ModBanFromCommunity: {
420         let mbfc = i.view as ModBanFromCommunityView;
421         return (
422           <>
423             <span>
424               {mbfc.mod_ban_from_community.banned.unwrapOr(false)
425                 ? "Banned "
426                 : "Unbanned "}{" "}
427             </span>
428             <span>
429               <PersonListing person={mbfc.banned_person} />
430             </span>
431             <span> from the community </span>
432             <span>
433               <CommunityLink community={mbfc.community} />
434             </span>
435             <span>
436               {mbfc.mod_ban_from_community.reason.match({
437                 some: reason => <div>reason: {reason}</div>,
438                 none: <></>,
439               })}
440             </span>
441             <span>
442               {mbfc.mod_ban_from_community.expires.match({
443                 some: expires => (
444                   <div>expires: {moment.utc(expires).fromNow()}</div>
445                 ),
446                 none: <></>,
447               })}
448             </span>
449           </>
450         );
451       }
452       case ModlogActionType.ModAddCommunity: {
453         let mac = i.view as ModAddCommunityView;
454         return (
455           <>
456             <span>
457               {mac.mod_add_community.removed.unwrapOr(false)
458                 ? "Removed "
459                 : "Appointed "}{" "}
460             </span>
461             <span>
462               <PersonListing person={mac.modded_person} />
463             </span>
464             <span> as a mod to the community </span>
465             <span>
466               <CommunityLink community={mac.community} />
467             </span>
468           </>
469         );
470       }
471       case ModlogActionType.ModTransferCommunity: {
472         let mtc = i.view as ModTransferCommunityView;
473         return (
474           <>
475             <span>
476               {mtc.mod_transfer_community.removed.unwrapOr(false)
477                 ? "Removed "
478                 : "Transferred "}{" "}
479             </span>
480             <span>
481               <CommunityLink community={mtc.community} />
482             </span>
483             <span> to </span>
484             <span>
485               <PersonListing person={mtc.modded_person} />
486             </span>
487           </>
488         );
489       }
490       case ModlogActionType.ModBan: {
491         let mb = i.view as ModBanView;
492         return (
493           <>
494             <span>
495               {mb.mod_ban.banned.unwrapOr(false) ? "Banned " : "Unbanned "}{" "}
496             </span>
497             <span>
498               <PersonListing person={mb.banned_person} />
499             </span>
500             <span>
501               {mb.mod_ban.reason.match({
502                 some: reason => <div>reason: {reason}</div>,
503                 none: <></>,
504               })}
505             </span>
506             <span>
507               {mb.mod_ban.expires.match({
508                 some: expires => (
509                   <div>expires: {moment.utc(expires).fromNow()}</div>
510                 ),
511                 none: <></>,
512               })}
513             </span>
514           </>
515         );
516       }
517       case ModlogActionType.ModAdd: {
518         let ma = i.view as ModAddView;
519         return (
520           <>
521             <span>
522               {ma.mod_add.removed.unwrapOr(false) ? "Removed " : "Appointed "}{" "}
523             </span>
524             <span>
525               <PersonListing person={ma.modded_person} />
526             </span>
527             <span> as an admin </span>
528           </>
529         );
530       }
531       case ModlogActionType.AdminPurgePerson: {
532         let ap = i.view as AdminPurgePersonView;
533         return (
534           <>
535             <span>Purged a Person</span>
536             <span>
537               {ap.admin_purge_person.reason.match({
538                 some: reason => <div>reason: {reason}</div>,
539                 none: <></>,
540               })}
541             </span>
542           </>
543         );
544       }
545       case ModlogActionType.AdminPurgeCommunity: {
546         let ap = i.view as AdminPurgeCommunityView;
547         return (
548           <>
549             <span>Purged a Community</span>
550             <span>
551               {ap.admin_purge_community.reason.match({
552                 some: reason => <div>reason: {reason}</div>,
553                 none: <></>,
554               })}
555             </span>
556           </>
557         );
558       }
559       case ModlogActionType.AdminPurgePost: {
560         let ap = i.view as AdminPurgePostView;
561         return (
562           <>
563             <span>Purged a Post from from </span>
564             <CommunityLink community={ap.community} />
565             <span>
566               {ap.admin_purge_post.reason.match({
567                 some: reason => <div>reason: {reason}</div>,
568                 none: <></>,
569               })}
570             </span>
571           </>
572         );
573       }
574       case ModlogActionType.AdminPurgeComment: {
575         let ap = i.view as AdminPurgeCommentView;
576         return (
577           <>
578             <span>
579               Purged a Comment from{" "}
580               <Link to={`/post/${ap.post.id}`}>{ap.post.name}</Link>
581             </span>
582             <span>
583               {ap.admin_purge_comment.reason.match({
584                 some: reason => <div>reason: {reason}</div>,
585                 none: <></>,
586               })}
587             </span>
588           </>
589         );
590       }
591       default:
592         return <div />;
593     }
594   }
595
596   combined() {
597     let combined = this.state.res.map(this.buildCombined).unwrapOr([]);
598
599     return (
600       <tbody>
601         {combined.map(i => (
602           <tr key={i.id}>
603             <td>
604               <MomentTime published={i.when_} updated={None} />
605             </td>
606             <td>
607               {this.amAdminOrMod ? (
608                 <PersonListing person={i.moderator.unwrap()} />
609               ) : (
610                 <div>{this.modOrAdminText(i.moderator)}</div>
611               )}
612             </td>
613             <td>{this.renderModlogType(i)}</td>
614           </tr>
615         ))}
616       </tbody>
617     );
618   }
619
620   get amAdminOrMod(): boolean {
621     return (
622       amAdmin(Some(this.state.siteRes.admins)) ||
623       amMod(this.state.communityMods)
624     );
625   }
626
627   modOrAdminText(person: Option<PersonSafe>): string {
628     return person.match({
629       some: res =>
630         this.isoData.site_res.admins.map(a => a.person.id).includes(res.id)
631           ? i18n.t("admin")
632           : i18n.t("mod"),
633       none: i18n.t("mod"),
634     });
635   }
636
637   get documentTitle(): string {
638     return this.state.siteRes.site_view.match({
639       some: siteView => `Modlog - ${siteView.site.name}`,
640       none: "",
641     });
642   }
643
644   render() {
645     return (
646       <div className="container">
647         <HtmlTags
648           title={this.documentTitle}
649           path={this.context.router.route.match.url}
650           description={None}
651           image={None}
652         />
653         {this.state.loading ? (
654           <h5>
655             <Spinner large />
656           </h5>
657         ) : (
658           <div>
659             <h5>
660               {this.state.communityName.match({
661                 some: name => (
662                   <Link className="text-body" to={`/c/${name}`}>
663                     /c/{name}{" "}
664                   </Link>
665                 ),
666                 none: <></>,
667               })}
668               <span>{i18n.t("modlog")}</span>
669             </h5>
670             <div className="form-row">
671               <div className="form-group col-sm-6">
672                 <select
673                   value={this.state.filter_action}
674                   onChange={linkEvent(this, this.handleFilterActionChange)}
675                   className="custom-select mb-2"
676                   aria-label="action"
677                 >
678                   <option disabled aria-hidden="true">
679                     {i18n.t("filter_by_action")}
680                   </option>
681                   <option value={ModlogActionType.All}>{i18n.t("all")}</option>
682                   <option value={ModlogActionType.ModRemovePost}>
683                     Removing Posts
684                   </option>
685                   <option value={ModlogActionType.ModLockPost}>
686                     Locking Posts
687                   </option>
688                   <option value={ModlogActionType.ModStickyPost}>
689                     Stickying Posts
690                   </option>
691                   <option value={ModlogActionType.ModRemoveComment}>
692                     Removing Comments
693                   </option>
694                   <option value={ModlogActionType.ModRemoveCommunity}>
695                     Removing Communities
696                   </option>
697                   <option value={ModlogActionType.ModBanFromCommunity}>
698                     Banning From Communities
699                   </option>
700                   <option value={ModlogActionType.ModAddCommunity}>
701                     Adding Mod to Community
702                   </option>
703                   <option value={ModlogActionType.ModTransferCommunity}>
704                     Transfering Communities
705                   </option>
706                   <option value={ModlogActionType.ModAdd}>
707                     Adding Mod to Site
708                   </option>
709                   <option value={ModlogActionType.ModBan}>
710                     Banning From Site
711                   </option>
712                 </select>
713               </div>
714               {this.state.siteRes.site_view.match({
715                 some: site_view =>
716                   !site_view.site.hide_modlog_mod_names.unwrapOr(false) && (
717                     <div className="form-group col-sm-6">
718                       <select
719                         id="filter-mod"
720                         className="form-control"
721                         value={toUndefined(this.state.filter_mod)}
722                       >
723                         <option>{i18n.t("filter_by_mod")}</option>
724                       </select>
725                     </div>
726                   ),
727                 none: <></>,
728               })}
729               <div className="form-group col-sm-6">
730                 <select
731                   id="filter-user"
732                   className="form-control"
733                   value={toUndefined(this.state.filter_user)}
734                 >
735                   <option>{i18n.t("filter_by_user")}</option>
736                 </select>
737               </div>
738             </div>
739             <div className="table-responsive">
740               <table id="modlog_table" className="table table-sm table-hover">
741                 <thead className="pointer">
742                   <tr>
743                     <th> {i18n.t("time")}</th>
744                     <th>{i18n.t("mod")}</th>
745                     <th>{i18n.t("action")}</th>
746                   </tr>
747                 </thead>
748                 {this.combined()}
749               </table>
750               <Paginator
751                 page={this.state.page}
752                 onChange={this.handlePageChange}
753               />
754             </div>
755           </div>
756         )}
757       </div>
758     );
759   }
760
761   handleFilterActionChange(i: Modlog, event: any) {
762     i.setState({ filter_action: event.target.value });
763     i.refetch();
764   }
765
766   handlePageChange(val: number) {
767     this.setState({ page: val });
768     this.refetch();
769   }
770
771   refetch() {
772     let modlogForm = new GetModlog({
773       community_id: this.state.communityId,
774       page: Some(this.state.page),
775       limit: Some(fetchLimit),
776       auth: auth(false).ok(),
777       type_: this.state.filter_action,
778       other_person_id: this.state.filter_user,
779       mod_person_id: this.state.filter_mod,
780     });
781     WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
782
783     this.state.communityId.match({
784       some: id => {
785         let communityForm = new GetCommunity({
786           id: Some(id),
787           name: None,
788           auth: auth(false).ok(),
789         });
790         WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
791       },
792       none: void 0,
793     });
794   }
795
796   setupUserFilter() {
797     if (isBrowser()) {
798       let selectId: any = document.getElementById("filter-user");
799       if (selectId) {
800         this.userChoices = new Choices(selectId, choicesConfig);
801         this.userChoices.passedElement.element.addEventListener(
802           "choice",
803           (e: any) => {
804             this.setState({ filter_user: Some(Number(e.detail.choice.value)) });
805             this.refetch();
806           },
807           false
808         );
809         this.userChoices.passedElement.element.addEventListener(
810           "search",
811           debounce(async (e: any) => {
812             try {
813               let users = (await fetchUsers(e.detail.value)).users;
814               this.userChoices.setChoices(
815                 users.map(u => {
816                   return {
817                     value: u.person.id.toString(),
818                     label: u.person.name,
819                   };
820                 }),
821                 "value",
822                 "label",
823                 true
824               );
825             } catch (err) {
826               console.log(err);
827             }
828           }),
829           false
830         );
831       }
832     }
833   }
834
835   setupModFilter() {
836     if (isBrowser()) {
837       let selectId: any = document.getElementById("filter-mod");
838       if (selectId) {
839         this.modChoices = new Choices(selectId, choicesConfig);
840         this.modChoices.passedElement.element.addEventListener(
841           "choice",
842           (e: any) => {
843             this.setState({ filter_mod: Some(Number(e.detail.choice.value)) });
844             this.refetch();
845           },
846           false
847         );
848         this.modChoices.passedElement.element.addEventListener(
849           "search",
850           debounce(async (e: any) => {
851             try {
852               let mods = (await fetchUsers(e.detail.value)).users;
853               this.modChoices.setChoices(
854                 mods.map(u => {
855                   return {
856                     value: u.person.id.toString(),
857                     label: u.person.name,
858                   };
859                 }),
860                 "value",
861                 "label",
862                 true
863               );
864             } catch (err) {
865               console.log(err);
866             }
867           }),
868           false
869         );
870       }
871     }
872   }
873
874   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
875     let pathSplit = req.path.split("/");
876     let communityId = Some(pathSplit[3]).map(Number);
877     let promises: Promise<any>[] = [];
878
879     let modlogForm = new GetModlog({
880       page: Some(1),
881       limit: Some(fetchLimit),
882       community_id: communityId,
883       mod_person_id: None,
884       auth: req.auth,
885       type_: ModlogActionType.All,
886       other_person_id: None,
887     });
888
889     promises.push(req.client.getModlog(modlogForm));
890
891     if (communityId.isSome()) {
892       let communityForm = new GetCommunity({
893         id: communityId,
894         name: None,
895         auth: req.auth,
896       });
897       promises.push(req.client.getCommunity(communityForm));
898     } else {
899       promises.push(Promise.resolve());
900     }
901     return promises;
902   }
903
904   parseMessage(msg: any) {
905     let op = wsUserOp(msg);
906     console.log(msg);
907     if (msg.error) {
908       toast(i18n.t(msg.error), "danger");
909       return;
910     } else if (op == UserOperation.GetModlog) {
911       let data = wsJsonToRes<GetModlogResponse>(msg, GetModlogResponse);
912       window.scrollTo(0, 0);
913       this.setState({ res: Some(data), loading: false });
914       this.setupUserFilter();
915       this.setupModFilter();
916     } else if (op == UserOperation.GetCommunity) {
917       let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
918       this.setState({
919         communityMods: Some(data.moderators),
920         communityName: Some(data.community_view.community.name),
921       });
922     }
923   }
924 }