mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-24 20:56:39 +00:00
aaaaaaaaaaaa
This commit is contained in:
parent
e62f5f9dbc
commit
007bdfb232
|
@ -32,6 +32,7 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// DomainPermissionDraftGet returns one
|
||||
|
@ -174,7 +175,7 @@ func (p *Processor) DomainPermissionDraftAccept(
|
|||
existing gtsmodel.DomainPermission
|
||||
)
|
||||
|
||||
// Check if existing entry.
|
||||
// Try to get existing entry.
|
||||
switch permDraft.PermissionType {
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
existing, err = p.state.DB.GetDomainBlock(
|
||||
|
@ -193,6 +194,15 @@ func (p *Processor) DomainPermissionDraftAccept(
|
|||
return nil, "", gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// Check if we got existing entry.
|
||||
existed := !util.IsNil(existing)
|
||||
if existed && !overwrite {
|
||||
// Domain permission exists and we shouldn't
|
||||
// overwrite it, leave everything alone.
|
||||
const text = "a domain permission already exists with this permission type and domain"
|
||||
return nil, "", gtserror.NewErrorConflict(errors.New(text), text)
|
||||
}
|
||||
|
||||
// Function to clean up the accepted draft, only called if
|
||||
// creating or updating permission from draft is successful.
|
||||
deleteDraft := func() {
|
||||
|
@ -201,11 +211,9 @@ func (p *Processor) DomainPermissionDraftAccept(
|
|||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
if !existed {
|
||||
// Easy case, we just need to create a new domain
|
||||
// permission from the draft, and then delete it.
|
||||
case existing == nil:
|
||||
var (
|
||||
new *apimodel.DomainPermission
|
||||
actionID string
|
||||
|
@ -241,11 +249,10 @@ func (p *Processor) DomainPermissionDraftAccept(
|
|||
deleteDraft()
|
||||
|
||||
return new, actionID, errWithCode
|
||||
|
||||
} else {
|
||||
// Domain permission exists but we should overwrite
|
||||
// it by just updating the existing domain permission.
|
||||
// Domain can't change, so no need to re-run side effects.
|
||||
case overwrite:
|
||||
existing.SetCreatedByAccountID(permDraft.CreatedByAccountID)
|
||||
existing.SetCreatedByAccount(permDraft.CreatedByAccount)
|
||||
existing.SetPrivateComment(permDraft.PrivateComment)
|
||||
|
@ -273,13 +280,6 @@ func (p *Processor) DomainPermissionDraftAccept(
|
|||
|
||||
apiPerm, errWithCode := p.apiDomainPerm(ctx, existing, false)
|
||||
return apiPerm, "", errWithCode
|
||||
|
||||
// Domain permission exists and we shouldn't
|
||||
// overwrite it, leave everything alone.
|
||||
default:
|
||||
const text = "a domain permission already exists with this permission type and domain"
|
||||
err := fmt.Errorf("%w: %s", err, text)
|
||||
return nil, "", gtserror.NewErrorConflict(err, text)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package util
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// EqualPtrs returns whether the values contained within two comparable ptr types are equal.
|
||||
func EqualPtrs[T comparable](t1, t2 *T) bool {
|
||||
switch {
|
||||
|
@ -59,3 +61,8 @@ func PtrOrValue[T any](t *T, value T) T {
|
|||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func IsNil(i interface{}) bool {
|
||||
type eface struct{ _, data unsafe.Pointer }
|
||||
return (*eface)(unsafe.Pointer(&i)).data == nil
|
||||
}
|
||||
|
|
|
@ -107,7 +107,11 @@ function Error({ error, reset }: ErrorProps) {
|
|||
{ reset &&
|
||||
<span
|
||||
className="dismiss"
|
||||
onClick={reset}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
reset();
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
|
|
|
@ -17,18 +17,107 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useLocation } from "wouter";
|
||||
import { AdminAccount } from "../lib/types/account";
|
||||
import { useLazyGetAccountQuery } from "../lib/query/admin";
|
||||
import Loading from "./loading";
|
||||
import { Error as ErrorC } from "./error";
|
||||
|
||||
interface UsernameProps {
|
||||
interface UsernameLozengeProps {
|
||||
/**
|
||||
* Either an account ID (for fetching) or an account.
|
||||
*/
|
||||
account?: string | AdminAccount;
|
||||
/**
|
||||
* Make the lozenge clickable and link to this location.
|
||||
*/
|
||||
linkTo?: string;
|
||||
/**
|
||||
* Location to set as backLocation after linking to linkTo.
|
||||
*/
|
||||
backLocation?: string;
|
||||
/**
|
||||
* Additional classnames to add to the lozenge.
|
||||
*/
|
||||
classNames?: string[];
|
||||
}
|
||||
|
||||
export default function UsernameLozenge({ account, linkTo, backLocation, classNames }: UsernameLozengeProps) {
|
||||
if (account === undefined) {
|
||||
return <>[unknown]</>;
|
||||
} else if (typeof account === "string") {
|
||||
return (
|
||||
<FetchUsernameLozenge
|
||||
accountID={account}
|
||||
linkTo={linkTo}
|
||||
backLocation={backLocation}
|
||||
classNames={classNames}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ReadyUsernameLozenge
|
||||
account={account}
|
||||
linkTo={linkTo}
|
||||
backLocation={backLocation}
|
||||
classNames={classNames}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface FetchUsernameLozengeProps {
|
||||
accountID: string;
|
||||
linkTo?: string;
|
||||
backLocation?: string;
|
||||
classNames?: string[];
|
||||
}
|
||||
|
||||
function FetchUsernameLozenge({ accountID, linkTo, backLocation, classNames }: FetchUsernameLozengeProps) {
|
||||
const [ trigger, result ] = useLazyGetAccountQuery();
|
||||
|
||||
// Call to get the account
|
||||
// using the provided ID.
|
||||
useEffect(() => {
|
||||
trigger(accountID, true);
|
||||
}, [trigger, accountID]);
|
||||
|
||||
const {
|
||||
data: account,
|
||||
isLoading,
|
||||
isFetching,
|
||||
isError,
|
||||
error,
|
||||
} = result;
|
||||
|
||||
// Wait for the account
|
||||
// model to be returned.
|
||||
if (isError) {
|
||||
return <ErrorC error={error} />;
|
||||
} else if (isLoading || isFetching || account === undefined) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<ReadyUsernameLozenge
|
||||
account={account}
|
||||
linkTo={linkTo}
|
||||
backLocation={backLocation}
|
||||
classNames={classNames}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface ReadyUsernameLozengeProps {
|
||||
account: AdminAccount;
|
||||
linkTo?: string;
|
||||
backLocation?: string;
|
||||
classNames?: string[];
|
||||
}
|
||||
|
||||
export default function Username({ account, linkTo, backLocation, classNames }: UsernameProps) {
|
||||
function ReadyUsernameLozenge({ account, linkTo, backLocation, classNames }: ReadyUsernameLozengeProps) {
|
||||
const [ _location, setLocation ] = useLocation();
|
||||
|
||||
let className = "username-lozenge";
|
|
@ -26,6 +26,7 @@ import type {
|
|||
DomainPermDraftSearchResp,
|
||||
} from "../../../types/domain-permission";
|
||||
import parse from "parse-link-header";
|
||||
import { PermType } from "../../../types/perm";
|
||||
|
||||
const extended = gtsApi.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
|
@ -78,6 +79,63 @@ const extended = gtsApi.injectEndpoints({
|
|||
}),
|
||||
invalidatesTags: [{ type: "DomainPermissionDraft", id: "TRANSFORMED" }],
|
||||
}),
|
||||
|
||||
acceptDomainPermissionDraft: build.mutation<DomainPerm, { id: string, overwrite?: boolean, permType: PermType }>({
|
||||
query: ({ id, overwrite }) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_drafts/${id}/accept`,
|
||||
asForm: true,
|
||||
body: {
|
||||
overwrite: overwrite,
|
||||
},
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: (res, _error, { id, permType }) => {
|
||||
const invalidated: any[] = [];
|
||||
|
||||
// If error, nothing to invalidate.
|
||||
if (!res) {
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
// Invalidate this draft by ID, and
|
||||
// the transformed list of all drafts.
|
||||
invalidated.push(
|
||||
{ type: 'DomainPermissionDraft', id: id },
|
||||
{ type: "DomainPermissionDraft", id: "TRANSFORMED" },
|
||||
);
|
||||
|
||||
// Invalidate cached blocks/allows depending
|
||||
// on the permType of the accepted draft.
|
||||
if (permType === "allow") {
|
||||
invalidated.push("domainAllows");
|
||||
} else {
|
||||
invalidated.push("domainBlocks");
|
||||
}
|
||||
|
||||
return invalidated;
|
||||
}
|
||||
}),
|
||||
|
||||
removeDomainPermissionDraft: build.mutation<DomainPerm, { id: string, ignore_target?: boolean }>({
|
||||
query: ({ id, ignore_target }) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_drafts/${id}/remove`,
|
||||
asForm: true,
|
||||
body: {
|
||||
ignore_target: ignore_target,
|
||||
},
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: (res, _error, { id }) =>
|
||||
res
|
||||
? [
|
||||
{ type: "DomainPermissionDraft", id },
|
||||
{ type: "DomainPermissionDraft", id: "TRANSFORMED" },
|
||||
]
|
||||
: [],
|
||||
})
|
||||
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -96,8 +154,20 @@ const useGetDomainPermissionDraftQuery = extended.useGetDomainPermissionDraftQue
|
|||
*/
|
||||
const useCreateDomainPermissionDraftMutation = extended.useCreateDomainPermissionDraftMutation;
|
||||
|
||||
/**
|
||||
* Accept a domain permission draft, turning it into an enforced domain permission.
|
||||
*/
|
||||
const useAcceptDomainPermissionDraftMutation = extended.useAcceptDomainPermissionDraftMutation;
|
||||
|
||||
/**
|
||||
* Remove a domain permission draft, optionally ignoring all future drafts targeting the given domain.
|
||||
*/
|
||||
const useRemoveDomainPermissionDraftMutation = extended.useRemoveDomainPermissionDraftMutation;
|
||||
|
||||
export {
|
||||
useLazySearchDomainPermissionDraftsQuery,
|
||||
useGetDomainPermissionDraftQuery,
|
||||
useCreateDomainPermissionDraftMutation,
|
||||
useAcceptDomainPermissionDraftMutation,
|
||||
useRemoveDomainPermissionDraftMutation,
|
||||
};
|
||||
|
|
|
@ -41,3 +41,16 @@ export function UseOurInstanceAccount(account: AdminAccount): boolean {
|
|||
|
||||
return !account.domain && account.username == ourDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uppercase first letter of given string.
|
||||
*/
|
||||
export function useCapitalize(i?: string): string {
|
||||
return useMemo(() => {
|
||||
if (i === undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return i.charAt(0).toUpperCase() + i.slice(1);
|
||||
}, [i]);
|
||||
}
|
||||
|
|
|
@ -1364,6 +1364,7 @@ button.tab-button {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.block {
|
||||
border-left: 0.3rem solid $error3;
|
||||
|
@ -1385,6 +1386,18 @@ button.tab-button {
|
|||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
|
||||
> .mutation-button
|
||||
> button {
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { useLocation, useParams } from "wouter";
|
||||
import { PermType } from "../../../lib/types/perm";
|
||||
import { useDeleteHeaderAllowMutation, useDeleteHeaderBlockMutation, useGetHeaderAllowQuery, useGetHeaderBlockQuery } from "../../../lib/query/admin/http-header-permissions";
|
||||
|
@ -26,8 +26,7 @@ import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
|||
import { SerializedError } from "@reduxjs/toolkit";
|
||||
import Loading from "../../../components/loading";
|
||||
import { Error } from "../../../components/error";
|
||||
import { useLazyGetAccountQuery } from "../../../lib/query/admin";
|
||||
import Username from "../../../components/username";
|
||||
import UsernameLozenge from "../../../components/username-lozenge";
|
||||
import { useBaseUrl } from "../../../lib/navigation/util";
|
||||
import BackButton from "../../../components/back-button";
|
||||
import MutationButton from "../../../components/form/mutation-button";
|
||||
|
@ -92,58 +91,19 @@ interface PermDeetsProps {
|
|||
function PermDeets({
|
||||
permType,
|
||||
data: perm,
|
||||
isLoading: isLoadingPerm,
|
||||
isFetching: isFetchingPerm,
|
||||
isError: isErrorPerm,
|
||||
error: errorPerm,
|
||||
isLoading,
|
||||
isFetching,
|
||||
isError,
|
||||
error,
|
||||
}: PermDeetsProps) {
|
||||
const [ location ] = useLocation();
|
||||
const baseUrl = useBaseUrl();
|
||||
|
||||
// Once we've loaded the perm, trigger
|
||||
// getting the account that created it.
|
||||
const [ getAccount, getAccountRes ] = useLazyGetAccountQuery();
|
||||
useEffect(() => {
|
||||
if (!perm) {
|
||||
return;
|
||||
}
|
||||
getAccount(perm.created_by, true);
|
||||
}, [getAccount, perm]);
|
||||
|
||||
// Load the createdByAccount if possible,
|
||||
// returning a username lozenge with
|
||||
// a link to the account.
|
||||
const createdByAccount = useMemo(() => {
|
||||
const {
|
||||
data: account,
|
||||
isLoading: isLoadingAccount,
|
||||
isFetching: isFetchingAccount,
|
||||
isError: isErrorAccount,
|
||||
} = getAccountRes;
|
||||
|
||||
// Wait for query to finish, returning
|
||||
// loading spinner in the meantime.
|
||||
if (isLoadingAccount || isFetchingAccount || !perm) {
|
||||
// Wait til the perm itself is loaded.
|
||||
if (isLoading || isFetching) {
|
||||
return <Loading />;
|
||||
} else if (isErrorAccount || account === undefined) {
|
||||
// Fall back to account ID.
|
||||
return perm?.created_by;
|
||||
}
|
||||
|
||||
return (
|
||||
<Username
|
||||
account={account}
|
||||
linkTo={`~/settings/moderation/accounts/${account.id}`}
|
||||
backLocation={`~${baseUrl}${location}`}
|
||||
/>
|
||||
);
|
||||
}, [getAccountRes, perm, baseUrl, location]);
|
||||
|
||||
// Now wait til the perm itself is loaded.
|
||||
if (isLoadingPerm || isFetchingPerm) {
|
||||
return <Loading />;
|
||||
} else if (isErrorPerm) {
|
||||
return <Error error={errorPerm} />;
|
||||
} else if (isError) {
|
||||
return <Error error={error} />;
|
||||
} else if (perm === undefined) {
|
||||
throw "perm undefined";
|
||||
}
|
||||
|
@ -172,7 +132,13 @@ function PermDeets({
|
|||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Created By</dt>
|
||||
<dd>{createdByAccount}</dd>
|
||||
<dd>
|
||||
<UsernameLozenge
|
||||
account={perm.created_by}
|
||||
linkTo={`~/settings/moderation/accounts/${perm.created_by}`}
|
||||
backLocation={`~${baseUrl}${location}`}
|
||||
/>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Header Name</dt>
|
||||
|
|
|
@ -21,7 +21,7 @@ import React, { ReactNode } from "react";
|
|||
import { useSearchAccountsQuery } from "../../../../lib/query/admin";
|
||||
import { PageableList } from "../../../../components/pageable-list";
|
||||
import { useLocation } from "wouter";
|
||||
import Username from "../../../../components/username";
|
||||
import UsernameLozenge from "../../../../components/username-lozenge";
|
||||
import { AdminAccount } from "../../../../lib/types/account";
|
||||
|
||||
export default function AccountsPending() {
|
||||
|
@ -32,7 +32,7 @@ export default function AccountsPending() {
|
|||
function itemToEntry(account: AdminAccount): ReactNode {
|
||||
const acc = account.account;
|
||||
return (
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
key={acc.acct}
|
||||
account={account}
|
||||
linkTo={`/${account.id}`}
|
||||
|
|
|
@ -26,7 +26,7 @@ import { Select, TextInput } from "../../../../components/form/inputs";
|
|||
import MutationButton from "../../../../components/form/mutation-button";
|
||||
import { useLocation, useSearch } from "wouter";
|
||||
import { AdminAccount } from "../../../../lib/types/account";
|
||||
import Username from "../../../../components/username";
|
||||
import UsernameLozenge from "../../../../components/username-lozenge";
|
||||
import { formDomainValidator } from "../../../../lib/util/formvalidators";
|
||||
|
||||
export function AccountSearchForm() {
|
||||
|
@ -93,7 +93,7 @@ export function AccountSearchForm() {
|
|||
function itemToEntry(account: AdminAccount): ReactNode {
|
||||
const acc = account.account;
|
||||
return (
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
key={acc.acct}
|
||||
account={account}
|
||||
linkTo={`/${account.id}`}
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import React from "react";
|
||||
import { useParams } from "wouter";
|
||||
import Loading from "../../../../components/loading";
|
||||
import { useBaseUrl } from "../../../../lib/navigation/util";
|
||||
import BackButton from "../../../../components/back-button";
|
||||
import { useGetDomainPermissionDraftQuery } from "../../../../lib/query/admin/domain-permissions/drafts";
|
||||
import { Error as ErrorC } from "../../../../components/error";
|
||||
import Username from "../../../../components/username";
|
||||
import { useLazyGetAccountQuery } from "../../../../lib/query/admin";
|
||||
import UsernameLozenge from "../../../../components/username-lozenge";
|
||||
|
||||
export default function DomainPermissionDraftDetail() {
|
||||
const baseUrl = useBaseUrl();
|
||||
|
@ -45,50 +44,6 @@ export default function DomainPermissionDraftDetail() {
|
|||
error,
|
||||
} = useGetDomainPermissionDraftQuery(draftID);
|
||||
|
||||
// Once we've triggered loading the perm draft,
|
||||
// trigger getting the account that created it.
|
||||
const [ getAccount, getAccountRes ] = useLazyGetAccountQuery();
|
||||
useEffect(() => {
|
||||
if (!permDraft) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!permDraft.created_by) {
|
||||
return;
|
||||
}
|
||||
|
||||
getAccount(permDraft.created_by, true);
|
||||
}, [getAccount, permDraft]);
|
||||
|
||||
// Load the createdByAccount if possible,
|
||||
// returning a username lozenge with
|
||||
// a link to the account.
|
||||
const createdByAccount = useMemo(() => {
|
||||
const {
|
||||
data: account,
|
||||
isLoading: isLoadingAccount,
|
||||
isFetching: isFetchingAccount,
|
||||
isError: isErrorAccount,
|
||||
} = getAccountRes;
|
||||
|
||||
// Wait for query to finish, returning
|
||||
// loading spinner in the meantime.
|
||||
if (isLoadingAccount || isFetchingAccount || !permDraft) {
|
||||
return <Loading />;
|
||||
} else if (isErrorAccount || account === undefined) {
|
||||
// Fall back to account ID.
|
||||
return permDraft?.created_by;
|
||||
}
|
||||
|
||||
return (
|
||||
<Username
|
||||
account={account}
|
||||
linkTo={`~/settings/moderation/accounts/${account.id}`}
|
||||
backLocation={`~${location}`}
|
||||
/>
|
||||
);
|
||||
}, [getAccountRes, permDraft]);
|
||||
|
||||
if (isLoading || isFetching) {
|
||||
return <Loading />;
|
||||
} else if (isError) {
|
||||
|
@ -117,7 +72,13 @@ export default function DomainPermissionDraftDetail() {
|
|||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Created By</dt>
|
||||
<dd>{createdByAccount}</dd>
|
||||
<dd>
|
||||
<UsernameLozenge
|
||||
account={permDraft.created_by}
|
||||
linkTo={`~/settings/moderation/accounts/${permDraft.created_by}`}
|
||||
backLocation={`~${location}`}
|
||||
/>
|
||||
</dd>
|
||||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Domain</dt>
|
||||
|
|
|
@ -23,11 +23,12 @@ import { useTextInput } from "../../../../lib/form";
|
|||
import { PageableList } from "../../../../components/pageable-list";
|
||||
import MutationButton from "../../../../components/form/mutation-button";
|
||||
import { useLocation, useSearch } from "wouter";
|
||||
import { useLazySearchDomainPermissionDraftsQuery } from "../../../../lib/query/admin/domain-permissions/drafts";
|
||||
import { useAcceptDomainPermissionDraftMutation, useLazySearchDomainPermissionDraftsQuery, useRemoveDomainPermissionDraftMutation } from "../../../../lib/query/admin/domain-permissions/drafts";
|
||||
import { DomainPerm } from "../../../../lib/types/domain-permission";
|
||||
import { Error as ErrorC } from "../../../../components/error";
|
||||
import { Select, TextInput } from "../../../../components/form/inputs";
|
||||
import { formDomainValidator } from "../../../../lib/util/formvalidators";
|
||||
import { useCapitalize } from "../../../../lib/util";
|
||||
|
||||
export default function DomainPermissionDraftsSearch() {
|
||||
return (
|
||||
|
@ -190,20 +191,31 @@ interface DraftEntryProps {
|
|||
|
||||
function DraftListEntry({ permDraft, linkTo, backLocation }: DraftEntryProps) {
|
||||
const [ _location, setLocation ] = useLocation();
|
||||
const [ accept, acceptResult ] = useAcceptDomainPermissionDraftMutation();
|
||||
const [ remove, removeResult ] = useRemoveDomainPermissionDraftMutation();
|
||||
|
||||
const domain = permDraft.domain;
|
||||
const permType = permDraft.permission_type;
|
||||
const permTypeUpper = useCapitalize(permType);
|
||||
if (!permType) {
|
||||
return <ErrorC error={new Error("permission_type was undefined")} />;
|
||||
}
|
||||
|
||||
const publicComment = permDraft.public_comment ?? "[none]";
|
||||
const privateComment = permDraft.private_comment ?? "[none]";
|
||||
const subscriptionID = permDraft.subscription_id ?? "[none]";
|
||||
const id = permDraft.id;
|
||||
if (!id) {
|
||||
return <ErrorC error={new Error("id was undefined")} />;
|
||||
}
|
||||
|
||||
const title = `${permTypeUpper} ${domain}`;
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`pseudolink domain-permission-draft entry ${permType}`}
|
||||
// aria-label={title}
|
||||
// title={title}
|
||||
aria-label={title}
|
||||
title={title}
|
||||
onClick={() => {
|
||||
// When clicking on a draft, direct
|
||||
// to the detail view for that draft.
|
||||
|
@ -217,6 +229,7 @@ function DraftListEntry({ permDraft, linkTo, backLocation }: DraftEntryProps) {
|
|||
role="link"
|
||||
tabIndex={0}
|
||||
>
|
||||
<h3>{title}</h3>
|
||||
<dl className="info-list">
|
||||
<div className="info-list-entry">
|
||||
<dt>Domain:</dt>
|
||||
|
@ -236,11 +249,45 @@ function DraftListEntry({ permDraft, linkTo, backLocation }: DraftEntryProps) {
|
|||
<dt>Private comment:</dt>
|
||||
<dd className="text-cutoff">{privateComment}</dd>
|
||||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Public comment:</dt>
|
||||
<dd>{publicComment}</dd>
|
||||
</div>
|
||||
<div className="info-list-entry">
|
||||
<dt>Subscription:</dt>
|
||||
<dd className="text-cutoff">{subscriptionID}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div className="action-buttons">
|
||||
<MutationButton
|
||||
label={`Accept ${permType}`}
|
||||
title={`Accept ${permType}`}
|
||||
type="button"
|
||||
className="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
accept({ id, permType });
|
||||
}}
|
||||
disabled={false}
|
||||
showError={true}
|
||||
result={acceptResult}
|
||||
/>
|
||||
<MutationButton
|
||||
label={`Remove draft`}
|
||||
title={`Remove draft`}
|
||||
type="button"
|
||||
className="button danger"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
remove({ id });
|
||||
}}
|
||||
disabled={false}
|
||||
showError={true}
|
||||
result={removeResult}
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,11 @@ import { useBoolInput, useRadioInput, useTextInput } from "../../../../lib/form"
|
|||
import { formDomainValidator } from "../../../../lib/util/formvalidators";
|
||||
import MutationButton from "../../../../components/form/mutation-button";
|
||||
import { Checkbox, RadioGroup, TextArea, TextInput } from "../../../../components/form/inputs";
|
||||
import { useLocation } from "wouter";
|
||||
|
||||
export default function DomainPermissionDraftNew() {
|
||||
const [ _location, setLocation ] = useLocation();
|
||||
|
||||
const form = {
|
||||
domain: useTextInput("domain", {
|
||||
validator: formDomainValidator,
|
||||
|
@ -41,7 +44,19 @@ export default function DomainPermissionDraftNew() {
|
|||
private_comment: useTextInput("private_comment"),
|
||||
};
|
||||
|
||||
const [formSubmit, result] = useFormSubmit(form, useCreateDomainPermissionDraftMutation());
|
||||
const [formSubmit, result] = useFormSubmit(
|
||||
form,
|
||||
useCreateDomainPermissionDraftMutation(),
|
||||
{
|
||||
changedOnly: false,
|
||||
onFinish: (res) => {
|
||||
if (res.data) {
|
||||
// Creation successful,
|
||||
// redirect to drafts overview.
|
||||
setLocation(`/drafts/search`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form
|
||||
|
|
|
@ -25,7 +25,7 @@ import { useValue, useTextInput } from "../../../lib/form";
|
|||
import useFormSubmit from "../../../lib/form/submit";
|
||||
import { TextArea } from "../../../components/form/inputs";
|
||||
import MutationButton from "../../../components/form/mutation-button";
|
||||
import Username from "../../../components/username";
|
||||
import UsernameLozenge from "../../../components/username-lozenge";
|
||||
import { useGetReportQuery, useResolveReportMutation } from "../../../lib/query/admin/reports";
|
||||
import { useBaseUrl } from "../../../lib/navigation/util";
|
||||
import { AdminReport } from "../../../lib/types/report";
|
||||
|
@ -99,7 +99,7 @@ function ReportBasicInfo({ report, baseUrl, location }: ReportSectionProps) {
|
|||
<div className="info-list-entry">
|
||||
<dt>Reported account</dt>
|
||||
<dd>
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
account={target}
|
||||
linkTo={`~/settings/moderation/accounts/${target.id}`}
|
||||
backLocation={`~${baseUrl}${location}`}
|
||||
|
@ -110,7 +110,7 @@ function ReportBasicInfo({ report, baseUrl, location }: ReportSectionProps) {
|
|||
<div className="info-list-entry">
|
||||
<dt>Reported by</dt>
|
||||
<dd>
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
account={from}
|
||||
linkTo={`~/settings/moderation/accounts/${from.id}`}
|
||||
backLocation={`~${baseUrl}${location}`}
|
||||
|
@ -173,7 +173,7 @@ function ReportHistory({ report, baseUrl, location }: ReportSectionProps) {
|
|||
<div className="info-list-entry">
|
||||
<dt>Handled by</dt>
|
||||
<dd>
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
account={handled_by}
|
||||
linkTo={`~/settings/moderation/accounts/${handled_by.id}`}
|
||||
backLocation={`~${baseUrl}${location}`}
|
||||
|
|
|
@ -25,7 +25,7 @@ import { PageableList } from "../../../components/pageable-list";
|
|||
import { Select } from "../../../components/form/inputs";
|
||||
import MutationButton from "../../../components/form/mutation-button";
|
||||
import { useLocation, useSearch } from "wouter";
|
||||
import Username from "../../../components/username";
|
||||
import UsernameLozenge from "../../../components/username-lozenge";
|
||||
import { AdminReport } from "../../../lib/types/report";
|
||||
|
||||
export default function ReportsSearch() {
|
||||
|
@ -206,7 +206,7 @@ function ReportListEntry({ report, linkTo, backLocation }: ReportEntryProps) {
|
|||
<div className="info-list-entry">
|
||||
<dt>Reported account:</dt>
|
||||
<dd className="text-cutoff">
|
||||
<Username
|
||||
<UsernameLozenge
|
||||
account={target}
|
||||
classNames={["text-cutoff report-byline"]}
|
||||
/>
|
||||
|
@ -216,7 +216,7 @@ function ReportListEntry({ report, linkTo, backLocation }: ReportEntryProps) {
|
|||
<div className="info-list-entry">
|
||||
<dt>Reported by:</dt>
|
||||
<dd className="text-cutoff reported-by">
|
||||
<Username account={from} />
|
||||
<UsernameLozenge account={from} />
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in a new issue