More moderation history (#2649)

* Updating translations.

* Adding a link to view all a user's moderation history from an item.

- Also making moderation history strings more detailed.

* Fix.

* Adding admin view moderation history to profile page.

* Adding admin view moderation history to profile page.
This commit is contained in:
Dessalines 2024-08-03 14:56:19 -04:00 committed by GitHub
parent bee4395706
commit 999b083545
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 80 additions and 43 deletions

@ -1 +1 @@
Subproject commit 088a27703ffa65e069dfbf341ee9bd44ec4c45c5 Subproject commit 1f4e378f2e18d843aec1e421b99a69a76ce633b7

View file

@ -159,6 +159,26 @@ export default class ContentActionDropdown extends Component<
(amMod(community.id) || (amAdmin() && community.local)) && (amMod(community.id) || (amAdmin() && community.local)) &&
!creator_banned_from_community; !creator_banned_from_community;
const modHistoryUserTranslation = I18NextService.i18n.t(
"user_moderation_history",
{ user: creator.name },
);
// The link and translation string for the item
const { modHistoryItemLink, modHistoryItemTranslation } =
type === "post"
? {
modHistoryItemLink: `/modlog?postId=${id}`,
modHistoryItemTranslation: I18NextService.i18n.t(
"post_moderation_history",
),
}
: {
modHistoryItemLink: `/modlog?commentId=${id}`,
modHistoryItemTranslation: I18NextService.i18n.t(
"comment_moderation_history",
),
};
return ( return (
<> <>
{type === "comment" && ( {type === "comment" && (
@ -349,15 +369,23 @@ export default class ContentActionDropdown extends Component<
<li> <li>
<Link <Link
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item" className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
to={`/modlog?${type === "post" ? "postId" : "commentId"}=${id}`} to={`/modlog?userId=${creator.id}`}
title={I18NextService.i18n.t("moderation_history")} title={modHistoryUserTranslation}
aria-label={I18NextService.i18n.t("moderation_history")} aria-label={modHistoryUserTranslation}
data-tippy-content={I18NextService.i18n.t( data-tippy-content={modHistoryUserTranslation}
"moderation_history",
)}
> >
<Icon icon="history" inline classes="me-2" /> <Icon icon="history" inline classes="me-2" />
{I18NextService.i18n.t("moderation_history")} {modHistoryUserTranslation}
</Link>
<Link
className="btn btn-link btn-sm d-flex align-items-center rounded-0 dropdown-item"
to={modHistoryItemLink}
title={modHistoryItemTranslation}
aria-label={modHistoryItemTranslation}
data-tippy-content={modHistoryItemTranslation}
>
<Icon icon="history" inline classes="me-2" />
{modHistoryItemTranslation}
</Link> </Link>
</li> </li>
{(this.canMod || this.canAdmin) && ( {(this.canMod || this.canAdmin) && (

View file

@ -76,8 +76,6 @@ export class MarkdownTextArea extends Component<
private id = `markdown-textarea-${randomStr()}`; private id = `markdown-textarea-${randomStr()}`;
private formId = `markdown-form-${randomStr()}`; private formId = `markdown-form-${randomStr()}`;
private tribute: any;
state: MarkdownTextAreaState = { state: MarkdownTextAreaState = {
content: this.props.initialContent, content: this.props.initialContent,
languageId: this.props.initialLanguageId, languageId: this.props.initialLanguageId,
@ -91,26 +89,25 @@ export class MarkdownTextArea extends Component<
this.handleLanguageChange = this.handleLanguageChange.bind(this); this.handleLanguageChange = this.handleLanguageChange.bind(this);
this.handleEmoji = this.handleEmoji.bind(this); this.handleEmoji = this.handleEmoji.bind(this);
if (isBrowser()) {
this.tribute = setupTribute();
}
} }
componentDidMount() { async componentDidMount() {
const textarea: any = document.getElementById(this.id); if (isBrowser()) {
if (textarea) { const tribute = await setupTribute();
autosize(textarea); const textarea: any = document.getElementById(this.id);
this.tribute.attach(textarea); if (textarea) {
textarea.addEventListener("tribute-replaced", () => { autosize(textarea);
this.setState({ content: textarea.value }); tribute.attach(textarea);
autosize.update(textarea); textarea.addEventListener("tribute-replaced", () => {
}); this.setState({ content: textarea.value });
autosize.update(textarea);
});
this.quoteInsert(); this.quoteInsert();
if (this.props.focus) { if (this.props.focus) {
textarea.focus(); textarea.focus();
}
} }
} }
} }

View file

@ -20,7 +20,7 @@ import {
resourcesSettled, resourcesSettled,
bareRoutePush, bareRoutePush,
} from "@utils/helpers"; } from "@utils/helpers";
import { canMod } from "@utils/roles"; import { amAdmin, canMod } from "@utils/roles";
import type { QueryParams } from "@utils/types"; import type { QueryParams } from "@utils/types";
import { RouteDataResponse } from "@utils/types"; import { RouteDataResponse } from "@utils/types";
import classNames from "classnames"; import classNames from "classnames";
@ -671,15 +671,27 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
<div className="flex-grow-1 unselectable pointer mx-2"></div> <div className="flex-grow-1 unselectable pointer mx-2"></div>
{!this.amCurrentUser && UserService.Instance.myUserInfo && ( {!this.amCurrentUser && UserService.Instance.myUserInfo && (
<> <>
<a {amAdmin() && (
className={`d-flex align-self-start btn btn-secondary me-2 ${ <Link
!pv.person.matrix_user_id && "invisible" className={
}`} "d-flex align-self-start btn btn-secondary me-2"
rel={relTags} }
href={`https://matrix.to/#/${pv.person.matrix_user_id}`} to={`/modlog?userId=${pv.person.id}`}
> >
{I18NextService.i18n.t("send_secure_message")} {I18NextService.i18n.t("user_moderation_history", {
</a> user: pv.person.name,
})}
</Link>
)}
{pv.person.matrix_user_id && (
<a
className={`d-flex align-self-start btn btn-secondary me-2`}
rel={relTags}
href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
>
{I18NextService.i18n.t("send_secure_message")}
</a>
)}
<Link <Link
className={ className={
"d-flex align-self-start btn btn-secondary me-2" "d-flex align-self-start btn btn-secondary me-2"

View file

@ -17,9 +17,8 @@ import markdown_it_highlightjs from "markdown-it-highlightjs/core";
import { Renderer, Token } from "markdown-it"; import { Renderer, Token } from "markdown-it";
import { instanceLinkRegex, relTags } from "./config"; import { instanceLinkRegex, relTags } from "./config";
import { lazyHighlightjs } from "./lazy-highlightjs"; import { lazyHighlightjs } from "./lazy-highlightjs";
import { isBrowser } from "@utils/browser";
export let Tribute: any; let Tribute: any;
export let md: MarkdownIt = new MarkdownIt(); export let md: MarkdownIt = new MarkdownIt();
@ -40,10 +39,6 @@ export let customEmojisLookup: Map<string, CustomEmojiView> = new Map<
CustomEmojiView CustomEmojiView
>(); >();
if (isBrowser()) {
Tribute = await import("tributejs");
}
export function mdToHtml(text: string, rerender: () => void) { export function mdToHtml(text: string, rerender: () => void) {
return { __html: lazyHighlightjs.render(md, text, rerender) }; return { __html: lazyHighlightjs.render(md, text, rerender) };
} }
@ -340,7 +335,12 @@ export function getEmojiMart(
return new Picker(pickerOptions); return new Picker(pickerOptions);
} }
export function setupTribute() { export async function setupTribute() {
if (Tribute === null) {
console.debug("Tribute is null, importing...");
Tribute = (await import("tributejs")).default;
}
return new Tribute({ return new Tribute({
noMatchTemplate: function () { noMatchTemplate: function () {
return ""; return "";