]> Untitled Git - lemmy-ui.git/commitdiff
Updating translations.
authorDessalines <tyhou13@gmx.com>
Wed, 17 Aug 2022 23:28:40 +0000 (19:28 -0400)
committerDessalines <tyhou13@gmx.com>
Wed, 17 Aug 2022 23:28:40 +0000 (19:28 -0400)
1  2 
src/shared/components/home/site-form.tsx
src/shared/components/modlog.tsx
src/shared/utils.ts

index 09a7ca352e26f46109cc0b2fec355d08f814d5b4,e2266feec996f59ca318384e26629d8963db7f68..e9a5b14006cc863d15dd4daafc519199a6c9c264
@@@ -54,6 -54,7 +54,7 @@@ export class SiteForm extends Component
        description: None,
        community_creation_admin_only: None,
        auth: undefined,
+       hide_modlog_mod_names: Some(true),
      }),
      loading: false,
      themeList: None,
@@@ -98,6 -99,7 +99,7 @@@
            default_theme: Some(site.default_theme),
            default_post_listing_type: Some(site.default_post_listing_type),
            legal_information: site.legal_information,
+           hide_modlog_mod_names: site.hide_modlog_mod_names,
            auth: undefined,
          });
        },
                </div>
              </div>
            </div>
 -                  checked={toUndefined(this.state.siteForm.hide_modlog_mod_names)}
+           <div class="form-group row">
+             <div class="col-12">
+               <div class="form-check">
+                 <input
+                   class="form-check-input"
+                   id="create-site-hide-modlog-mod-names"
+                   type="checkbox"
++                  checked={toUndefined(
++                    this.state.siteForm.hide_modlog_mod_names
++                  )}
+                   onChange={linkEvent(this, this.handleSiteHideModlogModNames)}
+                 />
+                 <label
+                   class="form-check-label"
+                   htmlFor="create-site-hide-modlog-mod-names"
+                 >
+                   {i18n.t("hide_modlog_mod_names")}
+                 </label>
+               </div>
+             </div>
+           </div>
            <div class="form-group row">
              <div class="col-12">
                <button
          default_theme: sForm.default_theme,
          default_post_listing_type: sForm.default_post_listing_type,
          auth: auth().unwrap(),
 -        hide_modlog_mod_names: sForm.hide_modlog_mod_names
++        hide_modlog_mod_names: sForm.hide_modlog_mod_names,
        });
        WebSocketService.Instance.send(wsClient.createSite(form));
      }
      i.setState(i.state);
    }
  
+   handleSiteHideModlogModNames(i: SiteForm, event: any) {
+     i.state.siteForm.hide_modlog_mod_names = Some(event.target.checked);
+     i.setState(i.state);
+   }
    handleSiteDefaultTheme(i: SiteForm, event: any) {
      i.state.siteForm.default_theme = Some(event.target.value);
      i.setState(i.state);
index c90dd647874bc74afbb9ae8bbcfdec0d92489cd7,a22c20b8f61415c533337b6c80bc53a747efff03..e8192d27caa21963f3203d428313e7839d726ab5
@@@ -1,5 -1,5 +1,5 @@@
  import { None, Option, Some } from "@sniptt/monads";
- import { Component } from "inferno";
+ import { Component, linkEvent } from "inferno";
  import { Link } from "inferno-router";
  import {
    AdminPurgeCommentView,
    ModBanFromCommunityView,
    ModBanView,
    ModLockPostView,
+   ModlogActionType,
    ModRemoveCommentView,
    ModRemoveCommunityView,
    ModRemovePostView,
    ModStickyPostView,
    ModTransferCommunityView,
    PersonSafe,
+   toUndefined,
    UserOperation,
    wsJsonToRes,
    wsUserOp,
@@@ -36,7 -38,11 +38,10 @@@ import 
    amAdmin,
    amMod,
    auth,
 -  choicesConfig,
+   choicesModLogConfig,
+   debounce,
    fetchLimit,
+   fetchUsers,
    isBrowser,
    setIsoData,
    toast,
@@@ -49,53 -55,43 +54,43 @@@ import { MomentTime } from "./common/mo
  import { Paginator } from "./common/paginator";
  import { CommunityLink } from "./community/community-link";
  import { PersonListing } from "./person/person-listing";
- enum ModlogEnum {
-   ModRemovePost,
-   ModLockPost,
-   ModStickyPost,
-   ModRemoveComment,
-   ModRemoveCommunity,
-   ModBanFromCommunity,
-   ModAddCommunity,
-   ModTransferCommunity,
-   ModAdd,
-   ModBan,
-   AdminPurgePerson,
-   AdminPurgeCommunity,
-   AdminPurgePost,
-   AdminPurgeComment,
- }
  type ModlogType = {
    id: number;
-   type_: ModlogEnum;
-   moderator: PersonSafe;
+   type_: ModlogActionType;
+   moderator: Option<PersonSafe>;
    view:
 -  | ModRemovePostView
 -  | ModLockPostView
 -  | ModStickyPostView
 -  | ModRemoveCommentView
 -  | ModRemoveCommunityView
 -  | ModBanFromCommunityView
 -  | ModBanView
 -  | ModAddCommunityView
 -  | ModTransferCommunityView
 -  | ModAddView
 -  | AdminPurgePersonView
 -  | AdminPurgeCommunityView
 -  | AdminPurgePostView
 -  | AdminPurgeCommentView;
 +    | ModRemovePostView
 +    | ModLockPostView
 +    | ModStickyPostView
 +    | ModRemoveCommentView
 +    | ModRemoveCommunityView
 +    | ModBanFromCommunityView
 +    | ModBanView
 +    | ModAddCommunityView
 +    | ModTransferCommunityView
 +    | ModAddView
 +    | AdminPurgePersonView
 +    | AdminPurgeCommunityView
 +    | AdminPurgePostView
 +    | AdminPurgeCommentView;
    when_: string;
  };
+ var Choices: any;
+ if (isBrowser()) {
+   Choices = require("choices.js");
+ }
  
  interface ModlogState {
    res: Option<GetModlogResponse>;
    communityId: Option<number>;
    communityMods: Option<CommunityModeratorView[]>;
 -  communityName: Option<string>,
++  communityName: Option<string>;
    page: number;
    siteRes: GetSiteResponse;
    loading: boolean;
 -  filter_action: ModlogActionType,
 -  filter_user: Option<number>,
 -  filter_mod: Option<number>,
++  filter_action: ModlogActionType;
++  filter_user: Option<number>;
++  filter_mod: Option<number>;
  }
  
  export class Modlog extends Component<any, ModlogState> {
      GetCommunityResponse
    );
    private subscription: Subscription;
+   private userChoices: any;
+   private modChoices: any;
    private emptyState: ModlogState = {
      res: None,
      communityId: None,
      communityMods: None,
+     communityName: None,
      page: 1,
      loading: true,
      siteRes: this.isoData.site_res,
+     filter_action: ModlogActionType.All,
+     filter_user: None,
+     filter_mod: None,
    };
    constructor(props: any, context: any) {
      super(props, context);
      this.state = this.emptyState;
      this.handlePageChange = this.handlePageChange.bind(this);
  
      }
    }
  
+   componentDidMount() {
+     this.setupUserFilter();
+     this.setupModFilter();
+   }
    componentWillUnmount() {
      if (isBrowser()) {
        this.subscription.unsubscribe();
    buildCombined(res: GetModlogResponse): ModlogType[] {
      let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
        id: r.mod_remove_post.id,
-       type_: ModlogEnum.ModRemovePost,
+       type_: ModlogActionType.ModRemovePost,
        view: r,
        moderator: r.moderator,
        when_: r.mod_remove_post.when_,
  
      let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
        id: r.mod_lock_post.id,
-       type_: ModlogEnum.ModLockPost,
+       type_: ModlogActionType.ModLockPost,
        view: r,
        moderator: r.moderator,
        when_: r.mod_lock_post.when_,
  
      let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
        id: r.mod_sticky_post.id,
-       type_: ModlogEnum.ModStickyPost,
+       type_: ModlogActionType.ModStickyPost,
        view: r,
        moderator: r.moderator,
        when_: r.mod_sticky_post.when_,
  
      let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
        id: r.mod_remove_comment.id,
-       type_: ModlogEnum.ModRemoveComment,
+       type_: ModlogActionType.ModRemoveComment,
        view: r,
        moderator: r.moderator,
        when_: r.mod_remove_comment.when_,
  
      let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
        id: r.mod_remove_community.id,
-       type_: ModlogEnum.ModRemoveCommunity,
+       type_: ModlogActionType.ModRemoveCommunity,
        view: r,
        moderator: r.moderator,
        when_: r.mod_remove_community.when_,
      let banned_from_community: ModlogType[] = res.banned_from_community.map(
        r => ({
          id: r.mod_ban_from_community.id,
-         type_: ModlogEnum.ModBanFromCommunity,
+         type_: ModlogActionType.ModBanFromCommunity,
          view: r,
          moderator: r.moderator,
          when_: r.mod_ban_from_community.when_,
  
      let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
        id: r.mod_add_community.id,
-       type_: ModlogEnum.ModAddCommunity,
+       type_: ModlogActionType.ModAddCommunity,
        view: r,
        moderator: r.moderator,
        when_: r.mod_add_community.when_,
      let transferred_to_community: ModlogType[] =
        res.transferred_to_community.map(r => ({
          id: r.mod_transfer_community.id,
-         type_: ModlogEnum.ModTransferCommunity,
+         type_: ModlogActionType.ModTransferCommunity,
          view: r,
          moderator: r.moderator,
          when_: r.mod_transfer_community.when_,
  
      let added: ModlogType[] = res.added.map(r => ({
        id: r.mod_add.id,
-       type_: ModlogEnum.ModAdd,
+       type_: ModlogActionType.ModAdd,
        view: r,
        moderator: r.moderator,
        when_: r.mod_add.when_,
  
      let banned: ModlogType[] = res.banned.map(r => ({
        id: r.mod_ban.id,
-       type_: ModlogEnum.ModBan,
+       type_: ModlogActionType.ModBan,
        view: r,
        moderator: r.moderator,
        when_: r.mod_ban.when_,
  
      let purged_persons: ModlogType[] = res.admin_purged_persons.map(r => ({
        id: r.admin_purge_person.id,
-       type_: ModlogEnum.AdminPurgePerson,
+       type_: ModlogActionType.AdminPurgePerson,
        view: r,
        moderator: r.admin,
        when_: r.admin_purge_person.when_,
      let purged_communities: ModlogType[] = res.admin_purged_communities.map(
        r => ({
          id: r.admin_purge_community.id,
-         type_: ModlogEnum.AdminPurgeCommunity,
+         type_: ModlogActionType.AdminPurgeCommunity,
          view: r,
          moderator: r.admin,
          when_: r.admin_purge_community.when_,
  
      let purged_posts: ModlogType[] = res.admin_purged_posts.map(r => ({
        id: r.admin_purge_post.id,
-       type_: ModlogEnum.AdminPurgePost,
+       type_: ModlogActionType.AdminPurgePost,
        view: r,
        moderator: r.admin,
        when_: r.admin_purge_post.when_,
  
      let purged_comments: ModlogType[] = res.admin_purged_comments.map(r => ({
        id: r.admin_purge_comment.id,
-       type_: ModlogEnum.AdminPurgeComment,
+       type_: ModlogActionType.AdminPurgeComment,
        view: r,
        moderator: r.admin,
        when_: r.admin_purge_comment.when_,
  
    renderModlogType(i: ModlogType) {
      switch (i.type_) {
-       case ModlogEnum.ModRemovePost: {
+       case ModlogActionType.ModRemovePost: {
          let mrpv = i.view as ModRemovePostView;
          return [
            mrpv.mod_remove_post.removed.unwrapOr(false)
            }),
          ];
        }
-       case ModlogEnum.ModLockPost: {
+       case ModlogActionType.ModLockPost: {
          let mlpv = i.view as ModLockPostView;
          return [
            mlpv.mod_lock_post.locked.unwrapOr(false) ? "Locked " : "Unlocked ",
            </span>,
          ];
        }
-       case ModlogEnum.ModStickyPost: {
+       case ModlogActionType.ModStickyPost: {
          let mspv = i.view as ModStickyPostView;
          return [
            mspv.mod_sticky_post.stickied.unwrapOr(false)
            </span>,
          ];
        }
-       case ModlogEnum.ModRemoveComment: {
+       case ModlogActionType.ModRemoveComment: {
          let mrc = i.view as ModRemoveCommentView;
          return [
            mrc.mod_remove_comment.removed.unwrapOr(false)
            }),
          ];
        }
-       case ModlogEnum.ModRemoveCommunity: {
+       case ModlogActionType.ModRemoveCommunity: {
          let mrco = i.view as ModRemoveCommunityView;
          return [
            mrco.mod_remove_community.removed.unwrapOr(false)
            }),
          ];
        }
-       case ModlogEnum.ModBanFromCommunity: {
+       case ModlogActionType.ModBanFromCommunity: {
          let mbfc = i.view as ModBanFromCommunityView;
          return [
            <span>
            }),
          ];
        }
-       case ModlogEnum.ModAddCommunity: {
+       case ModlogActionType.ModAddCommunity: {
          let mac = i.view as ModAddCommunityView;
          return [
            <span>
            </span>,
          ];
        }
-       case ModlogEnum.ModTransferCommunity: {
+       case ModlogActionType.ModTransferCommunity: {
          let mtc = i.view as ModTransferCommunityView;
          return [
            <span>
            </span>,
          ];
        }
-       case ModlogEnum.ModBan: {
+       case ModlogActionType.ModBan: {
          let mb = i.view as ModBanView;
          return [
            <span>
            }),
          ];
        }
-       case ModlogEnum.ModAdd: {
+       case ModlogActionType.ModAdd: {
          let ma = i.view as ModAddView;
          return [
            <span>
            <span> as an admin </span>,
          ];
        }
-       case ModlogEnum.AdminPurgePerson: {
+       case ModlogActionType.AdminPurgePerson: {
          let ap = i.view as AdminPurgePersonView;
          return [
            <span>Purged a Person</span>,
            }),
          ];
        }
-       case ModlogEnum.AdminPurgeCommunity: {
+       case ModlogActionType.AdminPurgeCommunity: {
          let ap = i.view as AdminPurgeCommunityView;
          return [
            <span>Purged a Community</span>,
            }),
          ];
        }
-       case ModlogEnum.AdminPurgePost: {
+       case ModlogActionType.AdminPurgePost: {
          let ap = i.view as AdminPurgePostView;
          return [
            <span>Purged a Post from from </span>,
            }),
          ];
        }
-       case ModlogEnum.AdminPurgeComment: {
+       case ModlogActionType.AdminPurgeComment: {
          let ap = i.view as AdminPurgeCommentView;
          return [
            <span>
              </td>
              <td>
                {this.amAdminOrMod ? (
-                 <PersonListing person={i.moderator} />
+                 <PersonListing person={i.moderator.unwrap()} />
                ) : (
                  <div>{this.modOrAdminText(i.moderator)}</div>
                )}
      );
    }
  
-   modOrAdminText(person: PersonSafe): string {
-     if (
-       this.isoData.site_res.admins.map(a => a.person.id).includes(person.id)
-     ) {
-       return i18n.t("admin");
-     } else {
-       return i18n.t("mod");
-     }
+   modOrAdminText(person: Option<PersonSafe>): string {
+     return person.match({
 -      some: res => this.isoData.site_res.admins.map(a => a.person.id).includes(res.id) ? i18n.t("admin") : i18n.t("mod"),
++      some: res =>
++        this.isoData.site_res.admins.map(a => a.person.id).includes(res.id)
++          ? i18n.t("admin")
++          : i18n.t("mod"),
+       none: i18n.t("mod"),
+     });
    }
  
    get documentTitle(): string {
  
    render() {
      return (
-       <div class="container">
+       <div className="container">
          <HtmlTags
            title={this.documentTitle}
            path={this.context.router.route.match.url}
            </h5>
          ) : (
            <div>
-             <div class="table-responsive">
-               <table id="modlog_table" class="table table-sm table-hover">
-                 <thead class="pointer">
+             <h5>
 -            {
 -              this.state.communityName.match({
++              {this.state.communityName.match({
+                 some: name => (
 -                  <Link
 -                    className="text-body"
 -                    to={`/c/${name}`}
 -                  >
++                  <Link className="text-body" to={`/c/${name}`}>
+                     /c/{name}{" "}
+                   </Link>
+                 ),
+                 none: <></>,
 -              })
 -            }
++              })}
+               <span>{i18n.t("modlog")}</span>
+             </h5>
+             <form className="form-inline mr-2">
+               <select
+                 value={this.state.filter_action}
+                 onChange={linkEvent(this, this.handleFilterActionChange)}
+                 className="custom-select col-4 mb-2"
 -                aria-label="action">
 -                <option disabled aria-hidden="true">{i18n.t("filter_by_action")}</option>
++                aria-label="action"
++              >
++                <option disabled aria-hidden="true">
++                  {i18n.t("filter_by_action")}
++                </option>
+                 <option value={ModlogActionType.All}>{i18n.t("all")}</option>
 -                <option value={ModlogActionType.ModRemovePost}>Removing Posts</option>
 -                <option value={ModlogActionType.ModLockPost}>Locking Posts</option>
 -                <option value={ModlogActionType.ModStickyPost}>Stickying Posts</option>
 -                <option value={ModlogActionType.ModRemoveComment}>Removing Comments</option>
 -                <option value={ModlogActionType.ModRemoveCommunity}>Removing Communities</option>
 -                <option value={ModlogActionType.ModBanFromCommunity}>Banning From Communities</option>
 -                <option value={ModlogActionType.ModAddCommunity}>Adding Mod to Community</option>
 -                <option value={ModlogActionType.ModTransferCommunity}>Transfering Communities</option>
 -                <option value={ModlogActionType.ModAdd}>Adding Mod to Site</option>
 -                <option value={ModlogActionType.ModBan}>Banning From Site</option>
++                <option value={ModlogActionType.ModRemovePost}>
++                  Removing Posts
++                </option>
++                <option value={ModlogActionType.ModLockPost}>
++                  Locking Posts
++                </option>
++                <option value={ModlogActionType.ModStickyPost}>
++                  Stickying Posts
++                </option>
++                <option value={ModlogActionType.ModRemoveComment}>
++                  Removing Comments
++                </option>
++                <option value={ModlogActionType.ModRemoveCommunity}>
++                  Removing Communities
++                </option>
++                <option value={ModlogActionType.ModBanFromCommunity}>
++                  Banning From Communities
++                </option>
++                <option value={ModlogActionType.ModAddCommunity}>
++                  Adding Mod to Community
++                </option>
++                <option value={ModlogActionType.ModTransferCommunity}>
++                  Transfering Communities
++                </option>
++                <option value={ModlogActionType.ModAdd}>
++                  Adding Mod to Site
++                </option>
++                <option value={ModlogActionType.ModBan}>
++                  Banning From Site
++                </option>
+               </select>
 -              {
 -                this.state.siteRes.site_view.match({
 -                  some: site_view => !site_view.site.hide_modlog_mod_names.unwrapOr(false) &&  (
++              {this.state.siteRes.site_view.match({
++                some: site_view =>
++                  !site_view.site.hide_modlog_mod_names.unwrapOr(false) && (
+                     <select
+                       id="filter-mod"
 -                      value={toUndefined(this.state.filter_mod)}>
++                      value={toUndefined(this.state.filter_mod)}
++                    >
+                       <option>{i18n.t("filter_by_mod")}</option>
+                     </select>
+                   ),
 -                  none: <></>,
 -                })
 -              }
++                none: <></>,
++              })}
+               <select
+                 id="filter-user"
 -                value={toUndefined(this.state.filter_user)}>
++                value={toUndefined(this.state.filter_user)}
++              >
+                 <option>{i18n.t("filter_by_user")}</option>
 -              </select> 
++              </select>
+             </form>
+             <div className="table-responsive">
+               <table id="modlog_table" className="table table-sm table-hover">
+                 <thead className="pointer">
                    <tr>
                      <th> {i18n.t("time")}</th>
                      <th>{i18n.t("mod")}</th>
      );
    }
  
+   handleFilterActionChange(i: Modlog, event: any) {
+     i.setState({ filter_action: event.target.value });
+     i.refetch();
+   }
    handlePageChange(val: number) {
      this.setState({ page: val });
      this.refetch();
    refetch() {
      let modlogForm = new GetModlog({
        community_id: this.state.communityId,
-       mod_person_id: None,
        page: Some(this.state.page),
        limit: Some(fetchLimit),
        auth: auth(false).ok(),
+       type_: this.state.filter_action,
+       other_person_id: this.state.filter_user,
+       mod_person_id: this.state.filter_mod,
      });
      WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
  
      });
    }
  
 -                users.map(u => {return {
 -                  value: u.person.id.toString(),
 -                  label: u.person.name,
 -                }}),
+   setupUserFilter() {
+     if (isBrowser()) {
+       let selectId: any = document.getElementById("filter-user");
+       if (selectId) {
+         this.userChoices = new Choices(selectId, choicesModLogConfig);
+         this.userChoices.passedElement.element.addEventListener(
+           "choice",
+           (e: any) => {
+             this.state.filter_user = Some(Number(e.detail.choice.value));
+             this.setState(this.state);
+             this.refetch();
+           },
+           false
+         );
+         this.userChoices.passedElement.element.addEventListener(
+           "search",
+           debounce(async (e: any) => {
+             try {
+               let users = (await fetchUsers(e.detail.value)).users;
+               this.userChoices.setChoices(
 -                mods.map(u => {return {
 -                  value: u.person.id.toString(),
 -                  label: u.person.name,
 -                }}),
++                users.map(u => {
++                  return {
++                    value: u.person.id.toString(),
++                    label: u.person.name,
++                  };
++                }),
+                 "value",
+                 "label",
+                 true
+               );
+             } catch (err) {
+               console.log(err);
+             }
+           }),
+           false
+         );
+       }
+     }
+   }
+   setupModFilter() {
+     if (isBrowser()) {
+       let selectId: any = document.getElementById("filter-mod");
+       if (selectId) {
+         this.modChoices = new Choices(selectId, choicesModLogConfig);
+         this.modChoices.passedElement.element.addEventListener(
+           "choice",
+           (e: any) => {
+             this.state.filter_mod = Some(Number(e.detail.choice.value));
+             this.setState(this.state);
+             this.refetch();
+           },
+           false
+         );
+         this.modChoices.passedElement.element.addEventListener(
+           "search",
+           debounce(async (e: any) => {
+             try {
+               let mods = (await fetchUsers(e.detail.value)).users;
+               this.modChoices.setChoices(
++                mods.map(u => {
++                  return {
++                    value: u.person.id.toString(),
++                    label: u.person.name,
++                  };
++                }),
+                 "value",
+                 "label",
+                 true
+               );
+             } catch (err) {
+               console.log(err);
+             }
+           }),
+           false
+         );
+       }
+     }
+   }
    static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
      let pathSplit = req.path.split("/");
      let communityId = Some(pathSplit[3]).map(Number);
        community_id: communityId,
        mod_person_id: None,
        auth: req.auth,
 -      other_person_id: None
+       type_: ModlogActionType.All,
++      other_person_id: None,
      });
  
      promises.push(req.client.getModlog(modlogForm));
      } else if (op == UserOperation.GetCommunity) {
        let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
        this.state.communityMods = Some(data.moderators);
+       this.state.communityName = Some(data.community_view.community.name);
      }
    }
  }
diff --combined src/shared/utils.ts
index 3354fcc5d1bf5698626c9d2e2c10bf813d6aa2ce,ab3f87929c45ba4092134b3e06fa00eaf5fc8cf6..19b48c1945700410520f2e15e1fc9e21eb2833df
@@@ -4,10 -4,7 +4,10 @@@ import emojiShortName from "emoji-short
  import {
    BlockCommunityResponse,
    BlockPersonResponse,
 +  Comment as CommentI,
 +  CommentNode as CommentNodeI,
    CommentReportView,
 +  CommentSortType,
    CommentView,
    CommunityBlockView,
    CommunityModeratorView,
@@@ -42,7 -39,12 +42,7 @@@ import tippy from "tippy.js"
  import Toastify from "toastify-js";
  import { httpBase } from "./env";
  import { i18n, languages } from "./i18next";
 -import {
 -  CommentNode as CommentNodeI,
 -  CommentSortType,
 -  DataType,
 -  IsoData,
 -} from "./interfaces";
 +import { DataType, IsoData } from "./interfaces";
  import { UserService, WebSocketService } from "./services";
  
  var Tribute: any;
@@@ -72,7 -74,6 +72,7 @@@ export const postRefetchSeconds: numbe
  export const fetchLimit = 20;
  export const trendingFetchLimit = 6;
  export const mentionDropdownFetchLimit = 10;
 +export const commentTreeMaxDepth = 8;
  
  export const relTags = "noopener nofollow";
  
@@@ -210,10 -211,9 +210,10 @@@ export function canMod
  export function canAdmin(
    admins: Option<PersonViewSafe[]>,
    creator_id: number,
 -  myUserInfo = UserService.Instance.myUserInfo
 +  myUserInfo = UserService.Instance.myUserInfo,
 +  onSelf = false
  ): boolean {
 -  return canMod(None, admins, creator_id, myUserInfo);
 +  return canMod(None, admins, creator_id, myUserInfo, onSelf);
  }
  
  export function isMod(
@@@ -611,7 -611,7 +611,7 @@@ export function notifyComment(comment_v
    let info: NotifyInfo = {
      name: comment_view.creator.name,
      icon: comment_view.creator.avatar,
 -    link: `/post/${comment_view.post.id}/comment/${comment_view.comment.id}`,
 +    link: `/comment/${comment_view.comment.id}`,
      body: comment_view.comment.content,
    };
    notify(info, router);
@@@ -813,14 -813,12 +813,14 @@@ export function getRecipientIdFromProps
      : 1;
  }
  
 -export function getIdFromProps(props: any): number {
 -  return Number(props.match.params.id);
 +export function getIdFromProps(props: any): Option<number> {
 +  let id: string = props.match.params.post_id;
 +  return id ? Some(Number(id)) : None;
  }
  
 -export function getCommentIdFromProps(props: any): number {
 -  return Number(props.match.params.comment_id);
 +export function getCommentIdFromProps(props: any): Option<number> {
 +  let id: string = props.match.params.comment_id;
 +  return id ? Some(Number(id)) : None;
  }
  
  export function getUsernameFromProps(props: any): string {
@@@ -831,7 -829,6 +831,7 @@@ export function editCommentRes(data: Co
    let found = comments.find(c => c.comment.id == data.comment.id);
    if (found) {
      found.comment.content = data.comment.content;
 +    found.comment.distinguished = data.comment.distinguished;
      found.comment.updated = data.comment.updated;
      found.comment.removed = data.comment.removed;
      found.comment.deleted = data.comment.deleted;
@@@ -988,12 -985,61 +988,12 @@@ export function updateRegistrationAppli
  export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
    let nodes: CommentNodeI[] = [];
    for (let comment of comments) {
 -    nodes.push({ comment_view: comment });
 +    nodes.push({ comment_view: comment, children: [], depth: 0 });
    }
    return nodes;
  }
  
 -function commentSort(tree: CommentNodeI[], sort: CommentSortType) {
 -  // First, put removed and deleted comments at the bottom, then do your other sorts
 -  if (sort == CommentSortType.Top) {
 -    tree.sort(
 -      (a, b) =>
 -        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
 -        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
 -        b.comment_view.counts.score - a.comment_view.counts.score
 -    );
 -  } else if (sort == CommentSortType.New) {
 -    tree.sort(
 -      (a, b) =>
 -        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
 -        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
 -        b.comment_view.comment.published.localeCompare(
 -          a.comment_view.comment.published
 -        )
 -    );
 -  } else if (sort == CommentSortType.Old) {
 -    tree.sort(
 -      (a, b) =>
 -        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
 -        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
 -        a.comment_view.comment.published.localeCompare(
 -          b.comment_view.comment.published
 -        )
 -    );
 -  } else if (sort == CommentSortType.Hot) {
 -    tree.sort(
 -      (a, b) =>
 -        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
 -        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
 -        hotRankComment(b.comment_view as CommentView) -
 -          hotRankComment(a.comment_view as CommentView)
 -    );
 -  }
 -
 -  // Go through the children recursively
 -  for (let node of tree) {
 -    if (node.children) {
 -      commentSort(node.children, sort);
 -    }
 -  }
 -}
 -
 -export function commentSortSortType(tree: CommentNodeI[], sort: SortType) {
 -  commentSort(tree, convertCommentSortType(sort));
 -}
 -
 -function convertCommentSortType(sort: SortType): CommentSortType {
 +export function convertCommentSortType(sort: SortType): CommentSortType {
    if (
      sort == SortType.TopAll ||
      sort == SortType.TopDay ||
  
  export function buildCommentsTree(
    comments: CommentView[],
 -  commentSortType: CommentSortType
 +  parentComment: boolean
  ): CommentNodeI[] {
    let map = new Map<number, CommentNodeI>();
 +  let depthOffset = !parentComment
 +    ? 0
 +    : getDepthFromComment(comments[0].comment);
 +
    for (let comment_view of comments) {
      let node: CommentNodeI = {
        comment_view: comment_view,
        children: [],
 -      depth: 0,
 +      depth: getDepthFromComment(comment_view.comment) - depthOffset,
      };
      map.set(comment_view.comment.id, { ...node });
    }
 +
    let tree: CommentNodeI[] = [];
 +
 +  // if its a parent comment fetch, then push the first comment to the top node.
 +  if (parentComment) {
 +    tree.push(map.get(comments[0].comment.id));
 +  }
 +
    for (let comment_view of comments) {
      let child = map.get(comment_view.comment.id);
 -    let parent_id = comment_view.comment.parent_id;
 +    let parent_id = getCommentParentId(comment_view.comment);
      parent_id.match({
        some: parentId => {
          let parent = map.get(parentId);
          }
        },
        none: () => {
 -        tree.push(child);
 +        if (!parentComment) {
 +          tree.push(child);
 +        }
        },
      });
 -
 -    setDepth(child);
    }
  
 -  commentSort(tree, commentSortType);
 -
    return tree;
  }
  
 -function setDepth(node: CommentNodeI, i = 0) {
 -  for (let child of node.children) {
 -    child.depth = i;
 -    setDepth(child, i + 1);
 +export function getCommentParentId(comment: CommentI): Option<number> {
 +  let split = comment.path.split(".");
 +  // remove the 0
 +  split.shift();
 +
 +  if (split.length > 1) {
 +    return Some(Number(split[split.length - 2]));
 +  } else {
 +    return None;
    }
  }
  
 -export function insertCommentIntoTree(tree: CommentNodeI[], cv: CommentView) {
 +export function getDepthFromComment(comment: CommentI): number {
 +  return comment.path.split(".").length - 2;
 +}
 +
 +export function insertCommentIntoTree(
 +  tree: CommentNodeI[],
 +  cv: CommentView,
 +  parentComment: boolean
 +) {
    // Building a fake node to be used for later
    let node: CommentNodeI = {
      comment_view: cv,
      depth: 0,
    };
  
 -  cv.comment.parent_id.match({
 +  getCommentParentId(cv.comment).match({
      some: parentId => {
        let parentComment = searchCommentTree(tree, parentId);
        parentComment.match({
        });
      },
      none: () => {
 -      tree.unshift(node);
 +      if (!parentComment) {
 +        tree.unshift(node);
 +      }
      },
    });
  }
@@@ -1127,7 -1149,6 +1127,7 @@@ export function searchCommentTree
  
  export const colorList: string[] = [
    hsl(0),
 +  hsl(50),
    hsl(100),
    hsl(150),
    hsl(200),
@@@ -1271,7 -1292,7 +1271,7 @@@ export function showLocal(isoData: IsoD
      .unwrapOr(false);
  }
  
- interface ChoicesValue {
export interface ChoicesValue {
    value: string;
    label: string;
  }
@@@ -1359,6 -1380,39 +1359,40 @@@ export const choicesConfig = 
    },
  };
  
 -    containerInner: "choices__inner bg-secondary border-0 py-0 modlog-choices-font-size",
+ export const choicesModLogConfig = {
+   shouldSort: false,
+   searchResultLimit: fetchLimit,
+   classNames: {
+     containerOuter: "choices mb-2 custom-select col-4 px-0",
++    containerInner:
++      "choices__inner bg-secondary border-0 py-0 modlog-choices-font-size",
+     input: "form-control",
+     inputCloned: "choices__input--cloned w-100",
+     list: "choices__list",
+     listItems: "choices__list--multiple",
+     listSingle: "choices__list--single py-0",
+     listDropdown: "choices__list--dropdown",
+     item: "choices__item bg-secondary",
+     itemSelectable: "choices__item--selectable",
+     itemDisabled: "choices__item--disabled",
+     itemChoice: "choices__item--choice",
+     placeholder: "choices__placeholder",
+     group: "choices__group",
+     groupHeading: "choices__heading",
+     button: "choices__button",
+     activeState: "is-active",
+     focusState: "is-focused",
+     openState: "is-open",
+     disabledState: "is-disabled",
+     highlightedState: "text-info",
+     selectedState: "text-info",
+     flippedState: "is-flipped",
+     loadingState: "is-loading",
+     noResults: "has-no-results",
+     noChoices: "has-no-choices",
+   },
+ };
  export function communitySelectName(cv: CommunityView): string {
    return cv.community.local
      ? cv.community.title
@@@ -1418,15 -1472,3 +1452,15 @@@ export function enableDownvotes(siteRes
  export function enableNsfw(siteRes: GetSiteResponse): boolean {
    return siteRes.site_view.map(s => s.site.enable_nsfw).unwrapOr(false);
  }
 +
 +export function postToCommentSortType(sort: SortType): CommentSortType {
 +  if ([SortType.Active, SortType.Hot].includes(sort)) {
 +    return CommentSortType.Hot;
 +  } else if ([SortType.New, SortType.NewComments].includes(sort)) {
 +    return CommentSortType.New;
 +  } else if (sort == SortType.Old) {
 +    return CommentSortType.Old;
 +  } else {
 +    return CommentSortType.Top;
 +  }
 +}