eslint --fix

This commit is contained in:
f0x 2024-11-06 15:55:00 +01:00
parent 8464f20370
commit 251286f2c7
94 changed files with 625 additions and 579 deletions

View file

@ -46,7 +46,7 @@ new PhotoswipeCaptionPlugin(lightbox, {
type: 'auto',
captionContent(slide) {
return slide.data.alt;
}
},
});
lightbox.addFilter('itemData', (item) => {
@ -68,10 +68,10 @@ lightbox.addFilter('itemData', (item) => {
},
pause() {
el._player.pause();
}
},
},
width: parseInt(el.dataset.pswpWidth),
height: parseInt(el.dataset.pswpHeight)
height: parseInt(el.dataset.pswpHeight),
};
}
return item;
@ -169,12 +169,12 @@ Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => {
}, 1);
}
lightbox.loadAndOpen(parseInt(video.dataset.pswpIndex), {
gallery: video.closest(".photoswipe-gallery")
gallery: video.closest(".photoswipe-gallery"),
});
return false;
}
}
},
},
});
player.elements.container.title = video.title;

View file

@ -29,10 +29,10 @@ const prodCfg = {
transform: [
["@browserify/uglifyify", {
global: true,
exts: ".js"
exts: ".js",
}],
["@browserify/envify", { global: true }]
]
["@browserify/envify", { global: true }],
],
};
skulk({
@ -42,8 +42,8 @@ skulk({
prodCfg: {
servers: {
express: false,
livereload: false
}
livereload: false,
},
},
servers: {
express: {
@ -54,6 +54,8 @@ skulk({
delete proxyRes.headers['content-security-policy'];
},
},
assets: "/assets",
},
},
bundles: {
frontend: {
@ -64,8 +66,8 @@ skulk({
transform: [
["babelify", {
global: true,
ignore: [/node_modules\/(?!(photoswipe.*))/]
}]
ignore: [/node_modules\/(?!(photoswipe.*))/],
}],
],
},
settings: {
@ -75,7 +77,7 @@ skulk({
plugin: [
// Additional settings for TS are passed from tsconfig.json.
// See: https://github.com/TypeStrong/tsify#tsconfigjson
["tsify"]
["tsify"],
],
transform: [
// tsify is called before babelify, so we're just babelifying
@ -83,28 +85,28 @@ skulk({
["babelify", {
global: true,
ignore: [/node_modules\/(?!(nanoid)|(wouter))/],
}]
}],
],
presets: [
"react",
["postcss", {
output: "settings-style.css"
}]
]
output: "settings-style.css",
}],
],
},
cssThemes: {
entryFiles: cssThemes,
outputFile: "_discard",
presets: [["postcss", {
output: "_split"
}]]
output: "_split",
}]],
},
css: {
entryFiles: cssFiles,
outputFile: "_discard",
presets: [["postcss", {
output: "style.css"
}]]
}
}
output: "style.css",
}]],
},
},
});

View file

@ -19,7 +19,8 @@
import { useLogoutMutation, useVerifyCredentialsQuery } from "../../lib/query/oauth";
import { store } from "../../redux/store";
import React, { ReactNode } from "react";
import type { ReactNode } from "react";
import React from "react";
import Login from "./login";
import Loading from "../loading";

View file

@ -29,7 +29,7 @@ import { TextInput } from "../form/inputs";
export default function Login({ }) {
const form = {
instance: useTextInput("instance", {
defaultValue: window.location.origin
defaultValue: window.location.origin,
}),
scopes: useValue("scopes", "user admin"),
};

View file

@ -17,10 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { memo, useDeferredValue, useCallback, useMemo } from "react";
import { memo, useDeferredValue, useCallback, useMemo } from "react";
import { Checkable, ChecklistInputHook } from "../lib/form/types";
import type { Checkable, ChecklistInputHook } from "../lib/form/types";
interface CheckListProps {
field: ChecklistInputHook;
@ -75,7 +74,7 @@ const CheckListEntries = memo(
getExtraProps={getExtraProps}
/>
));
}
},
);
interface CheckListEntryProps {
@ -94,7 +93,7 @@ const CheckListEntry = memo(
function CheckListEntry({ entry, updateValue, getExtraProps, EntryComponent }: CheckListEntryProps) {
const onChange = useCallback(
(value) => updateValue(entry.key, value),
[updateValue, entry.key]
[updateValue, entry.key],
);
const extraProps = useMemo(() => getExtraProps?.(entry), [getExtraProps, entry]);
@ -109,5 +108,5 @@ const CheckListEntry = memo(
<EntryComponent entry={entry} onChange={onChange} extraProps={extraProps} />
</label>
);
}
},
);

View file

@ -17,9 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { SerializedError } from "@reduxjs/toolkit";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import React, { ReactNode } from "react";
import type { SerializedError } from "@reduxjs/toolkit";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { ReactNode } from "react";
import React from "react";
function ErrorFallback({ error, resetErrorBoundary }) {
return (
@ -74,7 +75,7 @@ function Error({ error, reset }: ErrorProps) {
return null;
}
/* eslint-disable-next-line no-console */
console.error("caught error: ", error);
let message: ReactNode;

View file

@ -21,7 +21,7 @@ import React from "react";
import { all } from "langs";
const asElements = all().map((l) => {
let code = l["1"].toUpperCase();
const code = l["1"].toUpperCase();
let name = l.name;
if (l.name != l.local) {
name = `${name} - ${l.local}`;

View file

@ -17,12 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { ReactNode } from "react";
import type { ReactNode } from "react";
import React from "react";
import { useLocation } from "wouter";
import { Error } from "./error";
import { SerializedError } from "@reduxjs/toolkit";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { Links } from "parse-link-header";
import type { SerializedError } from "@reduxjs/toolkit";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { Links } from "parse-link-header";
import Loading from "./loading";
export interface PageableListProps<T> {

View file

@ -19,14 +19,14 @@
import React from "react";
import { useVerifyCredentialsQuery } from "../lib/query/oauth";
import { MediaAttachment, Status as StatusType } from "../lib/types/status";
import type { MediaAttachment, Status as StatusType } from "../lib/types/status";
import sanitize from "sanitize-html";
export function FakeStatus({ children }) {
const { data: account = {
avatar: "/assets/default_avatars/GoToSocial_icon1.webp",
display_name: "",
username: ""
username: "",
} } = useVerifyCredentialsQuery();
return (

View file

@ -19,7 +19,7 @@
import React from "react";
import { useLocation } from "wouter";
import { AdminAccount } from "../lib/types/account";
import type { AdminAccount } from "../lib/types/account";
interface UsernameProps {
account: AdminAccount;
@ -32,7 +32,7 @@ export default function Username({ account, linkTo, backLocation, classNames }:
const [ _location, setLocation ] = useLocation();
let className = "username-lozenge";
let isLocal = account.domain == null;
const isLocal = account.domain == null;
if (account.suspended) {
className += " suspended";
@ -46,7 +46,7 @@ export default function Username({ account, linkTo, backLocation, classNames }:
className = [ className, classNames ].flat().join(" ");
}
let icon = isLocal
const icon = isLocal
? { fa: "fa-home", info: "Local user" }
: { fa: "fa-external-link-square", info: "Remote user" };
@ -71,7 +71,7 @@ export default function Username({ account, linkTo, backLocation, classNames }:
// Store the back location in history so
// the detail view can use it to return to
// this page (including query parameters).
state: { backLocation: backLocation }
state: { backLocation: backLocation },
});
}}
role="link"

View file

@ -26,7 +26,7 @@ import { PersistGate } from "redux-persist/integration/react";
import { store, persistor } from "./redux/store";
import { Authorization } from "./components/authorization";
import Loading from "./components/loading";
import { Account } from "./lib/types/account";
import type { Account } from "./lib/types/account";
import { BaseUrlContext, RoleContext, InstanceDebugContext } from "./lib/navigation/util";
import { SidebarMenu } from "./lib/navigation/menu";
import { Redirect, Route, Router } from "wouter";

View file

@ -87,6 +87,6 @@ export default function useArrayInput(
} else {
return [];
}
}
},
};
}

View file

@ -27,7 +27,7 @@ import type {
const _default = false;
export default function useBoolInput(
{ name, Name }: CreateHookNames,
{ initialValue = _default }: HookOpts<boolean>
{ initialValue = _default }: HookOpts<boolean>,
): BoolFormInputHook {
const [value, setValue] = useState(initialValue);
@ -45,8 +45,8 @@ export default function useBoolInput(
reset,
{
[name]: value,
[`set${Name}`]: setValue
}
[`set${Name}`]: setValue,
},
], {
name,
Name: "",
@ -55,6 +55,6 @@ export default function useBoolInput(
value,
setter: setValue,
hasChanged: () => value != initialValue,
_default
_default,
});
}

View file

@ -38,20 +38,20 @@ import {
const _default: { [k: string]: Checkable } = {};
export default function useCheckListInput(
/* eslint-disable no-unused-vars */
{ name, Name }: CreateHookNames,
{
entries = [],
uniqueKey = "key",
initialValue = false,
}: HookOpts<boolean>
}: HookOpts<boolean>,
): ChecklistInputHook {
const [state, dispatch] = useChecklistReducer(entries, uniqueKey, initialValue);
const toggleAllRef = useRef<any>(null);
useEffect(() => {
if (toggleAllRef.current != null) {
let some = state.selectedEntries.size > 0;
const some = state.selectedEntries.size > 0;
let all = false;
if (some) {
all = state.selectedEntries.size == Object.values(state.entries).length;
@ -64,18 +64,24 @@ export default function useCheckListInput(
}, [state.selectedEntries]);
const reset = useCallback(
() => dispatch(actions.updateAll(initialValue)),
[initialValue, dispatch]
() => {
dispatch(actions.updateAll(initialValue));
},
[initialValue, dispatch],
);
const onChange = useCallback(
(key: string, value: Checkable) => dispatch(actions.update({ key, value })),
[dispatch]
(key: string, value: Checkable) => {
dispatch(actions.update({ key, value }));
},
[dispatch],
);
const updateMultiple = useCallback(
(entries: [key: string, value: Partial<Checkable>][]) => dispatch(actions.updateMultiple(entries)),
[dispatch]
(entries: [key: string, value: Partial<Checkable>][]) => {
dispatch(actions.updateMultiple(entries));
},
[dispatch],
);
return useMemo(() => {
@ -89,14 +95,14 @@ export default function useCheckListInput(
function selectedValues() {
return Array.from((state.selectedEntries)).map((key) => ({
...state.entries[key] // returned as new object, because reducer state is immutable
...state.entries[key], // returned as new object, because reducer state is immutable
}));
}
return Object.assign([
state,
reset,
{ name }
{ name },
], {
_default,
hasChanged: () => true,
@ -110,8 +116,8 @@ export default function useCheckListInput(
updateMultiple,
toggleAll: {
ref: toggleAllRef,
onChange: toggleAll
}
onChange: toggleAll,
},
});
}, [state, reset, name, onChange, updateMultiple, dispatch]);
}

View file

@ -20,7 +20,7 @@
import { useState } from "react";
import { useComboboxState } from "ariakit/combobox";
import {
import type {
ComboboxFormInputHook,
CreateHookNames,
HookOpts,
@ -29,14 +29,14 @@ import {
const _default = "";
export default function useComboBoxInput(
{ name, Name }: CreateHookNames,
{ initialValue = _default }: HookOpts<string>
{ initialValue = _default }: HookOpts<string>,
): ComboboxFormInputHook {
const [isNew, setIsNew] = useState(false);
const state = useComboboxState({
defaultValue: initialValue,
gutter: 0,
sameWidth: true
sameWidth: true,
});
function reset() {
@ -50,18 +50,20 @@ export default function useComboBoxInput(
[name]: state.value,
name,
[`${name}IsNew`]: isNew,
[`set${Name}IsNew`]: setIsNew
}
[`set${Name}IsNew`]: setIsNew,
},
], {
reset,
name,
Name: "", // Will be set by inputHook function.
state,
value: state.value,
setter: (val: string) => state.setValue(val),
setter: (val: string) => {
state.setValue(val);
},
hasChanged: () => state.value != initialValue,
isNew,
setIsNew,
_default
_default,
});
}

View file

@ -80,6 +80,6 @@ export default function useFieldArrayInput(
} else {
return [];
}
}
},
};
}

View file

@ -17,9 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { useState } from "react";
import { useState } from "react";
import prettierBytes from "prettier-bytes";
import type {
@ -35,8 +34,8 @@ export default function useFileInput(
{
withPreview,
maxSize,
initialInfo = "no file selected"
}: HookOpts<File>
initialInfo = "no file selected",
}: HookOpts<File>,
): FileFormInputHook {
const [file, setFile] = useState<File>();
const [imageURL, setImageURL] = useState<string>();
@ -58,7 +57,7 @@ export default function useFileInput(
return;
}
let file = files[0];
const file = files[0];
setFile(file);
if (imageURL) {
@ -76,7 +75,7 @@ export default function useFileInput(
<ErrorC
error={new Error(`file size ${sizePrettier} is larger than max size ${maxSizePrettier}`)}
reset={(reset)}
/>
/>,
);
} else {
setInfo(<>{file.name} ({sizePrettier})</>);
@ -100,7 +99,7 @@ export default function useFileInput(
[name]: file,
[`${name}URL`]: imageURL,
[`${name}Info`]: infoComponent,
}
},
], {
onChange,
reset,

View file

@ -17,14 +17,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-unused-vars */
import React from "react";
import { Error } from "../../components/error";
import Loading from "../../components/loading";
import { NoArg } from "../types/query";
import { FormWithDataQuery } from "./types";
import type { FormWithDataQuery } from "./types";
export interface FormWithDataProps {
dataQuery: FormWithDataQuery,

View file

@ -17,17 +17,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { FormInputHook, HookedForm } from "./types";
import type { FormInputHook, HookedForm } from "./types";
export default function getFormMutations(
form: HookedForm,
{ changedOnly }: { changedOnly: boolean },
): {
updatedFields: FormInputHook<any>[];
updatedFields: FormInputHook[];
mutationData: {
[k: string]: any;
};
} {
} {
const updatedFields: FormInputHook[] = [];
const mutationData: Array<[string, any]> = [];

View file

@ -18,7 +18,7 @@
*/
import { useState } from "react";
import { CreateHookNames, HookOpts, RadioFormInputHook } from "./types";
import type { CreateHookNames, HookOpts, RadioFormInputHook } from "./types";
const _default = "";
export default function useRadioInput(
@ -26,7 +26,7 @@ export default function useRadioInput(
{
initialValue = _default,
options = {},
}: HookOpts<string>
}: HookOpts<string>,
): RadioFormInputHook {
const [value, setValue] = useState(initialValue);
@ -44,8 +44,8 @@ export default function useRadioInput(
reset,
{
[name]: value,
[`set${Name}`]: setValue
}
[`set${Name}`]: setValue,
},
], {
onChange,
reset,
@ -55,6 +55,6 @@ export default function useRadioInput(
setter: setValue,
options,
hasChanged: () => value != initialValue,
_default
_default,
});
}

View file

@ -60,7 +60,7 @@ interface UseFormSubmitOptions {
export default function useFormSubmit(
form: HookedForm,
mutationQuery: readonly [MutationTrigger<any>, UseMutationStateResult<any, any>],
opts: UseFormSubmitOptions = { changedOnly: true }
opts: UseFormSubmitOptions = { changedOnly: true },
): [ FormSubmitFunction, FormSubmitResult ] {
if (!Array.isArray(mutationQuery)) {
throw "useFormSubmit: mutationQuery was not an Array. Is a valid useMutation RTK Query provided?";
@ -90,7 +90,7 @@ export default function useFormSubmit(
// what at this point. If it's an empty string, fall back to undefined.
//
// See: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
action = (e.nativeEvent.submitter as Object as { name: string }).name || undefined;
action = (e.nativeEvent.submitter as object as { name: string }).name || undefined;
} else {
// No submitter defined. Fall back
// to just use the FormSubmitEvent.
@ -125,7 +125,7 @@ export default function useFormSubmit(
onFinish(res);
}
} catch (e) {
// eslint-disable-next-line no-console
console.error(`caught error running mutation: ${e}`);
}
};
@ -134,7 +134,7 @@ export default function useFormSubmit(
submitForm,
{
...mutationResult,
action: usedAction.current
}
action: usedAction.current,
},
];
}

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, {
import type React from "react";
import {
useState,
useRef,
useTransition,
@ -41,7 +42,7 @@ export default function useTextInput(
showValidation = true,
initValidation,
nosubmit = false,
}: HookOpts<string>
}: HookOpts<string>,
): TextFormInputHook {
const [text, setText] = useState(initialValue);
const textRef = useRef<HTMLInputElement>(null);
@ -86,7 +87,7 @@ export default function useTextInput(
[`${name}Ref`]: textRef,
[`set${Name}`]: setText,
[`${name}Valid`]: valid,
}
},
], {
onChange,
reset,
@ -97,8 +98,10 @@ export default function useTextInput(
ref: textRef,
setter: setText,
valid,
validate: () => setValidation(validator ? validator(text): ""),
validate: () => {
setValidation(validator ? validator(text): "");
},
hasChanged: () => text != initialValue,
_default
_default,
});
}

View file

@ -17,12 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-unused-vars */
import { ComboboxState } from "ariakit";
import React from "react";
import {
import type { ComboboxState } from "ariakit";
import type React, {
ChangeEventHandler,
Dispatch,
RefObject,
@ -30,6 +26,7 @@ import {
SyntheticEvent,
} from "react";
export interface CreateHookNames {
name: string;
Name: string;
@ -227,7 +224,7 @@ export interface ChecklistInputHook<T = Checkable> extends FormInputHook<{[k: st
_withUpdateMultiple {
// Uses its own funky onChange handler.
onChange: (key: any, value: any) => void
}
}
export type AnyFormInputHook =
FormInputHook |

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { Component, ReactNode } from "react";
import type { ReactNode } from "react";
import React, { Component } from "react";
interface ErrorBoundaryProps {
@ -48,7 +49,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
componentDidCatch(_e, info) {
this.setState({
...this.state,
componentStack: info.componentStack
componentStack: info.componentStack,
});
}
@ -83,7 +84,7 @@ function ErrorFallback({ error, componentStack, resetErrorBoundary }) {
{componentStack && [
"\n\nComponent trace:",
componentStack
componentStack,
]}
{["\n\nError trace: ", error.stack]}
</pre>

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { PropsWithChildren } from "react";
import type { PropsWithChildren } from "react";
import React from "react";
import { Link, useRoute } from "wouter";
import {
BaseUrlContext,

View file

@ -26,9 +26,9 @@ const extended = gtsApi.injectEndpoints({
method: "POST",
url: `/api/v1/admin/media_cleanup`,
params: {
remote_cache_days: days
}
})
remote_cache_days: days,
},
}),
}),
instanceKeysExpire: build.mutation({
@ -36,9 +36,9 @@ const extended = gtsApi.injectEndpoints({
method: "POST",
url: `/api/v1/admin/domain_keys_expire`,
params: {
domain: domain
}
})
domain: domain,
},
}),
}),
sendTestEmail: build.mutation<any, { email: string, message?: string }>({
@ -46,7 +46,7 @@ const extended = gtsApi.injectEndpoints({
method: "POST",
url: `/api/v1/admin/email/test`,
params: params,
})
}),
}),
}),
});

View file

@ -18,8 +18,8 @@
*/
import { gtsApi } from "../../gts-api";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { RootState } from "../../../../redux/store";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { RootState } from "../../../../redux/store";
import type { CustomEmoji, EmojisFromItem, ListEmojiParams } from "../../../types/custom-emoji";
@ -77,39 +77,39 @@ const extended = gtsApi.injectEndpoints({
url: "/api/v1/admin/custom_emojis",
params: {
limit: 0,
...params
}
...params,
},
}),
providesTags: (res, _error, _arg) =>
res
? [
...res.map((emoji) => ({ type: "Emoji" as const, id: emoji.id })),
{ type: "Emoji", id: "LIST" }
{ type: "Emoji", id: "LIST" },
]
: [{ type: "Emoji", id: "LIST" }]
: [{ type: "Emoji", id: "LIST" }],
}),
getEmoji: build.query<CustomEmoji, string>({
query: (id) => ({
url: `/api/v1/admin/custom_emojis/${id}`
url: `/api/v1/admin/custom_emojis/${id}`,
}),
providesTags: (_res, _error, id) => [{ type: "Emoji", id }]
providesTags: (_res, _error, id) => [{ type: "Emoji", id }],
}),
addEmoji: build.mutation<CustomEmoji, Object>({
addEmoji: build.mutation<CustomEmoji, object>({
query: (form) => {
return {
method: "POST",
url: `/api/v1/admin/custom_emojis`,
asForm: true,
body: form,
discardEmpty: true
discardEmpty: true,
};
},
invalidatesTags: (res) =>
res
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
: [{ type: "Emoji", id: "LIST" }]
: [{ type: "Emoji", id: "LIST" }],
}),
editEmoji: build.mutation<CustomEmoji, any>({
@ -120,22 +120,22 @@ const extended = gtsApi.injectEndpoints({
asForm: true,
body: {
type: "modify",
...patch
}
...patch,
},
};
},
invalidatesTags: (res) =>
res
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
: [{ type: "Emoji", id: "LIST" }]
: [{ type: "Emoji", id: "LIST" }],
}),
deleteEmoji: build.mutation<any, string>({
query: (id) => ({
method: "DELETE",
url: `/api/v1/admin/custom_emojis/${id}`
url: `/api/v1/admin/custom_emojis/${id}`,
}),
invalidatesTags: (_res, _error, id) => [{ type: "Emoji", id }]
invalidatesTags: (_res, _error, id) => [{ type: "Emoji", id }],
}),
searchItemForEmoji: build.mutation<EmojisFromItem, string>({
@ -145,10 +145,10 @@ const extended = gtsApi.injectEndpoints({
// First search for given url.
const searchRes = await fetchWithBQ({
url: `/api/v2/search?q=${encodeURIComponent(url)}&resolve=true&limit=1`
url: `/api/v2/search?q=${encodeURIComponent(url)}&resolve=true&limit=1`,
});
if (searchRes.error) {
return { error: searchRes.error as FetchBaseQueryError };
return { error: searchRes.error };
}
// Parse initial results of search.
@ -178,8 +178,8 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/custom_emojis`,
params: {
filter: `domain:${domain},shortcode:${emoji.shortcode}`,
limit: 1
}
limit: 1,
},
});
if (emojiRes.error) {
@ -191,7 +191,7 @@ const extended = gtsApi.injectEndpoints({
// Got it!
return emojiRes.data as CustomEmoji;
})
}),
)
).flatMap((emoji) => {
// Remove any nulls.
@ -205,7 +205,7 @@ const extended = gtsApi.injectEndpoints({
status: 400,
statusText: 'Bad Request',
data: {
error: `One or more errors fetching custom emojis: [${errData}]`
error: `One or more errors fetching custom emojis: [${errData}]`,
},
},
};
@ -218,9 +218,9 @@ const extended = gtsApi.injectEndpoints({
type,
domain,
list: withIDs,
}
},
};
}
},
}),
patchRemoteEmojis: build.mutation({
@ -231,7 +231,7 @@ const extended = gtsApi.injectEndpoints({
// Map function to get a promise
// of an emoji (or null).
const copyEmoji = async(emoji: CustomEmoji) => {
let body: {
const body: {
type: string;
shortcode?: string;
category?: string;
@ -285,7 +285,7 @@ const extended = gtsApi.injectEndpoints({
status: 400,
statusText: 'Bad Request',
data: {
error: `One or more errors patching custom emojis: [${errData}]`
error: `One or more errors patching custom emojis: [${errData}]`,
},
},
};
@ -293,9 +293,9 @@ const extended = gtsApi.injectEndpoints({
return { data };
},
invalidatesTags: () => [{ type: "Emoji", id: "LIST" }]
})
})
invalidatesTags: () => [{ type: "Emoji", id: "LIST" }],
}),
}),
});
/**

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ApURLResponse } from "../../../types/debug";
import type { ApURLResponse } from "../../../types/debug";
import { gtsApi } from "../../gts-api";
const extended = gtsApi.injectEndpoints({
@ -32,13 +32,13 @@ const extended = gtsApi.injectEndpoints({
return {
url: `/api/v1/admin/debug/apurl?${urlParam.toString()}`,
};
}
},
}),
ClearCaches: build.mutation<{}, void>({
query: () => ({
method: "POST",
url: `/api/v1/admin/debug/caches/clear`
})
url: `/api/v1/admin/debug/caches/clear`,
}),
}),
}),
});

View file

@ -21,9 +21,9 @@ import fileDownload from "js-file-download";
import { unparse as csvUnparse } from "papaparse";
import { gtsApi } from "../../gts-api";
import { RootState } from "../../../../redux/store";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { DomainPerm, ExportDomainPermsParams } from "../../../types/domain-permission";
import type { RootState } from "../../../../redux/store";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { DomainPerm, ExportDomainPermsParams } from "../../../types/domain-permission";
interface _exportProcess {
transformEntry: (_entry: DomainPerm) => any;
@ -45,11 +45,11 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
transformEntry: (entry) => ({
domain: entry.domain,
public_comment: entry.public_comment,
obfuscate: entry.obfuscate
obfuscate: entry.obfuscate,
}),
stringify: (list) => JSON.stringify(list),
extension: ".json",
mime: "application/json"
mime: "application/json",
};
}
@ -61,7 +61,7 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
false, // reject_media
false, // reject_reports
entry.public_comment ?? "", // public_comment
entry.obfuscate ?? false // obfuscate
entry.obfuscate ?? false, // obfuscate
],
stringify: (list) => csvUnparse({
fields: [
@ -72,10 +72,10 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
"#public_comment",
"#obfuscate",
],
data: list
data: list,
}),
extension: ".csv",
mime: "text/csv"
mime: "text/csv",
};
}
@ -84,7 +84,7 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
transformEntry: (entry) => entry.domain,
stringify: (list) => list.join("\n"),
extension: ".txt",
mime: "text/plain"
mime: "text/plain",
};
}
@ -98,7 +98,7 @@ const extended = gtsApi.injectEndpoints({
// we want the untransformed array version.
const permsRes = await fetchWithBQ({ url: `/api/v1/admin/domain_${formData.permType}s` });
if (permsRes.error) {
return { error: permsRes.error as FetchBaseQueryError };
return { error: permsRes.error };
}
// Process perms into desired export format.
@ -130,16 +130,16 @@ const extended = gtsApi.injectEndpoints({
fileDownload(
exportAsString,
filename + process.extension,
process.mime
process.mime,
);
// js-file-download handles the
// nitty gritty for us, so we can
// just return null data.
return { data: null };
}
},
}),
}),
})
});
/**

View file

@ -26,14 +26,14 @@ const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
domainBlocks: build.query<MappedDomainPerms, void>({
query: () => ({
url: `/api/v1/admin/domain_blocks`
url: `/api/v1/admin/domain_blocks`,
}),
transformResponse: listToKeyedObject<DomainPerm>("domain"),
}),
domainAllows: build.query<MappedDomainPerms, void>({
query: () => ({
url: `/api/v1/admin/domain_allows`
url: `/api/v1/admin/domain_allows`,
}),
transformResponse: listToKeyedObject<DomainPerm>("domain"),
}),

View file

@ -36,7 +36,7 @@ import { listToKeyedObject } from "../../transforms";
* @returns
*/
function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: DomainPerm) => DomainPerm {
let processingFuncs: { (_entry: DomainPerm): void; }[] = [];
const processingFuncs: { (_entry: DomainPerm): void; }[] = [];
// Override each obfuscate entry if necessary.
if (formData.obfuscate !== undefined) {
@ -49,7 +49,7 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom
// Check whether we need to append or replace
// private_comment and public_comment.
["private_comment","public_comment"].forEach((commentType) => {
let text = formData.commentType?.trim();
const text = formData.commentType?.trim();
if (!text) {
return;
}
@ -78,7 +78,9 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom
return function process(entry) {
// Call all the assembled processing functions.
processingFuncs.forEach((f) => f(entry));
processingFuncs.forEach((f) => {
f(entry);
});
// Unset all internal processing keys
// and any undefined keys on this entry.
@ -111,7 +113,7 @@ const extended = gtsApi.injectEndpoints({
[JSON.stringify(domains)],
{ type: "application/json" },
),
}
},
};
},
transformResponse: listToKeyedObject<DomainPerm>("domain"),
@ -125,8 +127,8 @@ const extended = gtsApi.injectEndpoints({
formData.permType.slice(1);
return `domain${permType}s`;
}),
})
})
}),
}),
});
/**

View file

@ -17,9 +17,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type {
ParseConfig as CSVParseConfig} from "papaparse";
import {
ParseConfig as CSVParseConfig,
parse as csvParse
parse as csvParse,
} from "papaparse";
import { nanoid } from "nanoid";
@ -75,7 +76,7 @@ function parseDomainList(list: string): DomainPerm[] {
"reject_reports": true,
"public_comment": false,
"obfuscate": true,
}
},
};
const { data, errors } = csvParse(list, csvParseCfg);
@ -119,7 +120,7 @@ function parseDomainList(list: string): DomainPerm[] {
}
function deduplicateDomainList(list: DomainPerm[]): DomainPerm[] {
let domains = new Set();
const domains = new Set();
return list.filter((entry) => {
if (domains.has(entry.domain)) {
return false;
@ -168,9 +169,9 @@ const extended = gtsApi.injectEndpoints({
});
return { data: validated };
}
})
})
},
}),
}),
});
/**

View file

@ -26,7 +26,7 @@ import {
import { listToKeyedObject } from "../../transforms";
import type {
DomainPerm,
MappedDomainPerms
MappedDomainPerms,
} from "../../../types/domain-permission";
const extended = gtsApi.injectEndpoints({
@ -37,7 +37,7 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/domain_blocks`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
transformResponse: listToKeyedObject<DomainPerm>("domain"),
...replaceCacheOnMutation("domainBlocks"),
@ -49,10 +49,10 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/domain_allows`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
transformResponse: listToKeyedObject<DomainPerm>("domain"),
...replaceCacheOnMutation("domainAllows")
...replaceCacheOnMutation("domainAllows"),
}),
removeDomainBlock: build.mutation<DomainPerm, string>({
@ -63,8 +63,8 @@ const extended = gtsApi.injectEndpoints({
...removeFromCacheOnMutation("domainBlocks", {
key: (_draft, newData) => {
return newData.domain;
}
})
},
}),
}),
removeDomainAllow: build.mutation<DomainPerm, string>({
@ -75,8 +75,8 @@ const extended = gtsApi.injectEndpoints({
...removeFromCacheOnMutation("domainAllows", {
key: (_draft, newData) => {
return newData.domain;
}
})
},
}),
}),
}),
});
@ -105,5 +105,5 @@ export {
useAddDomainBlockMutation,
useAddDomainAllowMutation,
useRemoveDomainBlockMutation,
useRemoveDomainAllowMutation
useRemoveDomainAllowMutation,
};

View file

@ -18,7 +18,7 @@
*/
import { gtsApi } from "../../gts-api";
import { HeaderPermission } from "../../../types/http-header-permissions";
import type { HeaderPermission } from "../../../types/http-header-permissions";
const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
@ -27,7 +27,7 @@ const extended = gtsApi.injectEndpoints({
getHeaderAllows: build.query<HeaderPermission[], void>({
query: () => ({
url: `/api/v1/admin/header_allows`
url: `/api/v1/admin/header_allows`,
}),
providesTags: (res) =>
res
@ -40,7 +40,7 @@ const extended = gtsApi.injectEndpoints({
getHeaderAllow: build.query<HeaderPermission, string>({
query: (id) => ({
url: `/api/v1/admin/header_allows/${id}`
url: `/api/v1/admin/header_allows/${id}`,
}),
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
}),
@ -51,7 +51,7 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/header_allows`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
invalidatesTags: [{ type: "HTTPHeaderAllows", id: "LIST" }],
}),
@ -59,7 +59,7 @@ const extended = gtsApi.injectEndpoints({
deleteHeaderAllow: build.mutation<HeaderPermission, string>({
query: (id) => ({
method: "DELETE",
url: `/api/v1/admin/header_allows/${id}`
url: `/api/v1/admin/header_allows/${id}`,
}),
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
}),
@ -68,7 +68,7 @@ const extended = gtsApi.injectEndpoints({
getHeaderBlocks: build.query<HeaderPermission[], void>({
query: () => ({
url: `/api/v1/admin/header_blocks`
url: `/api/v1/admin/header_blocks`,
}),
providesTags: (res) =>
res
@ -85,14 +85,14 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/header_blocks`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
invalidatesTags: [{ type: "HTTPHeaderBlocks", id: "LIST" }],
}),
getHeaderBlock: build.query<HeaderPermission, string>({
query: (id) => ({
url: `/api/v1/admin/header_blocks/${id}`
url: `/api/v1/admin/header_blocks/${id}`,
}),
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
}),
@ -100,7 +100,7 @@ const extended = gtsApi.injectEndpoints({
deleteHeaderBlock: build.mutation<HeaderPermission, string>({
query: (id) => ({
method: "DELETE",
url: `/api/v1/admin/header_blocks/${id}`
url: `/api/v1/admin/header_blocks/${id}`,
}),
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
}),

View file

@ -20,8 +20,8 @@
import { replaceCacheOnMutation, removeFromCacheOnMutation } from "../query-modifiers";
import { gtsApi } from "../gts-api";
import { listToKeyedObject } from "../transforms";
import { ActionAccountParams, AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account";
import { InstanceRule, MappedRules } from "../../types/rules";
import type { ActionAccountParams, AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account";
import type { InstanceRule, MappedRules } from "../../types/rules";
import parse from "parse-link-header";
const extended = gtsApi.injectEndpoints({
@ -32,17 +32,17 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/instance`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
...replaceCacheOnMutation("instanceV1"),
}),
getAccount: build.query<AdminAccount, string>({
query: (id) => ({
url: `/api/v1/admin/accounts/${id}`
url: `/api/v1/admin/accounts/${id}`,
}),
providesTags: (_result, _error, id) => [
{ type: 'Account', id }
{ type: 'Account', id },
],
}),
@ -61,7 +61,7 @@ const extended = gtsApi.injectEndpoints({
}
return {
url: `/api/v2/admin/accounts${query}`
url: `/api/v2/admin/accounts${query}`,
};
},
// Headers required for paging.
@ -73,7 +73,7 @@ const extended = gtsApi.injectEndpoints({
},
// Only provide LIST tag id since this model is not the
// same as getAccount model (due to transformResponse).
providesTags: [{ type: "Account", id: "TRANSFORMED" }]
providesTags: [{ type: "Account", id: "TRANSFORMED" }],
}),
actionAccount: build.mutation<string, ActionAccountParams>({
@ -83,8 +83,8 @@ const extended = gtsApi.injectEndpoints({
asForm: true,
body: {
type: action,
text: reason
}
text: reason,
},
}),
// Do an optimistic update on this account to mark
// it according to whatever action was submitted.
@ -95,7 +95,7 @@ const extended = gtsApi.injectEndpoints({
draft.suspended = true;
draft.account.suspended = true;
}
})
}),
);
// Revert optimistic
@ -105,7 +105,7 @@ const extended = gtsApi.injectEndpoints({
} catch {
patchResult.undo();
}
}
},
}),
handleSignup: build.mutation<AdminAccount, HandleSignupParams>({
@ -124,7 +124,7 @@ const extended = gtsApi.injectEndpoints({
// Just invalidate this ID and getAccounts.
dispatch(extended.util.invalidateTags([
{ type: "Account", id: id },
{ type: "Account", id: "TRANSFORMED" }
{ type: "Account", id: "TRANSFORMED" },
]));
return;
}
@ -132,7 +132,7 @@ const extended = gtsApi.injectEndpoints({
const patchResult = dispatch(
extended.util.updateQueryData("getAccount", id, (draft) => {
draft.approved = true;
})
}),
);
// Revert optimistic
@ -142,14 +142,14 @@ const extended = gtsApi.injectEndpoints({
} catch {
patchResult.undo();
}
}
},
}),
instanceRules: build.query<MappedRules, void>({
query: () => ({
url: `/api/v1/admin/instance/rules`
url: `/api/v1/admin/instance/rules`,
}),
transformResponse: listToKeyedObject<InstanceRule>("id")
transformResponse: listToKeyedObject<InstanceRule>("id"),
}),
addInstanceRule: build.mutation<MappedRules, any>({
@ -158,7 +158,7 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/instance/rules`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
transformResponse: listToKeyedObject<InstanceRule>("id"),
...replaceCacheOnMutation("instanceRules"),
@ -170,11 +170,11 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/instance/rules/${id}`,
asForm: true,
body: edit,
discardEmpty: true
discardEmpty: true,
}),
transformResponse: (data) => {
return {
[data.id]: data
[data.id]: data,
};
},
...replaceCacheOnMutation("instanceRules"),
@ -183,13 +183,13 @@ const extended = gtsApi.injectEndpoints({
deleteInstanceRule: build.mutation({
query: (id) => ({
method: "DELETE",
url: `/api/v1/admin/instance/rules/${id}`
url: `/api/v1/admin/instance/rules/${id}`,
}),
...removeFromCacheOnMutation("instanceRules", {
key: (_draft, rule) => rule.id,
})
})
})
}),
}),
}),
});
export const {

View file

@ -44,7 +44,7 @@ const extended = gtsApi.injectEndpoints({
}
return {
url: `/api/v1/admin/reports${query}`
url: `/api/v1/admin/reports${query}`,
};
},
// Headers required for paging.
@ -56,15 +56,15 @@ const extended = gtsApi.injectEndpoints({
},
// Only provide LIST tag id since this model is not the
// same as getReport model (due to transformResponse).
providesTags: [{ type: "Report", id: "TRANSFORMED" }]
providesTags: [{ type: "Report", id: "TRANSFORMED" }],
}),
getReport: build.query<AdminReport, string>({
query: (id) => ({
url: `/api/v1/admin/reports/${id}`
url: `/api/v1/admin/reports/${id}`,
}),
providesTags: (_result, _error, id) => [
{ type: 'Report', id }
{ type: 'Report', id },
],
}),
@ -73,14 +73,14 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/admin/reports/${formData.id}/resolve`,
method: "POST",
asForm: true,
body: formData
body: formData,
}),
invalidatesTags: (res) =>
res
? [{ type: "Report", id: "TRANSFORMED" }, { type: "Report", id: res.id }]
: [{ type: "Report", id: "TRANSFORMED" }]
})
})
: [{ type: "Report", id: "TRANSFORMED" }],
}),
}),
});
/**

View file

@ -26,7 +26,7 @@ import type {
import { serialize as serializeForm } from "object-to-formdata";
import type { FetchBaseQueryMeta } from "@reduxjs/toolkit/dist/query/fetchBaseQuery";
import type { RootState } from '../../redux/store';
import { InstanceV1 } from '../types/instance';
import type { InstanceV1 } from '../types/instance';
/**
* GTSFetchArgs extends standard FetchArgs used by
@ -173,10 +173,10 @@ export const gtsApi = createApi({
endpoints: (build) => ({
instanceV1: build.query<InstanceV1, void>({
query: () => ({
url: `/api/v1/instance`
})
})
})
url: `/api/v1/instance`,
}),
}),
}),
});
/**

View file

@ -25,8 +25,8 @@ import {
remove as oauthRemove,
authorize as oauthAuthorize,
} from "../../../redux/oauth";
import { RootState } from '../../../redux/store';
import { Account } from '../../types/account';
import type { RootState } from '../../../redux/store';
import type { Account } from '../../types/account';
export interface OauthTokenRequestBody {
client_id: string;
@ -45,7 +45,7 @@ function getSettingsURL() {
Also drops anything past /settings/, because authorization urls that are too long
get rejected by GTS.
*/
let [pre, _past] = window.location.pathname.split("/settings");
const [pre, _past] = window.location.pathname.split("/settings");
return `${window.location.origin}${pre}/settings`;
}
@ -71,14 +71,14 @@ const extended = gtsApi.injectEndpoints({
// return a standard verify_credentials query.
if (oauthState.loginState != 'callback') {
return fetchWithBQ({
url: `/api/v1/accounts/verify_credentials`
url: `/api/v1/accounts/verify_credentials`,
});
}
// We're in the middle of an auth/callback flow.
// Try to retrieve callback code from URL query.
let urlParams = new URLSearchParams(window.location.search);
let code = urlParams.get("code");
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
if (code == undefined) {
return {
error: {
@ -91,7 +91,7 @@ const extended = gtsApi.injectEndpoints({
// Retrieve app with which the
// callback code was generated.
let app = oauthState.app;
const app = oauthState.app;
if (app == undefined || app.client_id == undefined) {
return {
error: {
@ -109,7 +109,7 @@ const extended = gtsApi.injectEndpoints({
client_secret: app.client_secret,
redirect_uri: SETTINGS_URL,
grant_type: "authorization_code",
code: code
code: code,
};
const tokenResult = await fetchWithBQ({
@ -118,7 +118,7 @@ const extended = gtsApi.injectEndpoints({
body: tokenReqBody,
});
if (tokenResult.error) {
return { error: tokenResult.error as FetchBaseQueryError };
return { error: tokenResult.error };
}
// Remove ?code= query param from
@ -131,9 +131,9 @@ const extended = gtsApi.injectEndpoints({
// We're now authed! So return
// standard verify_credentials query.
return fetchWithBQ({
url: `/api/v1/accounts/verify_credentials`
url: `/api/v1/accounts/verify_credentials`,
});
}
},
}),
authorizeFlow: build.mutation({
@ -147,7 +147,7 @@ const extended = gtsApi.injectEndpoints({
}
instanceUrl = new URL(formData.instance).origin;
if (oauthState?.instanceUrl == instanceUrl && oauthState.app) {
if (oauthState.instanceUrl == instanceUrl && oauthState.app) {
return { data: oauthState.app };
}
@ -159,31 +159,31 @@ const extended = gtsApi.injectEndpoints({
client_name: "GoToSocial Settings",
scopes: formData.scopes,
redirect_uris: SETTINGS_URL,
website: SETTINGS_URL
}
website: SETTINGS_URL,
},
});
if (appResult.error) {
return { error: appResult.error as FetchBaseQueryError };
return { error: appResult.error };
}
let app = appResult.data as any;
const app = appResult.data;
app.scopes = formData.scopes;
api.dispatch(oauthAuthorize({
instanceUrl: instanceUrl,
app: app,
loginState: "callback",
expectingRedirect: true
expectingRedirect: true,
}));
let url = new URL(instanceUrl);
const url = new URL(instanceUrl);
url.pathname = "/oauth/authorize";
url.searchParams.set("client_id", app.client_id);
url.searchParams.set("redirect_uri", SETTINGS_URL);
url.searchParams.set("response_type", "code");
url.searchParams.set("scope", app.scopes);
let redirectURL = url.toString();
const redirectURL = url.toString();
window.location.assign(redirectURL);
return { data: null };
},
@ -193,9 +193,9 @@ const extended = gtsApi.injectEndpoints({
api.dispatch(oauthRemove());
return { data: null };
},
invalidatesTags: ["Auth"]
})
})
invalidatesTags: ["Auth"],
}),
}),
});
export const {

View file

@ -86,13 +86,13 @@ function makeCacheMutation(action: Action): CacheMutation {
key = key(draft, newData);
}
action(draft, newData, { key });
})
}),
);
} catch (e) {
// eslint-disable-next-line no-console
console.error(`rolling back pessimistic update of ${queryName}: ${JSON.stringify(e)}`);
}
}
},
};
};
}

View file

@ -20,15 +20,15 @@
import fileDownload from "js-file-download";
import { gtsApi } from "../gts-api";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { AccountExportStats } from "../../types/account";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { AccountExportStats } from "../../types/account";
const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
exportStats: build.query<AccountExportStats, void>({
query: () => ({
url: `/api/v1/exports/stats`
})
url: `/api/v1/exports/stats`,
}),
}),
exportFollowing: build.mutation<string | null, void>({
@ -38,7 +38,7 @@ const extended = gtsApi.injectEndpoints({
acceptContentType: "text/csv",
});
if (csvRes.error) {
return { error: csvRes.error as FetchBaseQueryError };
return { error: csvRes.error };
}
if (csvRes.meta?.response?.status !== 200) {
@ -47,7 +47,7 @@ const extended = gtsApi.injectEndpoints({
fileDownload(csvRes.data, "following.csv", "text/csv");
return { data: null };
}
},
}),
exportFollowers: build.mutation<string | null, void>({
@ -57,7 +57,7 @@ const extended = gtsApi.injectEndpoints({
acceptContentType: "text/csv",
});
if (csvRes.error) {
return { error: csvRes.error as FetchBaseQueryError };
return { error: csvRes.error };
}
if (csvRes.meta?.response?.status !== 200) {
@ -66,7 +66,7 @@ const extended = gtsApi.injectEndpoints({
fileDownload(csvRes.data, "followers.csv", "text/csv");
return { data: null };
}
},
}),
exportLists: build.mutation<string | null, void>({
@ -76,7 +76,7 @@ const extended = gtsApi.injectEndpoints({
acceptContentType: "text/csv",
});
if (csvRes.error) {
return { error: csvRes.error as FetchBaseQueryError };
return { error: csvRes.error };
}
if (csvRes.meta?.response?.status !== 200) {
@ -85,7 +85,7 @@ const extended = gtsApi.injectEndpoints({
fileDownload(csvRes.data, "lists.csv", "text/csv");
return { data: null };
}
},
}),
exportBlocks: build.mutation<string | null, void>({
@ -95,7 +95,7 @@ const extended = gtsApi.injectEndpoints({
acceptContentType: "text/csv",
});
if (csvRes.error) {
return { error: csvRes.error as FetchBaseQueryError };
return { error: csvRes.error };
}
if (csvRes.meta?.response?.status !== 200) {
@ -104,7 +104,7 @@ const extended = gtsApi.injectEndpoints({
fileDownload(csvRes.data, "blocks.csv", "text/csv");
return { data: null };
}
},
}),
exportMutes: build.mutation<string | null, void>({
@ -114,7 +114,7 @@ const extended = gtsApi.injectEndpoints({
acceptContentType: "text/csv",
});
if (csvRes.error) {
return { error: csvRes.error as FetchBaseQueryError };
return { error: csvRes.error };
}
if (csvRes.meta?.response?.status !== 200) {
@ -123,7 +123,7 @@ const extended = gtsApi.injectEndpoints({
fileDownload(csvRes.data, "mutes.csv", "text/csv");
return { data: null };
}
},
}),
importData: build.mutation({
@ -132,10 +132,10 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/import`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
}),
}),
})
});
export const {

View file

@ -21,11 +21,11 @@ import { replaceCacheOnMutation } from "../query-modifiers";
import { gtsApi } from "../gts-api";
import type {
MoveAccountFormData,
UpdateAliasesFormData
UpdateAliasesFormData,
} from "../../types/migration";
import type { Theme } from "../../types/theme";
import { User } from "../../types/user";
import { DefaultInteractionPolicies, UpdateDefaultInteractionPolicies } from "../../types/interaction";
import type { User } from "../../types/user";
import type { DefaultInteractionPolicies, UpdateDefaultInteractionPolicies } from "../../types/interaction";
const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
@ -35,36 +35,36 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/accounts/update_credentials`,
asForm: true,
body: formData,
discardEmpty: true
discardEmpty: true,
}),
...replaceCacheOnMutation("verifyCredentials")
...replaceCacheOnMutation("verifyCredentials"),
}),
user: build.query<User, void>({
query: () => ({url: `/api/v1/user`})
query: () => ({url: `/api/v1/user`}),
}),
passwordChange: build.mutation({
query: (data) => ({
method: "POST",
url: `/api/v1/user/password_change`,
body: data
})
body: data,
}),
}),
emailChange: build.mutation<User, { password: string, new_email: string }>({
query: (data) => ({
method: "POST",
url: `/api/v1/user/email_change`,
body: data
body: data,
}),
...replaceCacheOnMutation("user")
...replaceCacheOnMutation("user"),
}),
aliasAccount: build.mutation<any, UpdateAliasesFormData>({
async queryFn(formData, _api, _extraOpts, fetchWithBQ) {
// Pull entries out from the hooked form.
const entries: String[] = [];
const entries: string[] = [];
formData.also_known_as_uris.forEach(entry => {
if (entry) {
entries.push(entry);
@ -76,28 +76,28 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/accounts/alias`,
body: { also_known_as_uris: entries },
});
}
},
}),
moveAccount: build.mutation<any, MoveAccountFormData>({
query: (data) => ({
method: "POST",
url: `/api/v1/accounts/move`,
body: data
})
body: data,
}),
}),
accountThemes: build.query<Theme[], void>({
query: () => ({
url: `/api/v1/accounts/themes`
})
url: `/api/v1/accounts/themes`,
}),
}),
defaultInteractionPolicies: build.query<DefaultInteractionPolicies, void>({
query: () => ({
url: `/api/v1/interaction_policies/defaults`
url: `/api/v1/interaction_policies/defaults`,
}),
providesTags: ["DefaultInteractionPolicies"]
providesTags: ["DefaultInteractionPolicies"],
}),
updateDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, UpdateDefaultInteractionPolicies>({
@ -106,7 +106,7 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/interaction_policies/defaults`,
body: data,
}),
...replaceCacheOnMutation("defaultInteractionPolicies")
...replaceCacheOnMutation("defaultInteractionPolicies"),
}),
resetDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, void>({
@ -115,9 +115,9 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/interaction_policies/defaults`,
body: {},
}),
invalidatesTags: ["DefaultInteractionPolicies"]
invalidatesTags: ["DefaultInteractionPolicies"],
}),
}),
})
});
export const {

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {
import type {
InteractionRequest,
SearchInteractionRequestsParams,
SearchInteractionRequestsResp,
@ -33,7 +33,7 @@ const extended = gtsApi.injectEndpoints({
url: `/api/v1/interaction_requests/${id}`,
}),
providesTags: (_result, _error, id) => [
{ type: 'InteractionRequest', id }
{ type: 'InteractionRequest', id },
],
}),
@ -52,7 +52,7 @@ const extended = gtsApi.injectEndpoints({
}
return {
url: `/api/v1/interaction_requests${query}`
url: `/api/v1/interaction_requests${query}`,
};
},
// Headers required for paging.
@ -62,7 +62,7 @@ const extended = gtsApi.injectEndpoints({
const links = parse(linksStr);
return { requests, links };
},
providesTags: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
providesTags: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
}),
approveInteractionRequest: build.mutation<InteractionRequest, string>({
@ -73,7 +73,7 @@ const extended = gtsApi.injectEndpoints({
invalidatesTags: (res) =>
res
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
}),
rejectInteractionRequest: build.mutation<any, string>({
@ -84,9 +84,9 @@ const extended = gtsApi.injectEndpoints({
invalidatesTags: (res) =>
res
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
}),
}),
})
});
export const {

View file

@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Links } from "parse-link-header";
import { CustomEmoji } from "./custom-emoji";
import type { Links } from "parse-link-header";
import type { CustomEmoji } from "./custom-emoji";
export interface AdminAccount {
id: string,

View file

@ -18,7 +18,7 @@
*/
import typia from "typia";
import { PermType } from "./perm";
import type { PermType } from "./perm";
export const validateDomainPerms = typia.createValidate<DomainPerm[]>();

View file

@ -36,7 +36,7 @@ export interface InstanceV1 {
urls: InstanceUrls;
stats: InstanceStats;
thumbnail: string;
contact_account: Object; // TODO: define this.
contact_account: object; // TODO: define this.
max_toot_chars: number;
rules: any[]; // TODO: define this
terms?: string;

View file

@ -17,9 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Links } from "parse-link-header";
import { Account } from "./account";
import { Status } from "./status";
import type { Links } from "parse-link-header";
import type { Account } from "./account";
import type { Status } from "./status";
export interface DefaultInteractionPolicies {
direct: InteractionPolicy;

View file

@ -17,7 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Draft } from "@reduxjs/toolkit";
import type { Draft } from "@reduxjs/toolkit";
/**
* Pass into a query when you don't

View file

@ -17,9 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Links } from "parse-link-header";
import { AdminAccount } from "./account";
import { Status } from "./status";
import type { Links } from "parse-link-header";
import type { AdminAccount } from "./account";
import type { Status } from "./status";
/**
* Admin model of a report. Differs from the client
@ -83,7 +83,7 @@ export interface AdminReport {
* Rules broken according to the reporter, if any.
* TODO: model this properly.
*/
rules: Object[];
rules: object[];
/**
* Comment stored about what action (if any) was taken.
*/

View file

@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Account } from "./account";
import { CustomEmoji } from "./custom-emoji";
import type { Account } from "./account";
import type { CustomEmoji } from "./custom-emoji";
export interface Status {
id: string;

View file

@ -29,7 +29,7 @@ import { get } from "psl";
export function isValidDomainPermission(domain: string): boolean {
return isValidDomain(domain, {
wildcard: false,
allowUnicode: true
allowUnicode: true,
});
}

View file

@ -19,7 +19,7 @@
import { useMemo } from "react";
import { AdminAccount } from "../types/account";
import type { AdminAccount } from "../types/account";
import { store } from "../../redux/store";
export function yesOrNo(b: boolean): string {

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import type { PayloadAction} from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";
import type { Checkable } from "../lib/form/types";
import { useReducer } from "react";
@ -57,12 +58,12 @@ function initialHookState({
}
return [ key, { ...entry, key, checked } ];
})
}),
);
return {
entries: mappedEntries,
selectedEntries
selectedEntries,
};
}
@ -81,7 +82,7 @@ const checklistSlice = createSlice({
}
return [entry.key, { ...entry, checked } ];
})
}),
);
return { entries, selectedEntries };
@ -97,7 +98,7 @@ const checklistSlice = createSlice({
state.entries[key] = {
...state.entries[key],
...value
...value,
};
},
updateMultiple: (state, { payload }: PayloadAction<Array<[key: string, value: Partial<Checkable>]>>) => {
@ -112,11 +113,11 @@ const checklistSlice = createSlice({
state.entries[key] = {
...state.entries[key],
...value
...value,
};
});
}
}
},
},
});
export const actions = checklistSlice.actions;
@ -153,6 +154,6 @@ export const useChecklistReducer = (entries: Checkable[], uniqueKey: string, ini
return useReducer(
checklistSlice.reducer,
initialState,
(_) => initialHookState({ entries, uniqueKey, initialValue })
(_) => initialHookState({ entries, uniqueKey, initialValue }),
);
};

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import type { PayloadAction} from "@reduxjs/toolkit";
import { createSlice } from "@reduxjs/toolkit";
/**
* OAuthToken represents a response
@ -78,8 +79,8 @@ export const oauthSlice = createSlice({
delete state.token;
delete state.app;
state.loginState = "logout";
}
}
},
},
});
export const {

View file

@ -50,13 +50,13 @@ const persistedReducer = persistReducer({
// This is a cheeky workaround for
// redux-persist being a stickler.
let anyState = state as any;
const anyState = state as any;
if (anyState?.oauth != undefined) {
anyState.oauth.expectingRedirect = false;
}
return anyState;
}
},
}, combinedReducers);
export const store = configureStore({
@ -71,10 +71,10 @@ export const store = configureStore({
PERSIST,
PURGE,
REGISTER,
]
}
],
},
}).concat(gtsApi.middleware);
}
},
});
export const persistor = persistStore(store);

View file

@ -30,7 +30,7 @@ export default function Test({}) {
const form = {
email: useTextInput("email", { defaultValue: instance?.email }),
message: useTextInput("message")
message: useTextInput("message"),
};
const [submit, result] = useFormSubmit(form, useSendTestEmailMutation(), { changedOnly: false });

View file

@ -47,7 +47,7 @@ export default function ExpireRemote({}) {
}
return "invalid domain";
}
},
});
const [expire, expireResult] = useInstanceKeysExpireMutation();

View file

@ -22,7 +22,7 @@ import { useTextInput } from "../../../../lib/form";
import { useLazyApURLQuery } from "../../../../lib/query/admin/debug";
import { TextInput } from "../../../../components/form/inputs";
import MutationButton from "../../../../components/form/mutation-button";
import { ApURLResponse } from "../../../../lib/types/debug";
import type { ApURLResponse } from "../../../../lib/types/debug";
import Loading from "../../../../components/loading";
// Used for syntax highlighting of json result.

View file

@ -17,12 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useMemo, useEffect, PropsWithChildren, ReactElement } from "react";
import type { PropsWithChildren, ReactElement } from "react";
import React, { useMemo, useEffect } from "react";
import { matchSorter } from "match-sorter";
import ComboBox from "../../../components/combo-box";
import { useListEmojiQuery } from "../../../lib/query/admin/custom-emoji";
import { CustomEmoji } from "../../../lib/types/custom-emoji";
import { ComboboxFormInputHook } from "../../../lib/form/types";
import type { CustomEmoji } from "../../../lib/types/custom-emoji";
import type { ComboboxFormInputHook } from "../../../lib/form/types";
import Loading from "../../../components/loading";
import { Error } from "../../../components/error";
@ -97,7 +98,7 @@ export function CategorySelect({ field, children }: PropsWithChildren<CategorySe
aria-hidden="true"
/>
{categoryName}
</>
</>,
]);
});

View file

@ -47,7 +47,7 @@ export default function EmojiDetail() {
function EmojiDetailForm({ data: emoji }) {
const { data: instance } = useInstanceV1Query();
const emojiMaxSize = useMemo(() => {
return instance?.configuration?.emojis?.emoji_size_limit ?? 50 * 1024;
return instance?.configuration.emojis.emoji_size_limit ?? 50 * 1024;
}, [instance]);
const baseUrl = useBaseUrl();
@ -56,8 +56,8 @@ function EmojiDetailForm({ data: emoji }) {
category: useComboBoxInput("category", { source: emoji }),
image: useFileInput("image", {
withPreview: true,
maxSize: emojiMaxSize
})
maxSize: emojiMaxSize,
}),
};
const [modifyEmoji, result] = useFormSubmit(form, useEditEmojiMutation());

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useMemo, useEffect, ReactNode } from "react";
import type { ReactNode } from "react";
import React, { useMemo, useEffect } from "react";
import { useFileInput, useComboBoxInput } from "../../../../lib/form";
import useShortcode from "./use-shortcode";
import useFormSubmit from "../../../../lib/form/submit";
@ -32,7 +33,7 @@ import prettierBytes from "prettier-bytes";
export default function NewEmojiForm() {
const { data: instance } = useInstanceV1Query();
const emojiMaxSize = useMemo(() => {
return instance?.configuration?.emojis?.emoji_size_limit ?? 50 * 1024;
return instance?.configuration.emojis.emoji_size_limit ?? 50 * 1024;
}, [instance]);
const prettierMaxSize = useMemo(() => {
@ -43,7 +44,7 @@ export default function NewEmojiForm() {
shortcode: useShortcode(),
image: useFileInput("image", {
withPreview: true,
maxSize: emojiMaxSize
maxSize: emojiMaxSize,
}),
category: useComboBoxInput("category"),
};
@ -59,7 +60,7 @@ export default function NewEmojiForm() {
form.shortcode.reset();
form.image.reset();
form.category.reset();
}
},
},
);
@ -70,7 +71,7 @@ export default function NewEmojiForm() {
(form.shortcode.value === undefined || form.shortcode.value.length === 0) &&
form.image.value !== undefined
) {
let [name, _ext] = form.image.value.name.split(".");
const [name, _ext] = form.image.value.name.split(".");
form.shortcode.setter(name);
}

View file

@ -27,7 +27,7 @@ import Loading from "../../../../components/loading";
import { Error } from "../../../../components/error";
import { TextInput } from "../../../../components/form/inputs";
import { useListEmojiQuery } from "../../../../lib/query/admin/custom-emoji";
import { CustomEmoji } from "../../../../lib/types/custom-emoji";
import type { CustomEmoji } from "../../../../lib/types/custom-emoji";
export default function EmojiOverview() {
const { data: emoji = [], isLoading, isError, error } = useListEmojiQuery({ filter: "domain:local" });
@ -87,7 +87,7 @@ function EmojiList({ emoji }: EmojiListParams) {
// Filter from emojis in this category.
emojiByCategory.forEach((entries, category) => {
const filteredEntries = matchSorter(entries, filter, {
keys: ["shortcode"]
keys: ["shortcode"],
});
if (filteredEntries.length == 0) {
@ -164,8 +164,12 @@ function EmojiPreview({ emoji }) {
return (
<img
onMouseEnter={() => { setAnimate(true); }}
onMouseLeave={() => { setAnimate(false); }}
onMouseEnter={() => {
setAnimate(true);
}}
onMouseLeave={() => {
setAnimate(false);
}}
src={animate ? emoji.url : emoji.static_url}
alt={emoji.shortcode}
title={emoji.shortcode}

View file

@ -26,7 +26,7 @@ const shortcodeRegex = /^\w{2,30}$/;
export default function useShortcode() {
const { data: emoji = [] } = useListEmojiQuery({
filter: "domain:local"
filter: "domain:local",
});
const emojiCodes = useMemo(() => {
@ -36,7 +36,9 @@ export default function useShortcode() {
return useTextInput("shortcode", {
validator: function validateShortcode(code) {
// technically invalid, but hacky fix to prevent validation error on page load
if (code == "") { return ""; }
if (code == "") {
return "";
}
if (emojiCodes.has(code)) {
return "Shortcode already in use";
@ -51,6 +53,6 @@ export default function useShortcode() {
}
return "";
}
},
});
}

View file

@ -31,7 +31,7 @@ export default function RemoteEmoji() {
const {
data: emoji = [],
isLoading,
error
error,
} = useListEmojiQuery({ filter: "domain:local" });
const emojiCodes = useMemo(() => new Set(emoji.map((e) => e.shortcode)), [emoji]);

View file

@ -64,7 +64,7 @@ export default function StealThisLook({ emojiCodes }) {
"fa fa-fw",
(result.isLoading
? "fa-refresh fa-spin"
: "fa-search")
: "fa-search"),
].join(" ")} aria-hidden="true" title="Search" />
<span className="sr-only">Search</span>
</button>
@ -108,9 +108,9 @@ function CopyEmojiForm({ localEmojiCodes, type, emojiList }) {
const form = {
selectedEmoji: useCheckListInput("selectedEmoji", {
entries: emojiList,
uniqueKey: "id"
uniqueKey: "id",
}),
category: useComboBoxInput("category")
category: useComboBoxInput("category"),
};
const [formSubmit, result] = useFormSubmit(
@ -126,18 +126,18 @@ function CopyEmojiForm({ localEmojiCodes, type, emojiList }) {
});
form.selectedEmoji.updateMultiple(processed);
}
}
}
},
},
);
const buttonsInactive = form.selectedEmoji.someSelected
? {
disabled: false,
title: ""
title: "",
}
: {
disabled: true,
title: "No emoji selected, cannot perform any actions"
title: "No emoji selected, cannot perform any actions",
};
const checkListExtraProps = useCallback(() => ({ localEmojiCodes }), [localEmojiCodes]);
@ -205,7 +205,7 @@ function EmojiEntry({ entry: emoji, onChange, extraProps: { localEmojiCodes } })
return (emoji.checked && localEmojiCodes.has(code))
? "Shortcode already in use"
: "";
}
},
});
useEffect(() => {

View file

@ -23,7 +23,7 @@ import { useTextInput } from "../../../lib/form";
import useFormSubmit from "../../../lib/form/submit";
import { TextInput } from "../../../components/form/inputs";
import MutationButton from "../../../components/form/mutation-button";
import { PermType } from "../../../lib/types/perm";
import type { PermType } from "../../../lib/types/perm";
import { RE2JS } from "re2js";
export default function HeaderPermCreateForm({ permType }: { permType: PermType }) {
@ -44,7 +44,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
}
return "";
}
},
}),
regex: useTextInput("regex", {
validator: (val: string) => {
@ -63,7 +63,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
}
return "";
}
},
}),
};

View file

@ -19,11 +19,11 @@
import React, { useEffect, useMemo } from "react";
import { useLocation, useParams } from "wouter";
import { PermType } from "../../../lib/types/perm";
import type { PermType } from "../../../lib/types/perm";
import { useDeleteHeaderAllowMutation, useDeleteHeaderBlockMutation, useGetHeaderAllowQuery, useGetHeaderBlockQuery } from "../../../lib/query/admin/http-header-permissions";
import { HeaderPermission } from "../../../lib/types/http-header-permissions";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { SerializedError } from "@reduxjs/toolkit";
import type { HeaderPermission } from "../../../lib/types/http-header-permissions";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { SerializedError } from "@reduxjs/toolkit";
import Loading from "../../../components/loading";
import { Error } from "../../../components/error";
import { useLazyGetAccountQuery } from "../../../lib/query/admin";
@ -42,7 +42,7 @@ Some Test Value
Another Test Value`;
export default function HeaderPermDetail() {
let params = useParams();
const params = useParams();
if (params.permType !== "blocks" && params.permType !== "allows") {
throw "unrecognized perm type " + params.permType;
}
@ -50,7 +50,7 @@ export default function HeaderPermDetail() {
return params.permType?.slice(0, -1) as PermType;
}, [params]);
let permID = params.permId as string | undefined;
const permID = params.permId;
if (!permID) {
throw "no perm ID";
}
@ -127,7 +127,7 @@ function PermDeets({
return <Loading />;
} else if (isErrorAccount || account === undefined) {
// Fall back to account ID.
return perm?.created_by;
return perm.created_by;
}
return (

View file

@ -21,18 +21,18 @@ import React, { useMemo } from "react";
import { useGetHeaderAllowsQuery, useGetHeaderBlocksQuery } from "../../../lib/query/admin/http-header-permissions";
import { NoArg } from "../../../lib/types/query";
import { PageableList } from "../../../components/pageable-list";
import { HeaderPermission } from "../../../lib/types/http-header-permissions";
import type { HeaderPermission } from "../../../lib/types/http-header-permissions";
import { useLocation, useParams } from "wouter";
import { PermType } from "../../../lib/types/perm";
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { SerializedError } from "@reduxjs/toolkit";
import type { PermType } from "../../../lib/types/perm";
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
import type { SerializedError } from "@reduxjs/toolkit";
import HeaderPermCreateForm from "./create";
export default function HeaderPermsOverview() {
const [ location, setLocation ] = useLocation();
// Parse perm type from routing params.
let params = useParams();
const params = useParams();
if (params.permType !== "blocks" && params.permType !== "allows") {
throw "unrecognized perm type " + params.permType;
}
@ -53,7 +53,7 @@ export default function HeaderPermsOverview() {
isFetching: isFetchingBlocks,
isSuccess: isSuccessBlocks,
isError: isErrorBlocks,
error: errorBlocks
error: errorBlocks,
} = useGetHeaderBlocksQuery(NoArg, { skip: permType !== "block" });
const {
@ -62,7 +62,7 @@ export default function HeaderPermsOverview() {
isFetching: isFetchingAllows,
isSuccess: isSuccessAllows,
isError: isErrorAllows,
error: errorAllows
error: errorAllows,
} = useGetHeaderAllowsQuery(NoArg, { skip: permType !== "allow" });
const itemToEntry = (perm: HeaderPermission) => {
@ -77,7 +77,7 @@ export default function HeaderPermsOverview() {
// Store the back location in
// history so the detail view
// can use it to return here.
state: { backLocation: location }
state: { backLocation: location },
});
}}
role="link"

View file

@ -56,7 +56,7 @@ function EditInstanceRuleForm({ rule }) {
const baseUrl = useBaseUrl();
const form = {
id: useValue("id", rule.id),
rule: useTextInput("text", { defaultValue: rule.text })
rule: useTextInput("text", { defaultValue: rule.text }),
};
const [submitForm, result] = useFormSubmit(form, useUpdateInstanceRuleMutation());

View file

@ -25,7 +25,7 @@ import { useTextInput } from "../../../lib/form";
import useFormSubmit from "../../../lib/form/submit";
import { TextArea } from "../../../components/form/inputs";
import MutationButton from "../../../components/form/mutation-button";
import { InstanceRule, MappedRules } from "../../../lib/types/rules";
import type { InstanceRule, MappedRules } from "../../../lib/types/rules";
import FormWithData from "../../../lib/form/form-with-data";
export default function InstanceRules() {
@ -46,7 +46,9 @@ function InstanceRulesForm({ data: rules }: { data: MappedRules }) {
const [submitForm, result] = useFormSubmit({ newRule }, useAddInstanceRuleMutation(), {
changedOnly: true,
onFinish: () => newRule.reset()
onFinish: () => {
newRule.reset();
},
});
return (

View file

@ -24,7 +24,7 @@ import { TextInput, TextArea, FileInput } from "../../../components/form/inputs"
import MutationButton from "../../../components/form/mutation-button";
import { useInstanceV1Query } from "../../../lib/query/gts-api";
import { useUpdateInstanceMutation } from "../../../lib/query/admin";
import { InstanceV1 } from "../../../lib/types/instance";
import type { InstanceV1 } from "../../../lib/types/instance";
import FormWithData from "../../../lib/form/form-with-data";
import useFormSubmit from "../../../lib/form/submit";
@ -50,7 +50,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
const form = {
title: useTextInput("title", {
source: instance,
validator: (val: string) => val.length <= titleLimit ? "" : `Instance title is ${val.length} characters; must be ${titleLimit} characters or less`
validator: (val: string) => val.length <= titleLimit ? "" : `Instance title is ${val.length} characters; must be ${titleLimit} characters or less`,
}),
thumbnail: useFileInput("thumbnail", { withPreview: true }),
thumbnailDesc: useTextInput("thumbnail_description", { source: instance }),
@ -58,22 +58,22 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
source: instance,
// Select "raw" text version of parsed field for editing.
valueSelector: (s: InstanceV1) => s.short_description_text,
validator: (val: string) => val.length <= shortDescLimit ? "" : `Instance short description is ${val.length} characters; must be ${shortDescLimit} characters or less`
validator: (val: string) => val.length <= shortDescLimit ? "" : `Instance short description is ${val.length} characters; must be ${shortDescLimit} characters or less`,
}),
description: useTextInput("description", {
source: instance,
// Select "raw" text version of parsed field for editing.
valueSelector: (s: InstanceV1) => s.description_text,
validator: (val: string) => val.length <= descLimit ? "" : `Instance description is ${val.length} characters; must be ${descLimit} characters or less`
validator: (val: string) => val.length <= descLimit ? "" : `Instance description is ${val.length} characters; must be ${descLimit} characters or less`,
}),
terms: useTextInput("terms", {
source: instance,
// Select "raw" text version of parsed field for editing.
valueSelector: (s: InstanceV1) => s.terms_text,
validator: (val: string) => val.length <= termsLimit ? "" : `Instance terms and conditions is ${val.length} characters; must be ${termsLimit} characters or less`
validator: (val: string) => val.length <= termsLimit ? "" : `Instance terms and conditions is ${val.length} characters; must be ${termsLimit} characters or less`,
}),
contactUser: useTextInput("contact_username", { source: instance, valueSelector: (s) => s.contact_account?.username }),
contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email })
contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email }),
};
const [submitForm, result] = useFormSubmit(form, useUpdateInstanceMutation());
@ -109,8 +109,8 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
<div className="file-upload-with-preview">
<img
className="preview avatar"
src={form.thumbnail.previewValue ?? instance?.thumbnail}
alt={form.thumbnailDesc.value ?? (instance?.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")}
src={form.thumbnail.previewValue ?? instance.thumbnail}
alt={form.thumbnailDesc.value ?? (instance.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")}
/>
<div className="file-input-with-image-description">
<FileInput

View file

@ -28,7 +28,7 @@ import {
useBoolInput,
} from "../../../../lib/form";
import { Checkbox, Select, TextInput } from "../../../../components/form/inputs";
import { AdminAccount } from "../../../../lib/types/account";
import type { AdminAccount } from "../../../../lib/types/account";
import { useLocation } from "wouter";
export interface AccountActionsProps {
@ -65,7 +65,7 @@ export function AccountActions({ account, backLocation }: AccountActionsProps) {
function ModerateAccount({ account }: { account: AdminAccount }) {
const form = {
id: useValue("id", account.id),
reason: useTextInput("text")
reason: useTextInput("text"),
};
const reallySuspend = useBoolInput("reallySuspend");
@ -96,7 +96,7 @@ function ModerateAccount({ account }: { account: AdminAccount }) {
/>
<div className="action-buttons">
<MutationButton
disabled={account.suspended || reallySuspend.value === undefined || reallySuspend.value === false}
disabled={account.suspended || reallySuspend.value === undefined || !reallySuspend.value}
label="Suspend"
name="suspend"
result={result}
@ -140,7 +140,7 @@ function HandleSignup({ account, backLocation }: { account: AdminAccount, backLo
// redirect to accounts page.
setLocation(backLocation);
}
}
},
});
return (

View file

@ -22,7 +22,7 @@ import React from "react";
import { useGetAccountQuery } from "../../../../lib/query/admin";
import FormWithData from "../../../../lib/form/form-with-data";
import FakeProfile from "../../../../components/profile";
import { AdminAccount } from "../../../../lib/types/account";
import type { AdminAccount } from "../../../../lib/types/account";
import { AccountActions } from "./actions";
import { useParams } from "wouter";
import { useBaseUrl } from "../../../../lib/navigation/util";
@ -32,7 +32,7 @@ import { UseOurInstanceAccount, yesOrNo } from "../../../../lib/util";
export default function AccountDetail() {
const params: { accountID: string } = useParams();
const baseUrl = useBaseUrl();
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
return (
<div className="account-detail">

View file

@ -17,12 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { ReactNode } from "react";
import type { ReactNode } from "react";
import React from "react";
import { useSearchAccountsQuery } from "../../../../lib/query/admin";
import { PageableList } from "../../../../components/pageable-list";
import { useLocation } from "wouter";
import Username from "../../../../components/username";
import { AdminAccount } from "../../../../lib/types/account";
import type { AdminAccount } from "../../../../lib/types/account";
export default function AccountsPending() {
const [ location, _setLocation ] = useLocation();

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { ReactNode, useEffect, useMemo } from "react";
import type { ReactNode} from "react";
import React, { useEffect, useMemo } from "react";
import { useLazySearchAccountsQuery } from "../../../../lib/query/admin";
import { useTextInput } from "../../../../lib/form";
@ -25,7 +26,7 @@ import { PageableList } from "../../../../components/pageable-list";
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 type { AdminAccount } from "../../../../lib/types/account";
import Username from "../../../../components/username";
import isValidDomain from "is-valid-domain";
@ -66,11 +67,11 @@ export function AccountSearchForm() {
}
return "invalid domain";
}
},
}),
email: useTextInput("email", { defaultValue: urlQueryParams.get("email") ?? ""}),
ip: useTextInput("ip", { defaultValue: urlQueryParams.get("ip") ?? ""}),
limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "50"})
limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "50"}),
};
// On mount, if urlQueryParams were provided,

View file

@ -17,9 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { useMemo } from "react";
import { useMemo } from "react";
import { useLocation, useParams, useSearch } from "wouter";
import { useTextInput, useBoolInput } from "../../../lib/form";
@ -34,18 +33,18 @@ import MutationButton from "../../../components/form/mutation-button";
import { useDomainAllowsQuery, useDomainBlocksQuery } from "../../../lib/query/admin/domain-permissions/get";
import { useAddDomainAllowMutation, useAddDomainBlockMutation, useRemoveDomainAllowMutation, useRemoveDomainBlockMutation } from "../../../lib/query/admin/domain-permissions/update";
import { DomainPerm } from "../../../lib/types/domain-permission";
import type { DomainPerm } from "../../../lib/types/domain-permission";
import { NoArg } from "../../../lib/types/query";
import { Error } from "../../../components/error";
import { useBaseUrl } from "../../../lib/navigation/util";
import { PermType } from "../../../lib/types/perm";
import type { PermType } from "../../../lib/types/perm";
import isValidDomain from "is-valid-domain";
export default function DomainPermDetail() {
const baseUrl = useBaseUrl();
// Parse perm type from routing params.
let params = useParams();
const params = useParams();
if (params.permType !== "blocks" && params.permType !== "allows") {
throw "unrecognized perm type " + params.permType;
}
@ -132,7 +131,7 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps)
const disabledForm = isExistingPerm
? {
disabled: true,
title: "Domain permissions currently cannot be edited."
title: "Domain permissions currently cannot be edited.",
}
: {
disabled: false,
@ -164,11 +163,11 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps)
}
return "invalid domain";
}
},
}),
obfuscate: useBoolInput("obfuscate", { source: perm }),
commentPrivate: useTextInput("private_comment", { source: perm }),
commentPublic: useTextInput("public_comment", { source: perm })
commentPublic: useTextInput("public_comment", { source: perm }),
};
// Check which perm type we're meant to be handling
@ -221,11 +220,11 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps)
// but if domain input changes, that doesn't match anymore
// and causes issues later on so, before submitting the form,
// silently change url, and THEN submit.
let correctUrl = `/${permType}s/${form.domain.value}`;
const correctUrl = `/${permType}s/${form.domain.value}`;
if (location != correctUrl) {
setLocation(correctUrl);
}
return submitForm(e);
submitForm(e);
}
return (

View file

@ -17,9 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { useEffect } from "react";
import { useEffect } from "react";
import { useExportDomainListMutation } from "../../../lib/query/admin/domain-permissions/export";
import useFormSubmit from "../../../lib/form/submit";
import {
@ -96,7 +95,9 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp
<MutationButton
label="Import"
type="button"
onClick={() => submitParse()}
onClick={() => {
submitParse();
}}
result={parseResult}
showError={false}
disabled={form.permType.value === undefined || form.permType.value.length === 0}
@ -116,7 +117,9 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp
<MutationButton
label="Export"
type="button"
onClick={() => submitExport("export")}
onClick={() => {
submitExport("export");
}}
result={exportResult} showError={false}
disabled={form.permType.value === undefined || form.permType.value.length === 0}
/>
@ -124,7 +127,9 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp
label="Export to file"
wrapperClassName="export-file-button"
type="button"
onClick={() => submitExport("export-file")}
onClick={() => {
submitExport("export-file");
}}
result={exportResult}
showError={false}
disabled={form.permType.value === undefined || form.permType.value.length === 0}

View file

@ -37,8 +37,8 @@ export default function ImportExport() {
options: {
block: "Domain blocks",
allow: "Domain allows",
}
})
},
}),
};
const [submitParse, parseResult] = useFormSubmit(form, useProcessDomainPermissionsMutation(), { changedOnly: false });

View file

@ -17,9 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import React, { useMemo } from "react";
import { useMemo } from "react";
import { Link, useLocation, useParams } from "wouter";
import { matchSorter } from "match-sorter";
import { useTextInput } from "../../../lib/form";
@ -28,14 +27,14 @@ import Loading from "../../../components/loading";
import { useDomainAllowsQuery, useDomainBlocksQuery } from "../../../lib/query/admin/domain-permissions/get";
import type { MappedDomainPerms } from "../../../lib/types/domain-permission";
import { NoArg } from "../../../lib/types/query";
import { PermType } from "../../../lib/types/perm";
import type { PermType } from "../../../lib/types/perm";
import { useBaseUrl } from "../../../lib/navigation/util";
export default function DomainPermissionsOverview() {
const baseUrl = useBaseUrl();
// Parse perm type from routing params.
let params = useParams();
const params = useParams();
if (params.permType !== "blocks" && params.permType !== "allows") {
throw "unrecognized perm type " + params.permType;
}

View file

@ -17,8 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { memo, useMemo, useCallback, useEffect } from "react";
import React, { memo, useMemo, useCallback, useEffect } from "react";
import { isValidDomainPermission, hasBetterScope } from "../../../lib/util/domain-permission";
import {
@ -45,7 +44,7 @@ import FormWithData from "../../../lib/form/form-with-data";
import { useImportDomainPermsMutation } from "../../../lib/query/admin/domain-permissions/import";
import {
useDomainAllowsQuery,
useDomainBlocksQuery
useDomainBlocksQuery,
} from "../../../lib/query/admin/domain-permissions/get";
import type { DomainPerm, MappedDomainPerms } from "../../../lib/types/domain-permission";
@ -68,7 +67,7 @@ export const ProcessImport = memo(
{...{ list, permType }}
/>
);
}
},
);
export interface ImportListProps {
@ -111,22 +110,22 @@ function ImportList({ list, data: domainPerms, permType }: ImportListProps) {
domains: useCheckListInput("domains", { entries: list }), // DomainPerm is actually also a Checkable.
obfuscate: useBoolInput("obfuscate"),
privateComment: useTextInput("private_comment", {
defaultValue: `Imported on ${new Date().toLocaleString()}`
defaultValue: `Imported on ${new Date().toLocaleString()}`,
}),
privateCommentBehavior: useRadioInput("private_comment_behavior", {
defaultValue: "append",
options: {
append: "Append to",
replace: "Replace"
}
replace: "Replace",
},
}),
publicComment: useTextInput("public_comment"),
publicCommentBehavior: useRadioInput("public_comment_behavior", {
defaultValue: "append",
options: {
append: "Append to",
replace: "Replace"
}
replace: "Replace",
},
}),
permType: permType,
};
@ -218,7 +217,7 @@ function DomainCheckList({ field, domainPerms, commentType, permType }: DomainCh
return (
<>
<CheckList
field={field as ChecklistInputHook}
field={field}
header={<>
<b>Domain</b>
<b>
@ -252,7 +251,7 @@ const UpdateHint = memo(
function changeAll() {
updateMultiple(
entries.map((entry) => [entry.key, { domain: entry.suggest, suggest: null }])
entries.map((entry) => [entry.key, { domain: entry.suggest, suggest: null }]),
);
}
@ -270,7 +269,7 @@ const UpdateHint = memo(
{entries.length > 0 && <a onClick={changeAll}>change all</a>}
</div>
);
}
},
);
interface UpdateableEntryProps {
@ -290,7 +289,7 @@ const UpdateableEntry = memo(
}>change</a>
</>
);
}
},
);
function domainValidationError(isValid) {
@ -312,7 +311,7 @@ function DomainEntry({ entry, onChange, extraProps: { alreadyExists, comment, pe
defaultValue: entry.domain,
showValidation: entry.checked,
initValidation: domainValidationError(entry.valid),
validator: (value) => domainValidationError(isValidDomainPermission(value))
validator: (value) => domainValidationError(isValidDomainPermission(value)),
});
useEffect(() => {

View file

@ -28,14 +28,14 @@ import MutationButton from "../../../components/form/mutation-button";
import Username from "../../../components/username";
import { useGetReportQuery, useResolveReportMutation } from "../../../lib/query/admin/reports";
import { useBaseUrl } from "../../../lib/navigation/util";
import { AdminReport } from "../../../lib/types/report";
import type { AdminReport } from "../../../lib/types/report";
import { yesOrNo } from "../../../lib/util";
import { Status } from "../../../components/status";
export default function ReportDetail({ }) {
const params: { reportId: string } = useParams();
const baseUrl = useBaseUrl();
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
return (
<div className="report-detail">
@ -200,7 +200,7 @@ function ReportHistory({ report, baseUrl, location }: ReportSectionProps) {
function ReportActionForm({ report }) {
const form = {
id: useValue("id", report.id),
comment: useTextInput("action_taken_comment")
comment: useTextInput("action_taken_comment"),
};
const [submit, result] = useFormSubmit(form, useResolveReportMutation(), { changedOnly: false });

View file

@ -17,7 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { ReactNode, useEffect, useMemo } from "react";
import type { ReactNode} from "react";
import React, { useEffect, useMemo } from "react";
import { useLazySearchReportsQuery } from "../../../lib/query/admin/reports";
import { useTextInput } from "../../../lib/form";
@ -26,7 +27,7 @@ import { Select } from "../../../components/form/inputs";
import MutationButton from "../../../components/form/mutation-button";
import { useLocation, useSearch } from "wouter";
import Username from "../../../components/username";
import { AdminReport } from "../../../lib/types/report";
import type { AdminReport } from "../../../lib/types/report";
export default function ReportsSearch() {
return (
@ -61,7 +62,7 @@ function ReportSearchForm() {
resolved: useTextInput("resolved", { defaultValue: resolved }),
account_id: useTextInput("account_id", { defaultValue: urlQueryParams.get("account_id") ?? "" }),
target_account_id: useTextInput("target_account_id", { defaultValue: urlQueryParams.get("target_account_id") ?? "" }),
limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "20" })
limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "20" }),
};
const setResolved = form.resolved.setter;
@ -196,7 +197,7 @@ function ReportListEntry({ report, linkTo, backLocation }: ReportEntryProps) {
// Store the back location in history so
// the detail view can use it to return to
// this page (including query parameters).
state: { backLocation: backLocation }
state: { backLocation: backLocation },
});
}}
role="link"

View file

@ -24,7 +24,7 @@ import { TextInput } from "../../components/form/inputs";
import MutationButton from "../../components/form/mutation-button";
import { useEmailChangeMutation, usePasswordChangeMutation, useUserQuery } from "../../lib/query/user";
import Loading from "../../components/loading";
import { User } from "../../lib/types/user";
import type { User } from "../../lib/types/user";
import { useInstanceV1Query } from "../../lib/query/gts-api";
export default function EmailPassword() {
@ -42,7 +42,7 @@ function PasswordChange() {
const {
data: instance,
isFetching: isFetchingInstance,
isLoading: isLoadingInstance
isLoading: isLoadingInstance,
} = useInstanceV1Query();
if (isFetchingInstance || isLoadingInstance) {
return <Loading />;
@ -64,8 +64,8 @@ function PasswordChangeForm({ oidcEnabled }: { oidcEnabled?: boolean }) {
return "New password same as old password";
}
return "";
}
})
},
}),
};
const verifyNewPassword = useTextInput("verifyNewPassword", {
@ -74,7 +74,7 @@ function PasswordChangeForm({ oidcEnabled }: { oidcEnabled?: boolean }) {
return "Passwords do not match";
}
return "";
}
},
});
const [submitForm, result] = useFormSubmit(form, usePasswordChangeMutation());
@ -138,14 +138,14 @@ function EmailChange() {
const {
data: instance,
isFetching: isFetchingInstance,
isLoading: isLoadingInstance
isLoading: isLoadingInstance,
} = useInstanceV1Query();
// Load user data.
const {
data: user,
isFetching: isFetchingUser,
isLoading: isLoadingUser
isLoading: isLoadingUser,
} = useUserQuery();
if (
@ -170,7 +170,7 @@ function EmailChangeForm({user, oidcEnabled}: { user: User, oidcEnabled?: boolea
const form = {
currentEmail: useTextInput("current_email", {
defaultValue: user.email,
nosubmit: true
nosubmit: true,
}),
newEmail: useTextInput("new_email", {
validator: (value: string | undefined) => {

View file

@ -28,7 +28,7 @@ import {
import MutationButton from "../../../components/form/mutation-button";
import useFormSubmit from "../../../lib/form/submit";
import { useValue } from "../../../lib/form";
import { AccountExportStats } from "../../../lib/types/account";
import type { AccountExportStats } from "../../../lib/types/account";
export default function Export({ exportStats }: { exportStats: AccountExportStats }) {
const [exportFollowing, exportFollowingResult] = useFormSubmit(
@ -105,7 +105,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
className="text-cutoff"
label="Download following.csv"
type="button"
onClick={() => exportFollowing()}
onClick={() => {
exportFollowing();
}}
result={exportFollowingResult}
showError={true}
disabled={exportStats.following_count === 0}
@ -119,7 +121,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
className="text-cutoff"
label="Download followers.csv"
type="button"
onClick={() => exportFollowers()}
onClick={() => {
exportFollowers();
}}
result={exportFollowersResult}
showError={true}
disabled={exportStats.followers_count === 0}
@ -133,7 +137,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
className="text-cutoff"
label="Download lists.csv"
type="button"
onClick={() => exportLists()}
onClick={() => {
exportLists();
}}
result={exportListsResult}
showError={true}
disabled={exportStats.lists_count === 0}
@ -147,7 +153,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
className="text-cutoff"
label="Download blocks.csv"
type="button"
onClick={() => exportBlocks()}
onClick={() => {
exportBlocks();
}}
result={exportBlocksResult}
showError={true}
disabled={exportStats.blocks_count === 0}
@ -161,7 +169,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
className="text-cutoff"
label="Download mutes.csv"
type="button"
onClick={() => exportMutes()}
onClick={() => {
exportMutes();
}}
result={exportMutesResult}
showError={true}
disabled={exportStats.mutes_count === 0}

View file

@ -28,7 +28,7 @@ export default function Import() {
const form = {
data: useFileInput("data"),
type: useTextInput("type", { defaultValue: "" }),
mode: useTextInput("mode", { defaultValue: "" })
mode: useTextInput("mode", { defaultValue: "" }),
};
const [submitForm, result] = useFormSubmit(form, useImportDataMutation(), {
@ -37,7 +37,7 @@ export default function Import() {
form.data.reset();
form.type.reset();
form.mode.reset();
}
},
});
return (

View file

@ -23,7 +23,7 @@ import FormWithData from "../../../lib/form/form-with-data";
import BackButton from "../../../components/back-button";
import { useBaseUrl } from "../../../lib/navigation/util";
import { useApproveInteractionRequestMutation, useGetInteractionRequestQuery, useRejectInteractionRequestMutation } from "../../../lib/query/user/interactions";
import { InteractionRequest } from "../../../lib/types/interaction";
import type { InteractionRequest } from "../../../lib/types/interaction";
import { useIcon, useNoun, useVerbed } from "./util";
import MutationButton from "../../../components/form/mutation-button";
import { Status } from "../../../components/status";
@ -31,7 +31,7 @@ import { Status } from "../../../components/status";
export default function InteractionRequestDetail({ }) {
const params: { reqId: string } = useParams();
const baseUrl = useBaseUrl();
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
return (
<div className="interaction-request-detail">

View file

@ -17,14 +17,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { ReactNode, useEffect, useMemo } from "react";
import type { ReactNode} from "react";
import React, { useEffect, useMemo } from "react";
import { useBoolInput, useTextInput } from "../../../lib/form";
import { PageableList } from "../../../components/pageable-list";
import MutationButton from "../../../components/form/mutation-button";
import { useLocation, useSearch } from "wouter";
import { useApproveInteractionRequestMutation, useLazySearchInteractionRequestsQuery, useRejectInteractionRequestMutation } from "../../../lib/query/user/interactions";
import { InteractionRequest } from "../../../lib/types/interaction";
import type { InteractionRequest } from "../../../lib/types/interaction";
import { Checkbox } from "../../../components/form/inputs";
import { useContent, useIcon, useNoun, useVerbed } from "./util";
@ -46,16 +47,16 @@ export default function InteractionRequestsSearchForm() {
// urlQueryParams, to allow paging.
const form = {
statusID: useTextInput("status_id", {
defaultValue: urlQueryParams.get("status_id") ?? ""
defaultValue: urlQueryParams.get("status_id") ?? "",
}),
likes: useBoolInput("favourites", {
defaultValue: defaultTrue(urlQueryParams.get("favourites"))
defaultValue: defaultTrue(urlQueryParams.get("favourites")),
}),
replies: useBoolInput("replies", {
defaultValue: defaultTrue(urlQueryParams.get("replies"))
defaultValue: defaultTrue(urlQueryParams.get("replies")),
}),
boosts: useBoolInput("reblogs", {
defaultValue: defaultTrue(urlQueryParams.get("reblogs"))
defaultValue: defaultTrue(urlQueryParams.get("reblogs")),
}),
};
@ -186,7 +187,7 @@ function ReqsListEntry({ req, linkTo, backLocation }: ReqsListEntryProps) {
// Store the back location in history so
// the detail view can use it to return to
// this page (including query parameters).
state: { backLocation: backLocation }
state: { backLocation: backLocation },
});
}}
role="link"

View file

@ -20,8 +20,9 @@
import { useMemo } from "react";
import sanitize from "sanitize-html";
import { compile, HtmlToTextOptions } from "html-to-text";
import { Status } from "../../../lib/types/status";
import type { HtmlToTextOptions } from "html-to-text";
import { compile } from "html-to-text";
import type { Status } from "../../../lib/types/status";
// Options for converting HTML statuses
// to plaintext representations.
@ -29,7 +30,7 @@ const convertOptions: HtmlToTextOptions = {
selectors: [
// Don't fancy format links, just use their text value.
{ selector: 'a', options: { ignoreHref: true } },
]
],
};
const convertHTML = compile(convertOptions);

View file

@ -142,8 +142,8 @@ function AlsoKnownAsURI({ index, data }) {
}
function MoveForm({ data: profile }) {
let urlStr = store.getState().oauth.instanceUrl ?? "";
let url = new URL(urlStr);
const urlStr = store.getState().oauth.instanceUrl ?? "";
const url = new URL(urlStr);
const form = {
movedToURI: useTextInput("moved_to_uri", {

View file

@ -24,7 +24,7 @@ import { Select, Checkbox } from "../../../../components/form/inputs";
import Languages from "../../../../components/languages";
import MutationButton from "../../../../components/form/mutation-button";
import { useUpdateCredentialsMutation } from "../../../../lib/query/user";
import { Account } from "../../../../lib/types/account";
import type { Account } from "../../../../lib/types/account";
export default function BasicSettings({ account }: { account: Account }) {
/* form keys
@ -36,7 +36,7 @@ export default function BasicSettings({ account }: { account: Account }) {
const form = {
defaultPrivacy: useTextInput("source[privacy]", { source: account, defaultValue: "unlisted" }),
isSensitive: useBoolInput("source[sensitive]", { source: account }),
language: useTextInput("source[language]", { source: account, valueSelector: (s: Account) => s.source?.language?.toUpperCase() ?? "EN" }),
language: useTextInput("source[language]", { source: account, valueSelector: (s: Account) => s.source?.language.toUpperCase() ?? "EN" }),
statusContentType: useTextInput("source[status_content_type]", { source: account, defaultValue: "text/plain" }),
};

View file

@ -18,15 +18,16 @@
*/
import React, { useMemo } from "react";
import type {
InteractionPolicyValue} from "../../../../lib/types/interaction";
import {
InteractionPolicyValue,
PolicyValueAuthor,
PolicyValueFollowers,
PolicyValueMentioned,
PolicyValuePublic,
} from "../../../../lib/types/interaction";
import { useTextInput } from "../../../../lib/form";
import { Action, BasicValue, PolicyFormSub, Visibility } from "./types";
import type { Action, BasicValue, PolicyFormSub, Visibility } from "./types";
// Based on the given visibility, action, and states,
// derives what the initial basic Select value should be.

View file

@ -26,11 +26,12 @@ import {
import Loading from "../../../../components/loading";
import { Error } from "../../../../components/error";
import MutationButton from "../../../../components/form/mutation-button";
import {
import type {
DefaultInteractionPolicies,
InteractionPolicy,
InteractionPolicyEntry,
InteractionPolicyValue,
InteractionPolicyValue} from "../../../../lib/types/interaction";
import {
PolicyValueAuthor,
PolicyValueFollowers,
PolicyValueFollowing,
@ -39,10 +40,11 @@ import {
} from "../../../../lib/types/interaction";
import { useTextInput } from "../../../../lib/form";
import { Select } from "../../../../components/form/inputs";
import { TextFormInputHook } from "../../../../lib/form/types";
import type { TextFormInputHook } from "../../../../lib/form/types";
import { useBasicFor } from "./basic";
import { PolicyFormSomethingElse, useSomethingElseFor } from "./something-else";
import { Action, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
import type { PolicyFormSomethingElse} from "./something-else";
import { useSomethingElseFor } from "./something-else";
import type { Action, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
export default function InteractionPolicySettings() {
const {

View file

@ -18,9 +18,10 @@
*/
import React, { useMemo } from "react";
import { InteractionPolicyValue, PolicyValueFollowers, PolicyValueFollowing, PolicyValuePublic } from "../../../../lib/types/interaction";
import type { InteractionPolicyValue} from "../../../../lib/types/interaction";
import { PolicyValueFollowers, PolicyValueFollowing, PolicyValuePublic } from "../../../../lib/types/interaction";
import { useTextInput } from "../../../../lib/form";
import { Action, Audience, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
import type { Action, Audience, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
export interface PolicyFormSomethingElse {
followers: PolicyFormSub,

View file

@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { TextFormInputHook } from "../../../../lib/form/types";
import React from "react";
import type { TextFormInputHook } from "../../../../lib/form/types";
import type React from "react";
export interface PolicyFormSub {
field: TextFormInputHook;

View file

@ -34,18 +34,17 @@ import {
TextArea,
FileInput,
Checkbox,
Select
Select,
} from "../../components/form/inputs";
import FormWithData from "../../lib/form/form-with-data";
import FakeProfile from "../../components/profile";
import MutationButton from "../../components/form/mutation-button";
import { useAccountThemesQuery } from "../../lib/query/user";
import { useUpdateCredentialsMutation } from "../../lib/query/user";
import { useAccountThemesQuery , useUpdateCredentialsMutation } from "../../lib/query/user";
import { useVerifyCredentialsQuery } from "../../lib/query/oauth";
import { useInstanceV1Query } from "../../lib/query/gts-api";
import { Account } from "../../lib/types/account";
import type { Account } from "../../lib/types/account";
export default function UserProfile() {
return (
@ -78,18 +77,18 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
const { data: instance } = useInstanceV1Query();
const instanceConfig = React.useMemo(() => {
return {
allowCustomCSS: instance?.configuration?.accounts?.allow_custom_css === true,
maxPinnedFields: instance?.configuration?.accounts?.max_profile_fields ?? 6
allowCustomCSS: instance?.configuration.accounts.allow_custom_css === true,
maxPinnedFields: instance?.configuration.accounts.max_profile_fields ?? 6,
};
}, [instance]);
// Parse out available theme options into nice format.
const { data: themes } = useAccountThemesQuery();
const themeOptions = useMemo(() => {
let themeOptions = [
const themeOptions = [
<option key="" value="">
Default
</option>
</option>,
];
themes?.forEach((theme) => {
@ -101,7 +100,7 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
themeOptions.push(
<option key={value} value={value}>
{text}
</option>
</option>,
);
});
@ -122,8 +121,8 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
hideCollections: useBoolInput("hide_collections", { source: profile }),
webVisibility: useTextInput("web_visibility", { source: profile, valueSelector: (p) => p.source?.web_visibility }),
fields: useFieldArrayInput("fields_attributes", {
defaultValue: profile?.source?.fields,
length: instanceConfig.maxPinnedFields
defaultValue: profile.source?.fields,
length: instanceConfig.maxPinnedFields,
}),
customCSS: useTextInput("custom_css", { source: profile, nosubmit: !instanceConfig.allowCustomCSS }),
theme: useTextInput("theme", { source: profile }),
@ -134,7 +133,7 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
onFinish: () => {
form.avatar.reset();
form.header.reset();
}
},
});
const noAvatarSet = !profile.avatar_media_id;
@ -322,7 +321,7 @@ function ProfileFields({ field: formField }) {
function Field({ index, data }) {
const form = useWithFormContext(index, {
name: useTextInput("name", { defaultValue: data.name }),
value: useTextInput("value", { defaultValue: data.value })
value: useTextInput("value", { defaultValue: data.value }),
});
return (