mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-25 21:26:40 +00:00
eslint --fix
This commit is contained in:
parent
8464f20370
commit
251286f2c7
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
}]],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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"),
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
|
@ -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;
|
||||
|
|
|
@ -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}`;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -87,6 +87,6 @@ export default function useArrayInput(
|
|||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -80,6 +80,6 @@ export default function useFieldArrayInput(
|
|||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>[];
|
||||
mutationData: {
|
||||
[k: string]: any;
|
||||
};
|
||||
} {
|
||||
updatedFields: FormInputHook[];
|
||||
mutationData: {
|
||||
[k: string]: any;
|
||||
};
|
||||
} {
|
||||
const updatedFields: FormInputHook[] = [];
|
||||
const mutationData: Array<[string, any]> = [];
|
||||
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -225,9 +222,9 @@ export interface ChecklistInputHook<T = Checkable> extends FormInputHook<{[k: st
|
|||
_withSelectedFieldValues,
|
||||
_withSomeSelected,
|
||||
_withUpdateMultiple {
|
||||
// Uses its own funky onChange handler.
|
||||
onChange: (key: any, value: any) => void
|
||||
}
|
||||
// Uses its own funky onChange handler.
|
||||
onChange: (key: any, value: any) => void
|
||||
}
|
||||
|
||||
export type AnyFormInputHook =
|
||||
FormInputHook |
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -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" }],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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`,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
},
|
||||
}),
|
||||
})
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"),
|
||||
}),
|
||||
|
|
|
@ -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`;
|
||||
}),
|
||||
})
|
||||
})
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 }],
|
||||
}),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" }],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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`,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import typia from "typia";
|
||||
import { PermType } from "./perm";
|
||||
import type { PermType } from "./perm";
|
||||
|
||||
export const validateDomainPerms = typia.createValidate<DomainPerm[]>();
|
||||
|
||||
|
|
|
@ -18,80 +18,80 @@
|
|||
*/
|
||||
|
||||
export interface InstanceV1 {
|
||||
uri: string;
|
||||
account_domain: string;
|
||||
title: string;
|
||||
description: string;
|
||||
description_text?: string;
|
||||
short_description: string;
|
||||
short_description_text?: string;
|
||||
email: string;
|
||||
version: string;
|
||||
debug?: boolean;
|
||||
languages: any[]; // TODO: define this
|
||||
registrations: boolean;
|
||||
approval_required: boolean;
|
||||
invites_enabled: boolean;
|
||||
configuration: InstanceConfiguration;
|
||||
urls: InstanceUrls;
|
||||
stats: InstanceStats;
|
||||
thumbnail: string;
|
||||
contact_account: Object; // TODO: define this.
|
||||
max_toot_chars: number;
|
||||
rules: any[]; // TODO: define this
|
||||
terms?: string;
|
||||
terms_text?: string;
|
||||
uri: string;
|
||||
account_domain: string;
|
||||
title: string;
|
||||
description: string;
|
||||
description_text?: string;
|
||||
short_description: string;
|
||||
short_description_text?: string;
|
||||
email: string;
|
||||
version: string;
|
||||
debug?: boolean;
|
||||
languages: any[]; // TODO: define this
|
||||
registrations: boolean;
|
||||
approval_required: boolean;
|
||||
invites_enabled: boolean;
|
||||
configuration: InstanceConfiguration;
|
||||
urls: InstanceUrls;
|
||||
stats: InstanceStats;
|
||||
thumbnail: string;
|
||||
contact_account: object; // TODO: define this.
|
||||
max_toot_chars: number;
|
||||
rules: any[]; // TODO: define this
|
||||
terms?: string;
|
||||
terms_text?: string;
|
||||
}
|
||||
|
||||
export interface InstanceConfiguration {
|
||||
statuses: InstanceStatuses;
|
||||
media_attachments: InstanceMediaAttachments;
|
||||
polls: InstancePolls;
|
||||
accounts: InstanceAccounts;
|
||||
emojis: InstanceEmojis;
|
||||
oidc_enabled?: boolean;
|
||||
statuses: InstanceStatuses;
|
||||
media_attachments: InstanceMediaAttachments;
|
||||
polls: InstancePolls;
|
||||
accounts: InstanceAccounts;
|
||||
emojis: InstanceEmojis;
|
||||
oidc_enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface InstanceAccounts {
|
||||
allow_custom_css: boolean;
|
||||
max_featured_tags: number;
|
||||
max_profile_fields: number;
|
||||
allow_custom_css: boolean;
|
||||
max_featured_tags: number;
|
||||
max_profile_fields: number;
|
||||
}
|
||||
|
||||
export interface InstanceEmojis {
|
||||
emoji_size_limit: number;
|
||||
emoji_size_limit: number;
|
||||
}
|
||||
|
||||
export interface InstanceMediaAttachments {
|
||||
supported_mime_types: string[];
|
||||
image_size_limit: number;
|
||||
image_matrix_limit: number;
|
||||
video_size_limit: number;
|
||||
video_frame_rate_limit: number;
|
||||
video_matrix_limit: number;
|
||||
supported_mime_types: string[];
|
||||
image_size_limit: number;
|
||||
image_matrix_limit: number;
|
||||
video_size_limit: number;
|
||||
video_frame_rate_limit: number;
|
||||
video_matrix_limit: number;
|
||||
}
|
||||
|
||||
export interface InstancePolls {
|
||||
max_options: number;
|
||||
max_characters_per_option: number;
|
||||
min_expiration: number;
|
||||
max_expiration: number;
|
||||
max_options: number;
|
||||
max_characters_per_option: number;
|
||||
min_expiration: number;
|
||||
max_expiration: number;
|
||||
}
|
||||
|
||||
export interface InstanceStatuses {
|
||||
max_characters: number;
|
||||
max_media_attachments: number;
|
||||
characters_reserved_per_url: number;
|
||||
supported_mime_types: string[];
|
||||
max_characters: number;
|
||||
max_media_attachments: number;
|
||||
characters_reserved_per_url: number;
|
||||
supported_mime_types: string[];
|
||||
}
|
||||
|
||||
export interface InstanceStats {
|
||||
domain_count: number;
|
||||
status_count: number;
|
||||
user_count: number;
|
||||
domain_count: number;
|
||||
status_count: number;
|
||||
user_count: number;
|
||||
}
|
||||
|
||||
export interface InstanceUrls {
|
||||
streaming_api: string;
|
||||
streaming_api: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -71,7 +71,7 @@ export {
|
|||
* Interaction request targeting a status by an account.
|
||||
*/
|
||||
export interface InteractionRequest {
|
||||
/**
|
||||
/**
|
||||
* ID of the request.
|
||||
*/
|
||||
id: string;
|
||||
|
|
|
@ -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
|
||||
|
@ -46,25 +46,25 @@ interface MutationStartedParams {
|
|||
/**
|
||||
* A method to get the current state for the store.
|
||||
*/
|
||||
getState,
|
||||
getState,
|
||||
/**
|
||||
* extra as provided as thunk.extraArgument to the configureStore getDefaultMiddleware option.
|
||||
*/
|
||||
extra,
|
||||
extra,
|
||||
/**
|
||||
* A unique ID generated for the query/mutation.
|
||||
*/
|
||||
requestId,
|
||||
requestId,
|
||||
/**
|
||||
* A Promise that will resolve with a data property (the transformed query result), and a
|
||||
* meta property (meta returned by the baseQuery). If the query fails, this Promise will
|
||||
* reject with the error. This allows you to await for the query to finish.
|
||||
*/
|
||||
queryFulfilled,
|
||||
queryFulfilled,
|
||||
/**
|
||||
* A function that gets the current value of the cache entry.
|
||||
*/
|
||||
getCacheEntry,
|
||||
getCacheEntry,
|
||||
}
|
||||
|
||||
export type Action = (
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
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
|
||||
* model, which contains less detailed information.
|
||||
*/
|
||||
export interface AdminReport {
|
||||
/**
|
||||
/**
|
||||
* ID of the report.
|
||||
*/
|
||||
id: string;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -94,7 +94,7 @@ export interface AdminReport {
|
|||
* Parameters for POST to /api/v1/admin/reports/{id}/resolve.
|
||||
*/
|
||||
export interface AdminReportResolveParams {
|
||||
/**
|
||||
/**
|
||||
* The ID of the report to resolve.
|
||||
*/
|
||||
id: string;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -29,7 +29,7 @@ import { get } from "psl";
|
|||
export function isValidDomainPermission(domain: string): boolean {
|
||||
return isValidDomain(domain, {
|
||||
wildcard: false,
|
||||
allowUnicode: true
|
||||
allowUnicode: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 }),
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -47,7 +47,7 @@ export default function ExpireRemote({}) {
|
|||
}
|
||||
|
||||
return "invalid domain";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const [expire, expireResult] = useInstanceKeysExpireMutation();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}
|
||||
</>
|
||||
</>,
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
|
@ -101,7 +101,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
|
|||
label={
|
||||
<>
|
||||
Header Name
|
||||
<a
|
||||
<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"
|
||||
target="_blank"
|
||||
className="docslink"
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -37,8 +37,8 @@ export default function ImportExport() {
|
|||
options: {
|
||||
block: "Domain blocks",
|
||||
allow: "Domain allows",
|
||||
}
|
||||
})
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const [submitParse, parseResult] = useFormSubmit(form, useProcessDomainPermissionsMutation(), { changedOnly: false });
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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 });
|
||||
|
@ -249,7 +249,7 @@ function ReportStatuses({ report }: { report: AdminReport }) {
|
|||
<Status
|
||||
key={status.id}
|
||||
status={status}
|
||||
/>
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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(
|
||||
|
@ -92,7 +92,7 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
|||
className="docslink"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more about this section (opens in a new tab)
|
||||
Learn more about this section (opens in a new tab)
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
@ -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}
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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", {
|
||||
|
@ -162,10 +162,10 @@ function MoveForm({ data: profile }) {
|
|||
<div className="form-section-docs">
|
||||
<h3>Move Account</h3>
|
||||
<p>
|
||||
For a move to be successful, you must have already set an alias from the
|
||||
target account back to the account you're moving from (ie., this account),
|
||||
using the settings panel of the instance on which the target account resides.
|
||||
To do this, provide the following details to the other instance:
|
||||
For a move to be successful, you must have already set an alias from the
|
||||
target account back to the account you're moving from (ie., this account),
|
||||
using the settings panel of the instance on which the target account resides.
|
||||
To do this, provide the following details to the other instance:
|
||||
</p>
|
||||
<dl className="migration-details">
|
||||
<div>
|
||||
|
|
|
@ -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" }),
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ export default function BasicSettings({ account }: { account: Account }) {
|
|||
className="docslink"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more about these settings (opens in a new tab)
|
||||
Learn more about these settings (opens in a new tab)
|
||||
</a>
|
||||
</div>
|
||||
<Select field={form.language} label="Default post language" options={
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
@ -134,7 +136,7 @@ function InteractionPoliciesForm({ defaultPolicies }: InteractionPoliciesFormPro
|
|||
these settings; they do not apply retroactively.
|
||||
<br/>
|
||||
The word "anyone" in the below options means <em>anyone with
|
||||
permission to see the post</em>, taking account of blocks.
|
||||
permission to see the post</em>, taking account of blocks.
|
||||
<br/>
|
||||
Bear in mind that no matter what you set below, you will always
|
||||
be able to like, reply-to, and boost your own posts.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
|
|
Loading…
Reference in a new issue