[frontend] Basic user moderation actions (#1728)

* remove info banner

* update swagger definition for AccountAction

* basic user view, suspend action

* clean up suspended user display

* basic user searching

* rename User -> Account for clarity

* refactor error boundary component to give better info

* appease the linter
This commit is contained in:
f0x52
2023-05-13 12:17:22 +02:00
committed by GitHub
parent b47661f033
commit 89dcbd5a20
16 changed files with 419 additions and 37 deletions

View File

@ -21,11 +21,8 @@
const React = require("react");
const { Link, Route, Redirect, Switch, useLocation, useRouter } = require("wouter");
const { ErrorBoundary } = require("react-error-boundary");
const syncpipe = require("syncpipe");
const { ErrorFallback } = require("../../components/error");
const {
RoleContext,
useHasPermission,
@ -72,8 +69,8 @@ function ViewRouter(routing, defaultRoute) {
(_) => _.map((route) => {
return (
<Route path={route.routingUrl} key={route.key}>
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => { }}>
{/* FIXME: implement onReset */}
<ErrorBoundary>
{/* FIXME: implement reset */}
<BaseUrlContext.Provider value={route.url}>
{route.view}
</BaseUrlContext.Provider>
@ -134,6 +131,71 @@ function MenuComponent({ type, name, url, icon, permissions, links, level, child
);
}
class ErrorBoundary extends React.Component {
constructor() {
super();
this.state = {};
this.resetErrorBoundary = () => {
this.setState({});
};
}
static getDerivedStateFromError(error) {
return { hadError: true, error };
}
componentDidCatch(_e, info) {
this.setState({
...this.state,
componentStack: info.componentStack
});
}
render() {
if (this.state.hadError) {
return (
<ErrorFallback
error={this.state.error}
componentStack={this.state.componentStack}
resetErrorBoundary={this.resetErrorBoundary}
/>
);
} else {
return this.props.children;
}
}
}
function ErrorFallback({ error, componentStack, resetErrorBoundary }) {
return (
<div className="error">
<p>
{"An error occured, please report this on the "}
<a href="https://github.com/superseriousbusiness/gotosocial/issues">GoToSocial issue tracker</a>
{" or "}
<a href="https://matrix.to/#/#gotosocial-help:superseriousbusiness.org">Matrix support room</a>.
<br />Include the details below:
</p>
<div className="details">
<pre>
{error.name}: {error.message}
{componentStack && [
"\n\nComponent trace:",
componentStack
]}
{["\n\nError trace: ", error.stack]}
</pre>
</div>
<p>
<button onClick={resetErrorBoundary}>Try again</button> or <a href="">refresh the page</a>
</p>
</div>
);
}
module.exports = {
Sidebar,
ViewRouter,

View File

@ -78,6 +78,32 @@ const endpoints = (build) => ({
}
})
}),
getAccount: build.query({
query: (id) => ({
url: `/api/v1/accounts/${id}`
}),
providesTags: (_, __, id) => [{ type: "Account", id }]
}),
actionAccount: build.mutation({
query: ({ id, action, reason }) => ({
method: "POST",
url: `/api/v1/admin/accounts/${id}/action`,
asForm: true,
body: {
type: action,
text: reason
}
}),
invalidatesTags: (_, __, { id }) => [{ type: "Account", id }]
}),
searchAccount: build.mutation({
query: (username) => ({
url: `/api/v2/search?q=${encodeURIComponent(username)}&resolve=true`
}),
transformResponse: (res) => {
return res.accounts ?? [];
}
}),
...require("./import-export")(build),
...require("./custom-emoji")(build),
...require("./reports")(build)

View File

@ -73,7 +73,7 @@ function instanceBasedQuery(args, api, extraOptions) {
module.exports = createApi({
reducerPath: "api",
baseQuery: instanceBasedQuery,
tagTypes: ["Auth", "Emoji", "Reports"],
tagTypes: ["Auth", "Emoji", "Reports", "Account"],
endpoints: (build) => ({
instance: build.query({
query: () => ({