mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-29 15:12:45 +00:00
eslint --fix
This commit is contained in:
parent
8464f20370
commit
251286f2c7
|
@ -46,7 +46,7 @@ new PhotoswipeCaptionPlugin(lightbox, {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
captionContent(slide) {
|
captionContent(slide) {
|
||||||
return slide.data.alt;
|
return slide.data.alt;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
lightbox.addFilter('itemData', (item) => {
|
lightbox.addFilter('itemData', (item) => {
|
||||||
|
@ -68,10 +68,10 @@ lightbox.addFilter('itemData', (item) => {
|
||||||
},
|
},
|
||||||
pause() {
|
pause() {
|
||||||
el._player.pause();
|
el._player.pause();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
width: parseInt(el.dataset.pswpWidth),
|
width: parseInt(el.dataset.pswpWidth),
|
||||||
height: parseInt(el.dataset.pswpHeight)
|
height: parseInt(el.dataset.pswpHeight),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
@ -169,12 +169,12 @@ Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => {
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
lightbox.loadAndOpen(parseInt(video.dataset.pswpIndex), {
|
lightbox.loadAndOpen(parseInt(video.dataset.pswpIndex), {
|
||||||
gallery: video.closest(".photoswipe-gallery")
|
gallery: video.closest(".photoswipe-gallery"),
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
player.elements.container.title = video.title;
|
player.elements.container.title = video.title;
|
||||||
|
|
|
@ -29,10 +29,10 @@ const prodCfg = {
|
||||||
transform: [
|
transform: [
|
||||||
["@browserify/uglifyify", {
|
["@browserify/uglifyify", {
|
||||||
global: true,
|
global: true,
|
||||||
exts: ".js"
|
exts: ".js",
|
||||||
}],
|
}],
|
||||||
["@browserify/envify", { global: true }]
|
["@browserify/envify", { global: true }],
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
skulk({
|
skulk({
|
||||||
|
@ -42,8 +42,8 @@ skulk({
|
||||||
prodCfg: {
|
prodCfg: {
|
||||||
servers: {
|
servers: {
|
||||||
express: false,
|
express: false,
|
||||||
livereload: false
|
livereload: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
servers: {
|
servers: {
|
||||||
express: {
|
express: {
|
||||||
|
@ -54,6 +54,8 @@ skulk({
|
||||||
delete proxyRes.headers['content-security-policy'];
|
delete proxyRes.headers['content-security-policy'];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
assets: "/assets",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
bundles: {
|
bundles: {
|
||||||
frontend: {
|
frontend: {
|
||||||
|
@ -64,8 +66,8 @@ skulk({
|
||||||
transform: [
|
transform: [
|
||||||
["babelify", {
|
["babelify", {
|
||||||
global: true,
|
global: true,
|
||||||
ignore: [/node_modules\/(?!(photoswipe.*))/]
|
ignore: [/node_modules\/(?!(photoswipe.*))/],
|
||||||
}]
|
}],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
|
@ -75,7 +77,7 @@ skulk({
|
||||||
plugin: [
|
plugin: [
|
||||||
// Additional settings for TS are passed from tsconfig.json.
|
// Additional settings for TS are passed from tsconfig.json.
|
||||||
// See: https://github.com/TypeStrong/tsify#tsconfigjson
|
// See: https://github.com/TypeStrong/tsify#tsconfigjson
|
||||||
["tsify"]
|
["tsify"],
|
||||||
],
|
],
|
||||||
transform: [
|
transform: [
|
||||||
// tsify is called before babelify, so we're just babelifying
|
// tsify is called before babelify, so we're just babelifying
|
||||||
|
@ -83,28 +85,28 @@ skulk({
|
||||||
["babelify", {
|
["babelify", {
|
||||||
global: true,
|
global: true,
|
||||||
ignore: [/node_modules\/(?!(nanoid)|(wouter))/],
|
ignore: [/node_modules\/(?!(nanoid)|(wouter))/],
|
||||||
}]
|
}],
|
||||||
],
|
],
|
||||||
presets: [
|
presets: [
|
||||||
"react",
|
"react",
|
||||||
["postcss", {
|
["postcss", {
|
||||||
output: "settings-style.css"
|
output: "settings-style.css",
|
||||||
}]
|
}],
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
cssThemes: {
|
cssThemes: {
|
||||||
entryFiles: cssThemes,
|
entryFiles: cssThemes,
|
||||||
outputFile: "_discard",
|
outputFile: "_discard",
|
||||||
presets: [["postcss", {
|
presets: [["postcss", {
|
||||||
output: "_split"
|
output: "_split",
|
||||||
}]]
|
}]],
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
entryFiles: cssFiles,
|
entryFiles: cssFiles,
|
||||||
outputFile: "_discard",
|
outputFile: "_discard",
|
||||||
presets: [["postcss", {
|
presets: [["postcss", {
|
||||||
output: "style.css"
|
output: "style.css",
|
||||||
}]]
|
}]],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
|
|
||||||
import { useLogoutMutation, useVerifyCredentialsQuery } from "../../lib/query/oauth";
|
import { useLogoutMutation, useVerifyCredentialsQuery } from "../../lib/query/oauth";
|
||||||
import { store } from "../../redux/store";
|
import { store } from "../../redux/store";
|
||||||
import React, { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
import Login from "./login";
|
import Login from "./login";
|
||||||
import Loading from "../loading";
|
import Loading from "../loading";
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { TextInput } from "../form/inputs";
|
||||||
export default function Login({ }) {
|
export default function Login({ }) {
|
||||||
const form = {
|
const form = {
|
||||||
instance: useTextInput("instance", {
|
instance: useTextInput("instance", {
|
||||||
defaultValue: window.location.origin
|
defaultValue: window.location.origin,
|
||||||
}),
|
}),
|
||||||
scopes: useValue("scopes", "user admin"),
|
scopes: useValue("scopes", "user admin"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 type { Checkable, ChecklistInputHook } from "../lib/form/types";
|
||||||
import { Checkable, ChecklistInputHook } from "../lib/form/types";
|
|
||||||
|
|
||||||
interface CheckListProps {
|
interface CheckListProps {
|
||||||
field: ChecklistInputHook;
|
field: ChecklistInputHook;
|
||||||
|
@ -75,7 +74,7 @@ const CheckListEntries = memo(
|
||||||
getExtraProps={getExtraProps}
|
getExtraProps={getExtraProps}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface CheckListEntryProps {
|
interface CheckListEntryProps {
|
||||||
|
@ -94,7 +93,7 @@ const CheckListEntry = memo(
|
||||||
function CheckListEntry({ entry, updateValue, getExtraProps, EntryComponent }: CheckListEntryProps) {
|
function CheckListEntry({ entry, updateValue, getExtraProps, EntryComponent }: CheckListEntryProps) {
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(value) => updateValue(entry.key, value),
|
(value) => updateValue(entry.key, value),
|
||||||
[updateValue, entry.key]
|
[updateValue, entry.key],
|
||||||
);
|
);
|
||||||
|
|
||||||
const extraProps = useMemo(() => getExtraProps?.(entry), [getExtraProps, entry]);
|
const extraProps = useMemo(() => getExtraProps?.(entry), [getExtraProps, entry]);
|
||||||
|
@ -109,5 +108,5 @@ const CheckListEntry = memo(
|
||||||
<EntryComponent entry={entry} onChange={onChange} extraProps={extraProps} />
|
<EntryComponent entry={entry} onChange={onChange} extraProps={extraProps} />
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
|
@ -17,9 +17,10 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SerializedError } from "@reduxjs/toolkit";
|
import type { SerializedError } from "@reduxjs/toolkit";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import React, { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
function ErrorFallback({ error, resetErrorBoundary }) {
|
function ErrorFallback({ error, resetErrorBoundary }) {
|
||||||
return (
|
return (
|
||||||
|
@ -74,7 +75,7 @@ function Error({ error, reset }: ErrorProps) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.error("caught error: ", error);
|
console.error("caught error: ", error);
|
||||||
|
|
||||||
let message: ReactNode;
|
let message: ReactNode;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import React from "react";
|
||||||
import { all } from "langs";
|
import { all } from "langs";
|
||||||
|
|
||||||
const asElements = all().map((l) => {
|
const asElements = all().map((l) => {
|
||||||
let code = l["1"].toUpperCase();
|
const code = l["1"].toUpperCase();
|
||||||
let name = l.name;
|
let name = l.name;
|
||||||
if (l.name != l.local) {
|
if (l.name != l.local) {
|
||||||
name = `${name} - ${l.local}`;
|
name = `${name} - ${l.local}`;
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useLocation } from "wouter";
|
||||||
import { Error } from "./error";
|
import { Error } from "./error";
|
||||||
import { SerializedError } from "@reduxjs/toolkit";
|
import type { SerializedError } from "@reduxjs/toolkit";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { Links } from "parse-link-header";
|
import type { Links } from "parse-link-header";
|
||||||
import Loading from "./loading";
|
import Loading from "./loading";
|
||||||
|
|
||||||
export interface PageableListProps<T> {
|
export interface PageableListProps<T> {
|
||||||
|
|
|
@ -19,14 +19,14 @@
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useVerifyCredentialsQuery } from "../lib/query/oauth";
|
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";
|
import sanitize from "sanitize-html";
|
||||||
|
|
||||||
export function FakeStatus({ children }) {
|
export function FakeStatus({ children }) {
|
||||||
const { data: account = {
|
const { data: account = {
|
||||||
avatar: "/assets/default_avatars/GoToSocial_icon1.webp",
|
avatar: "/assets/default_avatars/GoToSocial_icon1.webp",
|
||||||
display_name: "",
|
display_name: "",
|
||||||
username: ""
|
username: "",
|
||||||
} } = useVerifyCredentialsQuery();
|
} } = useVerifyCredentialsQuery();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useLocation } from "wouter";
|
import { useLocation } from "wouter";
|
||||||
import { AdminAccount } from "../lib/types/account";
|
import type { AdminAccount } from "../lib/types/account";
|
||||||
|
|
||||||
interface UsernameProps {
|
interface UsernameProps {
|
||||||
account: AdminAccount;
|
account: AdminAccount;
|
||||||
|
@ -32,7 +32,7 @@ export default function Username({ account, linkTo, backLocation, classNames }:
|
||||||
const [ _location, setLocation ] = useLocation();
|
const [ _location, setLocation ] = useLocation();
|
||||||
|
|
||||||
let className = "username-lozenge";
|
let className = "username-lozenge";
|
||||||
let isLocal = account.domain == null;
|
const isLocal = account.domain == null;
|
||||||
|
|
||||||
if (account.suspended) {
|
if (account.suspended) {
|
||||||
className += " suspended";
|
className += " suspended";
|
||||||
|
@ -46,7 +46,7 @@ export default function Username({ account, linkTo, backLocation, classNames }:
|
||||||
className = [ className, classNames ].flat().join(" ");
|
className = [ className, classNames ].flat().join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = isLocal
|
const icon = isLocal
|
||||||
? { fa: "fa-home", info: "Local user" }
|
? { fa: "fa-home", info: "Local user" }
|
||||||
: { fa: "fa-external-link-square", info: "Remote 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
|
// Store the back location in history so
|
||||||
// the detail view can use it to return to
|
// the detail view can use it to return to
|
||||||
// this page (including query parameters).
|
// this page (including query parameters).
|
||||||
state: { backLocation: backLocation }
|
state: { backLocation: backLocation },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
role="link"
|
role="link"
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { PersistGate } from "redux-persist/integration/react";
|
||||||
import { store, persistor } from "./redux/store";
|
import { store, persistor } from "./redux/store";
|
||||||
import { Authorization } from "./components/authorization";
|
import { Authorization } from "./components/authorization";
|
||||||
import Loading from "./components/loading";
|
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 { BaseUrlContext, RoleContext, InstanceDebugContext } from "./lib/navigation/util";
|
||||||
import { SidebarMenu } from "./lib/navigation/menu";
|
import { SidebarMenu } from "./lib/navigation/menu";
|
||||||
import { Redirect, Route, Router } from "wouter";
|
import { Redirect, Route, Router } from "wouter";
|
||||||
|
|
|
@ -87,6 +87,6 @@ export default function useArrayInput(
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import type {
|
||||||
const _default = false;
|
const _default = false;
|
||||||
export default function useBoolInput(
|
export default function useBoolInput(
|
||||||
{ name, Name }: CreateHookNames,
|
{ name, Name }: CreateHookNames,
|
||||||
{ initialValue = _default }: HookOpts<boolean>
|
{ initialValue = _default }: HookOpts<boolean>,
|
||||||
): BoolFormInputHook {
|
): BoolFormInputHook {
|
||||||
const [value, setValue] = useState(initialValue);
|
const [value, setValue] = useState(initialValue);
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ export default function useBoolInput(
|
||||||
reset,
|
reset,
|
||||||
{
|
{
|
||||||
[name]: value,
|
[name]: value,
|
||||||
[`set${Name}`]: setValue
|
[`set${Name}`]: setValue,
|
||||||
}
|
},
|
||||||
], {
|
], {
|
||||||
name,
|
name,
|
||||||
Name: "",
|
Name: "",
|
||||||
|
@ -55,6 +55,6 @@ export default function useBoolInput(
|
||||||
value,
|
value,
|
||||||
setter: setValue,
|
setter: setValue,
|
||||||
hasChanged: () => value != initialValue,
|
hasChanged: () => value != initialValue,
|
||||||
_default
|
_default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,20 +38,20 @@ import {
|
||||||
|
|
||||||
const _default: { [k: string]: Checkable } = {};
|
const _default: { [k: string]: Checkable } = {};
|
||||||
export default function useCheckListInput(
|
export default function useCheckListInput(
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
{ name, Name }: CreateHookNames,
|
{ name, Name }: CreateHookNames,
|
||||||
{
|
{
|
||||||
entries = [],
|
entries = [],
|
||||||
uniqueKey = "key",
|
uniqueKey = "key",
|
||||||
initialValue = false,
|
initialValue = false,
|
||||||
}: HookOpts<boolean>
|
}: HookOpts<boolean>,
|
||||||
): ChecklistInputHook {
|
): ChecklistInputHook {
|
||||||
const [state, dispatch] = useChecklistReducer(entries, uniqueKey, initialValue);
|
const [state, dispatch] = useChecklistReducer(entries, uniqueKey, initialValue);
|
||||||
const toggleAllRef = useRef<any>(null);
|
const toggleAllRef = useRef<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (toggleAllRef.current != null) {
|
if (toggleAllRef.current != null) {
|
||||||
let some = state.selectedEntries.size > 0;
|
const some = state.selectedEntries.size > 0;
|
||||||
let all = false;
|
let all = false;
|
||||||
if (some) {
|
if (some) {
|
||||||
all = state.selectedEntries.size == Object.values(state.entries).length;
|
all = state.selectedEntries.size == Object.values(state.entries).length;
|
||||||
|
@ -64,18 +64,24 @@ export default function useCheckListInput(
|
||||||
}, [state.selectedEntries]);
|
}, [state.selectedEntries]);
|
||||||
|
|
||||||
const reset = useCallback(
|
const reset = useCallback(
|
||||||
() => dispatch(actions.updateAll(initialValue)),
|
() => {
|
||||||
[initialValue, dispatch]
|
dispatch(actions.updateAll(initialValue));
|
||||||
|
},
|
||||||
|
[initialValue, dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(key: string, value: Checkable) => dispatch(actions.update({ key, value })),
|
(key: string, value: Checkable) => {
|
||||||
[dispatch]
|
dispatch(actions.update({ key, value }));
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateMultiple = useCallback(
|
const updateMultiple = useCallback(
|
||||||
(entries: [key: string, value: Partial<Checkable>][]) => dispatch(actions.updateMultiple(entries)),
|
(entries: [key: string, value: Partial<Checkable>][]) => {
|
||||||
[dispatch]
|
dispatch(actions.updateMultiple(entries));
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
|
@ -89,14 +95,14 @@ export default function useCheckListInput(
|
||||||
|
|
||||||
function selectedValues() {
|
function selectedValues() {
|
||||||
return Array.from((state.selectedEntries)).map((key) => ({
|
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([
|
return Object.assign([
|
||||||
state,
|
state,
|
||||||
reset,
|
reset,
|
||||||
{ name }
|
{ name },
|
||||||
], {
|
], {
|
||||||
_default,
|
_default,
|
||||||
hasChanged: () => true,
|
hasChanged: () => true,
|
||||||
|
@ -110,8 +116,8 @@ export default function useCheckListInput(
|
||||||
updateMultiple,
|
updateMultiple,
|
||||||
toggleAll: {
|
toggleAll: {
|
||||||
ref: toggleAllRef,
|
ref: toggleAllRef,
|
||||||
onChange: toggleAll
|
onChange: toggleAll,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, [state, reset, name, onChange, updateMultiple, dispatch]);
|
}, [state, reset, name, onChange, updateMultiple, dispatch]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useComboboxState } from "ariakit/combobox";
|
import { useComboboxState } from "ariakit/combobox";
|
||||||
import {
|
import type {
|
||||||
ComboboxFormInputHook,
|
ComboboxFormInputHook,
|
||||||
CreateHookNames,
|
CreateHookNames,
|
||||||
HookOpts,
|
HookOpts,
|
||||||
|
@ -29,14 +29,14 @@ import {
|
||||||
const _default = "";
|
const _default = "";
|
||||||
export default function useComboBoxInput(
|
export default function useComboBoxInput(
|
||||||
{ name, Name }: CreateHookNames,
|
{ name, Name }: CreateHookNames,
|
||||||
{ initialValue = _default }: HookOpts<string>
|
{ initialValue = _default }: HookOpts<string>,
|
||||||
): ComboboxFormInputHook {
|
): ComboboxFormInputHook {
|
||||||
const [isNew, setIsNew] = useState(false);
|
const [isNew, setIsNew] = useState(false);
|
||||||
|
|
||||||
const state = useComboboxState({
|
const state = useComboboxState({
|
||||||
defaultValue: initialValue,
|
defaultValue: initialValue,
|
||||||
gutter: 0,
|
gutter: 0,
|
||||||
sameWidth: true
|
sameWidth: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
|
@ -50,18 +50,20 @@ export default function useComboBoxInput(
|
||||||
[name]: state.value,
|
[name]: state.value,
|
||||||
name,
|
name,
|
||||||
[`${name}IsNew`]: isNew,
|
[`${name}IsNew`]: isNew,
|
||||||
[`set${Name}IsNew`]: setIsNew
|
[`set${Name}IsNew`]: setIsNew,
|
||||||
}
|
},
|
||||||
], {
|
], {
|
||||||
reset,
|
reset,
|
||||||
name,
|
name,
|
||||||
Name: "", // Will be set by inputHook function.
|
Name: "", // Will be set by inputHook function.
|
||||||
state,
|
state,
|
||||||
value: state.value,
|
value: state.value,
|
||||||
setter: (val: string) => state.setValue(val),
|
setter: (val: string) => {
|
||||||
|
state.setValue(val);
|
||||||
|
},
|
||||||
hasChanged: () => state.value != initialValue,
|
hasChanged: () => state.value != initialValue,
|
||||||
isNew,
|
isNew,
|
||||||
setIsNew,
|
setIsNew,
|
||||||
_default
|
_default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,6 @@ export default function useFieldArrayInput(
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 prettierBytes from "prettier-bytes";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
@ -35,8 +34,8 @@ export default function useFileInput(
|
||||||
{
|
{
|
||||||
withPreview,
|
withPreview,
|
||||||
maxSize,
|
maxSize,
|
||||||
initialInfo = "no file selected"
|
initialInfo = "no file selected",
|
||||||
}: HookOpts<File>
|
}: HookOpts<File>,
|
||||||
): FileFormInputHook {
|
): FileFormInputHook {
|
||||||
const [file, setFile] = useState<File>();
|
const [file, setFile] = useState<File>();
|
||||||
const [imageURL, setImageURL] = useState<string>();
|
const [imageURL, setImageURL] = useState<string>();
|
||||||
|
@ -58,7 +57,7 @@ export default function useFileInput(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = files[0];
|
const file = files[0];
|
||||||
setFile(file);
|
setFile(file);
|
||||||
|
|
||||||
if (imageURL) {
|
if (imageURL) {
|
||||||
|
@ -76,7 +75,7 @@ export default function useFileInput(
|
||||||
<ErrorC
|
<ErrorC
|
||||||
error={new Error(`file size ${sizePrettier} is larger than max size ${maxSizePrettier}`)}
|
error={new Error(`file size ${sizePrettier} is larger than max size ${maxSizePrettier}`)}
|
||||||
reset={(reset)}
|
reset={(reset)}
|
||||||
/>
|
/>,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setInfo(<>{file.name} ({sizePrettier})</>);
|
setInfo(<>{file.name} ({sizePrettier})</>);
|
||||||
|
@ -100,7 +99,7 @@ export default function useFileInput(
|
||||||
[name]: file,
|
[name]: file,
|
||||||
[`${name}URL`]: imageURL,
|
[`${name}URL`]: imageURL,
|
||||||
[`${name}Info`]: infoComponent,
|
[`${name}Info`]: infoComponent,
|
||||||
}
|
},
|
||||||
], {
|
], {
|
||||||
onChange,
|
onChange,
|
||||||
reset,
|
reset,
|
||||||
|
|
|
@ -17,14 +17,12 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { Error } from "../../components/error";
|
import { Error } from "../../components/error";
|
||||||
import Loading from "../../components/loading";
|
import Loading from "../../components/loading";
|
||||||
import { NoArg } from "../types/query";
|
import { NoArg } from "../types/query";
|
||||||
import { FormWithDataQuery } from "./types";
|
import type { FormWithDataQuery } from "./types";
|
||||||
|
|
||||||
export interface FormWithDataProps {
|
export interface FormWithDataProps {
|
||||||
dataQuery: FormWithDataQuery,
|
dataQuery: FormWithDataQuery,
|
||||||
|
|
|
@ -17,17 +17,17 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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(
|
export default function getFormMutations(
|
||||||
form: HookedForm,
|
form: HookedForm,
|
||||||
{ changedOnly }: { changedOnly: boolean },
|
{ changedOnly }: { changedOnly: boolean },
|
||||||
): {
|
): {
|
||||||
updatedFields: FormInputHook<any>[];
|
updatedFields: FormInputHook[];
|
||||||
mutationData: {
|
mutationData: {
|
||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
};
|
};
|
||||||
} {
|
} {
|
||||||
const updatedFields: FormInputHook[] = [];
|
const updatedFields: FormInputHook[] = [];
|
||||||
const mutationData: Array<[string, any]> = [];
|
const mutationData: Array<[string, any]> = [];
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { CreateHookNames, HookOpts, RadioFormInputHook } from "./types";
|
import type { CreateHookNames, HookOpts, RadioFormInputHook } from "./types";
|
||||||
|
|
||||||
const _default = "";
|
const _default = "";
|
||||||
export default function useRadioInput(
|
export default function useRadioInput(
|
||||||
|
@ -26,7 +26,7 @@ export default function useRadioInput(
|
||||||
{
|
{
|
||||||
initialValue = _default,
|
initialValue = _default,
|
||||||
options = {},
|
options = {},
|
||||||
}: HookOpts<string>
|
}: HookOpts<string>,
|
||||||
): RadioFormInputHook {
|
): RadioFormInputHook {
|
||||||
const [value, setValue] = useState(initialValue);
|
const [value, setValue] = useState(initialValue);
|
||||||
|
|
||||||
|
@ -44,8 +44,8 @@ export default function useRadioInput(
|
||||||
reset,
|
reset,
|
||||||
{
|
{
|
||||||
[name]: value,
|
[name]: value,
|
||||||
[`set${Name}`]: setValue
|
[`set${Name}`]: setValue,
|
||||||
}
|
},
|
||||||
], {
|
], {
|
||||||
onChange,
|
onChange,
|
||||||
reset,
|
reset,
|
||||||
|
@ -55,6 +55,6 @@ export default function useRadioInput(
|
||||||
setter: setValue,
|
setter: setValue,
|
||||||
options,
|
options,
|
||||||
hasChanged: () => value != initialValue,
|
hasChanged: () => value != initialValue,
|
||||||
_default
|
_default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ interface UseFormSubmitOptions {
|
||||||
export default function useFormSubmit(
|
export default function useFormSubmit(
|
||||||
form: HookedForm,
|
form: HookedForm,
|
||||||
mutationQuery: readonly [MutationTrigger<any>, UseMutationStateResult<any, any>],
|
mutationQuery: readonly [MutationTrigger<any>, UseMutationStateResult<any, any>],
|
||||||
opts: UseFormSubmitOptions = { changedOnly: true }
|
opts: UseFormSubmitOptions = { changedOnly: true },
|
||||||
): [ FormSubmitFunction, FormSubmitResult ] {
|
): [ FormSubmitFunction, FormSubmitResult ] {
|
||||||
if (!Array.isArray(mutationQuery)) {
|
if (!Array.isArray(mutationQuery)) {
|
||||||
throw "useFormSubmit: mutationQuery was not an Array. Is a valid useMutation RTK Query provided?";
|
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.
|
// 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
|
// 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 {
|
} else {
|
||||||
// No submitter defined. Fall back
|
// No submitter defined. Fall back
|
||||||
// to just use the FormSubmitEvent.
|
// to just use the FormSubmitEvent.
|
||||||
|
@ -125,7 +125,7 @@ export default function useFormSubmit(
|
||||||
onFinish(res);
|
onFinish(res);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(`caught error running mutation: ${e}`);
|
console.error(`caught error running mutation: ${e}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -134,7 +134,7 @@ export default function useFormSubmit(
|
||||||
submitForm,
|
submitForm,
|
||||||
{
|
{
|
||||||
...mutationResult,
|
...mutationResult,
|
||||||
action: usedAction.current
|
action: usedAction.current,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {
|
import type React from "react";
|
||||||
|
import {
|
||||||
useState,
|
useState,
|
||||||
useRef,
|
useRef,
|
||||||
useTransition,
|
useTransition,
|
||||||
|
@ -41,7 +42,7 @@ export default function useTextInput(
|
||||||
showValidation = true,
|
showValidation = true,
|
||||||
initValidation,
|
initValidation,
|
||||||
nosubmit = false,
|
nosubmit = false,
|
||||||
}: HookOpts<string>
|
}: HookOpts<string>,
|
||||||
): TextFormInputHook {
|
): TextFormInputHook {
|
||||||
const [text, setText] = useState(initialValue);
|
const [text, setText] = useState(initialValue);
|
||||||
const textRef = useRef<HTMLInputElement>(null);
|
const textRef = useRef<HTMLInputElement>(null);
|
||||||
|
@ -86,7 +87,7 @@ export default function useTextInput(
|
||||||
[`${name}Ref`]: textRef,
|
[`${name}Ref`]: textRef,
|
||||||
[`set${Name}`]: setText,
|
[`set${Name}`]: setText,
|
||||||
[`${name}Valid`]: valid,
|
[`${name}Valid`]: valid,
|
||||||
}
|
},
|
||||||
], {
|
], {
|
||||||
onChange,
|
onChange,
|
||||||
reset,
|
reset,
|
||||||
|
@ -97,8 +98,10 @@ export default function useTextInput(
|
||||||
ref: textRef,
|
ref: textRef,
|
||||||
setter: setText,
|
setter: setText,
|
||||||
valid,
|
valid,
|
||||||
validate: () => setValidation(validator ? validator(text): ""),
|
validate: () => {
|
||||||
|
setValidation(validator ? validator(text): "");
|
||||||
|
},
|
||||||
hasChanged: () => text != initialValue,
|
hasChanged: () => text != initialValue,
|
||||||
_default
|
_default,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
import type { ComboboxState } from "ariakit";
|
||||||
|
import type React, {
|
||||||
import { ComboboxState } from "ariakit";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import {
|
|
||||||
ChangeEventHandler,
|
ChangeEventHandler,
|
||||||
Dispatch,
|
Dispatch,
|
||||||
RefObject,
|
RefObject,
|
||||||
|
@ -30,6 +26,7 @@ import {
|
||||||
SyntheticEvent,
|
SyntheticEvent,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
|
||||||
export interface CreateHookNames {
|
export interface CreateHookNames {
|
||||||
name: string;
|
name: string;
|
||||||
Name: string;
|
Name: string;
|
||||||
|
@ -225,9 +222,9 @@ export interface ChecklistInputHook<T = Checkable> extends FormInputHook<{[k: st
|
||||||
_withSelectedFieldValues,
|
_withSelectedFieldValues,
|
||||||
_withSomeSelected,
|
_withSomeSelected,
|
||||||
_withUpdateMultiple {
|
_withUpdateMultiple {
|
||||||
// Uses its own funky onChange handler.
|
// Uses its own funky onChange handler.
|
||||||
onChange: (key: any, value: any) => void
|
onChange: (key: any, value: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnyFormInputHook =
|
export type AnyFormInputHook =
|
||||||
FormInputHook |
|
FormInputHook |
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 {
|
interface ErrorBoundaryProps {
|
||||||
|
@ -48,7 +49,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||||
componentDidCatch(_e, info) {
|
componentDidCatch(_e, info) {
|
||||||
this.setState({
|
this.setState({
|
||||||
...this.state,
|
...this.state,
|
||||||
componentStack: info.componentStack
|
componentStack: info.componentStack,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ function ErrorFallback({ error, componentStack, resetErrorBoundary }) {
|
||||||
|
|
||||||
{componentStack && [
|
{componentStack && [
|
||||||
"\n\nComponent trace:",
|
"\n\nComponent trace:",
|
||||||
componentStack
|
componentStack,
|
||||||
]}
|
]}
|
||||||
{["\n\nError trace: ", error.stack]}
|
{["\n\nError trace: ", error.stack]}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { Link, useRoute } from "wouter";
|
||||||
import {
|
import {
|
||||||
BaseUrlContext,
|
BaseUrlContext,
|
||||||
|
|
|
@ -26,9 +26,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/admin/media_cleanup`,
|
url: `/api/v1/admin/media_cleanup`,
|
||||||
params: {
|
params: {
|
||||||
remote_cache_days: days
|
remote_cache_days: days,
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
instanceKeysExpire: build.mutation({
|
instanceKeysExpire: build.mutation({
|
||||||
|
@ -36,9 +36,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/admin/domain_keys_expire`,
|
url: `/api/v1/admin/domain_keys_expire`,
|
||||||
params: {
|
params: {
|
||||||
domain: domain
|
domain: domain,
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
sendTestEmail: build.mutation<any, { email: string, message?: string }>({
|
sendTestEmail: build.mutation<any, { email: string, message?: string }>({
|
||||||
|
@ -46,7 +46,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/admin/email/test`,
|
url: `/api/v1/admin/email/test`,
|
||||||
params: params,
|
params: params,
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { gtsApi } from "../../gts-api";
|
import { gtsApi } from "../../gts-api";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { RootState } from "../../../../redux/store";
|
import type { RootState } from "../../../../redux/store";
|
||||||
|
|
||||||
import type { CustomEmoji, EmojisFromItem, ListEmojiParams } from "../../../types/custom-emoji";
|
import type { CustomEmoji, EmojisFromItem, ListEmojiParams } from "../../../types/custom-emoji";
|
||||||
|
|
||||||
|
@ -77,39 +77,39 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: "/api/v1/admin/custom_emojis",
|
url: "/api/v1/admin/custom_emojis",
|
||||||
params: {
|
params: {
|
||||||
limit: 0,
|
limit: 0,
|
||||||
...params
|
...params,
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
providesTags: (res, _error, _arg) =>
|
providesTags: (res, _error, _arg) =>
|
||||||
res
|
res
|
||||||
? [
|
? [
|
||||||
...res.map((emoji) => ({ type: "Emoji" as const, id: emoji.id })),
|
...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>({
|
getEmoji: build.query<CustomEmoji, string>({
|
||||||
query: (id) => ({
|
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) => {
|
query: (form) => {
|
||||||
return {
|
return {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/admin/custom_emojis`,
|
url: `/api/v1/admin/custom_emojis`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: form,
|
body: form,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
invalidatesTags: (res) =>
|
invalidatesTags: (res) =>
|
||||||
res
|
res
|
||||||
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
|
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
|
||||||
: [{ type: "Emoji", id: "LIST" }]
|
: [{ type: "Emoji", id: "LIST" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
editEmoji: build.mutation<CustomEmoji, any>({
|
editEmoji: build.mutation<CustomEmoji, any>({
|
||||||
|
@ -120,22 +120,22 @@ const extended = gtsApi.injectEndpoints({
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: {
|
body: {
|
||||||
type: "modify",
|
type: "modify",
|
||||||
...patch
|
...patch,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
invalidatesTags: (res) =>
|
invalidatesTags: (res) =>
|
||||||
res
|
res
|
||||||
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
|
? [{ type: "Emoji", id: "LIST" }, { type: "Emoji", id: res.id }]
|
||||||
: [{ type: "Emoji", id: "LIST" }]
|
: [{ type: "Emoji", id: "LIST" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
deleteEmoji: build.mutation<any, string>({
|
deleteEmoji: build.mutation<any, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
method: "DELETE",
|
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>({
|
searchItemForEmoji: build.mutation<EmojisFromItem, string>({
|
||||||
|
@ -145,10 +145,10 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
// First search for given url.
|
// First search for given url.
|
||||||
const searchRes = await fetchWithBQ({
|
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) {
|
if (searchRes.error) {
|
||||||
return { error: searchRes.error as FetchBaseQueryError };
|
return { error: searchRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse initial results of search.
|
// Parse initial results of search.
|
||||||
|
@ -178,8 +178,8 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/custom_emojis`,
|
url: `/api/v1/admin/custom_emojis`,
|
||||||
params: {
|
params: {
|
||||||
filter: `domain:${domain},shortcode:${emoji.shortcode}`,
|
filter: `domain:${domain},shortcode:${emoji.shortcode}`,
|
||||||
limit: 1
|
limit: 1,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (emojiRes.error) {
|
if (emojiRes.error) {
|
||||||
|
@ -191,7 +191,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
// Got it!
|
// Got it!
|
||||||
return emojiRes.data as CustomEmoji;
|
return emojiRes.data as CustomEmoji;
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
).flatMap((emoji) => {
|
).flatMap((emoji) => {
|
||||||
// Remove any nulls.
|
// Remove any nulls.
|
||||||
|
@ -205,7 +205,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
status: 400,
|
status: 400,
|
||||||
statusText: 'Bad Request',
|
statusText: 'Bad Request',
|
||||||
data: {
|
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,
|
type,
|
||||||
domain,
|
domain,
|
||||||
list: withIDs,
|
list: withIDs,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
patchRemoteEmojis: build.mutation({
|
patchRemoteEmojis: build.mutation({
|
||||||
|
@ -231,7 +231,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
// Map function to get a promise
|
// Map function to get a promise
|
||||||
// of an emoji (or null).
|
// of an emoji (or null).
|
||||||
const copyEmoji = async(emoji: CustomEmoji) => {
|
const copyEmoji = async(emoji: CustomEmoji) => {
|
||||||
let body: {
|
const body: {
|
||||||
type: string;
|
type: string;
|
||||||
shortcode?: string;
|
shortcode?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
|
@ -285,7 +285,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
status: 400,
|
status: 400,
|
||||||
statusText: 'Bad Request',
|
statusText: 'Bad Request',
|
||||||
data: {
|
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 };
|
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/>.
|
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";
|
import { gtsApi } from "../../gts-api";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
|
@ -32,13 +32,13 @@ const extended = gtsApi.injectEndpoints({
|
||||||
return {
|
return {
|
||||||
url: `/api/v1/admin/debug/apurl?${urlParam.toString()}`,
|
url: `/api/v1/admin/debug/apurl?${urlParam.toString()}`,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
ClearCaches: build.mutation<{}, void>({
|
ClearCaches: build.mutation<{}, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
method: "POST",
|
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 { unparse as csvUnparse } from "papaparse";
|
||||||
|
|
||||||
import { gtsApi } from "../../gts-api";
|
import { gtsApi } from "../../gts-api";
|
||||||
import { RootState } from "../../../../redux/store";
|
import type { RootState } from "../../../../redux/store";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { DomainPerm, ExportDomainPermsParams } from "../../../types/domain-permission";
|
import type { DomainPerm, ExportDomainPermsParams } from "../../../types/domain-permission";
|
||||||
|
|
||||||
interface _exportProcess {
|
interface _exportProcess {
|
||||||
transformEntry: (_entry: DomainPerm) => any;
|
transformEntry: (_entry: DomainPerm) => any;
|
||||||
|
@ -45,11 +45,11 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
|
||||||
transformEntry: (entry) => ({
|
transformEntry: (entry) => ({
|
||||||
domain: entry.domain,
|
domain: entry.domain,
|
||||||
public_comment: entry.public_comment,
|
public_comment: entry.public_comment,
|
||||||
obfuscate: entry.obfuscate
|
obfuscate: entry.obfuscate,
|
||||||
}),
|
}),
|
||||||
stringify: (list) => JSON.stringify(list),
|
stringify: (list) => JSON.stringify(list),
|
||||||
extension: ".json",
|
extension: ".json",
|
||||||
mime: "application/json"
|
mime: "application/json",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
|
||||||
false, // reject_media
|
false, // reject_media
|
||||||
false, // reject_reports
|
false, // reject_reports
|
||||||
entry.public_comment ?? "", // public_comment
|
entry.public_comment ?? "", // public_comment
|
||||||
entry.obfuscate ?? false // obfuscate
|
entry.obfuscate ?? false, // obfuscate
|
||||||
],
|
],
|
||||||
stringify: (list) => csvUnparse({
|
stringify: (list) => csvUnparse({
|
||||||
fields: [
|
fields: [
|
||||||
|
@ -72,10 +72,10 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
|
||||||
"#public_comment",
|
"#public_comment",
|
||||||
"#obfuscate",
|
"#obfuscate",
|
||||||
],
|
],
|
||||||
data: list
|
data: list,
|
||||||
}),
|
}),
|
||||||
extension: ".csv",
|
extension: ".csv",
|
||||||
mime: "text/csv"
|
mime: "text/csv",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ function exportProcess(formData: ExportDomainPermsParams): _exportProcess {
|
||||||
transformEntry: (entry) => entry.domain,
|
transformEntry: (entry) => entry.domain,
|
||||||
stringify: (list) => list.join("\n"),
|
stringify: (list) => list.join("\n"),
|
||||||
extension: ".txt",
|
extension: ".txt",
|
||||||
mime: "text/plain"
|
mime: "text/plain",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
// we want the untransformed array version.
|
// we want the untransformed array version.
|
||||||
const permsRes = await fetchWithBQ({ url: `/api/v1/admin/domain_${formData.permType}s` });
|
const permsRes = await fetchWithBQ({ url: `/api/v1/admin/domain_${formData.permType}s` });
|
||||||
if (permsRes.error) {
|
if (permsRes.error) {
|
||||||
return { error: permsRes.error as FetchBaseQueryError };
|
return { error: permsRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process perms into desired export format.
|
// Process perms into desired export format.
|
||||||
|
@ -130,16 +130,16 @@ const extended = gtsApi.injectEndpoints({
|
||||||
fileDownload(
|
fileDownload(
|
||||||
exportAsString,
|
exportAsString,
|
||||||
filename + process.extension,
|
filename + process.extension,
|
||||||
process.mime
|
process.mime,
|
||||||
);
|
);
|
||||||
|
|
||||||
// js-file-download handles the
|
// js-file-download handles the
|
||||||
// nitty gritty for us, so we can
|
// nitty gritty for us, so we can
|
||||||
// just return null data.
|
// just return null data.
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,14 +26,14 @@ const extended = gtsApi.injectEndpoints({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
domainBlocks: build.query<MappedDomainPerms, void>({
|
domainBlocks: build.query<MappedDomainPerms, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/admin/domain_blocks`
|
url: `/api/v1/admin/domain_blocks`,
|
||||||
}),
|
}),
|
||||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
domainAllows: build.query<MappedDomainPerms, void>({
|
domainAllows: build.query<MappedDomainPerms, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/admin/domain_allows`
|
url: `/api/v1/admin/domain_allows`,
|
||||||
}),
|
}),
|
||||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -36,7 +36,7 @@ import { listToKeyedObject } from "../../transforms";
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: DomainPerm) => DomainPerm {
|
function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: DomainPerm) => DomainPerm {
|
||||||
let processingFuncs: { (_entry: DomainPerm): void; }[] = [];
|
const processingFuncs: { (_entry: DomainPerm): void; }[] = [];
|
||||||
|
|
||||||
// Override each obfuscate entry if necessary.
|
// Override each obfuscate entry if necessary.
|
||||||
if (formData.obfuscate !== undefined) {
|
if (formData.obfuscate !== undefined) {
|
||||||
|
@ -49,7 +49,7 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom
|
||||||
// Check whether we need to append or replace
|
// Check whether we need to append or replace
|
||||||
// private_comment and public_comment.
|
// private_comment and public_comment.
|
||||||
["private_comment","public_comment"].forEach((commentType) => {
|
["private_comment","public_comment"].forEach((commentType) => {
|
||||||
let text = formData.commentType?.trim();
|
const text = formData.commentType?.trim();
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,9 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom
|
||||||
|
|
||||||
return function process(entry) {
|
return function process(entry) {
|
||||||
// Call all the assembled processing functions.
|
// Call all the assembled processing functions.
|
||||||
processingFuncs.forEach((f) => f(entry));
|
processingFuncs.forEach((f) => {
|
||||||
|
f(entry);
|
||||||
|
});
|
||||||
|
|
||||||
// Unset all internal processing keys
|
// Unset all internal processing keys
|
||||||
// and any undefined keys on this entry.
|
// and any undefined keys on this entry.
|
||||||
|
@ -111,7 +113,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
[JSON.stringify(domains)],
|
[JSON.stringify(domains)],
|
||||||
{ type: "application/json" },
|
{ type: "application/json" },
|
||||||
),
|
),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||||
|
@ -125,8 +127,8 @@ const extended = gtsApi.injectEndpoints({
|
||||||
formData.permType.slice(1);
|
formData.permType.slice(1);
|
||||||
return `domain${permType}s`;
|
return `domain${permType}s`;
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ParseConfig as CSVParseConfig} from "papaparse";
|
||||||
import {
|
import {
|
||||||
ParseConfig as CSVParseConfig,
|
parse as csvParse,
|
||||||
parse as csvParse
|
|
||||||
} from "papaparse";
|
} from "papaparse";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ function parseDomainList(list: string): DomainPerm[] {
|
||||||
"reject_reports": true,
|
"reject_reports": true,
|
||||||
"public_comment": false,
|
"public_comment": false,
|
||||||
"obfuscate": true,
|
"obfuscate": true,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const { data, errors } = csvParse(list, csvParseCfg);
|
const { data, errors } = csvParse(list, csvParseCfg);
|
||||||
|
@ -119,7 +120,7 @@ function parseDomainList(list: string): DomainPerm[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
function deduplicateDomainList(list: DomainPerm[]): DomainPerm[] {
|
function deduplicateDomainList(list: DomainPerm[]): DomainPerm[] {
|
||||||
let domains = new Set();
|
const domains = new Set();
|
||||||
return list.filter((entry) => {
|
return list.filter((entry) => {
|
||||||
if (domains.has(entry.domain)) {
|
if (domains.has(entry.domain)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -168,9 +169,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data: validated };
|
return { data: validated };
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -26,7 +26,7 @@ import {
|
||||||
import { listToKeyedObject } from "../../transforms";
|
import { listToKeyedObject } from "../../transforms";
|
||||||
import type {
|
import type {
|
||||||
DomainPerm,
|
DomainPerm,
|
||||||
MappedDomainPerms
|
MappedDomainPerms,
|
||||||
} from "../../../types/domain-permission";
|
} from "../../../types/domain-permission";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
|
@ -37,7 +37,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/domain_blocks`,
|
url: `/api/v1/admin/domain_blocks`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||||
...replaceCacheOnMutation("domainBlocks"),
|
...replaceCacheOnMutation("domainBlocks"),
|
||||||
|
@ -49,10 +49,10 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/domain_allows`,
|
url: `/api/v1/admin/domain_allows`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||||
...replaceCacheOnMutation("domainAllows")
|
...replaceCacheOnMutation("domainAllows"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeDomainBlock: build.mutation<DomainPerm, string>({
|
removeDomainBlock: build.mutation<DomainPerm, string>({
|
||||||
|
@ -63,8 +63,8 @@ const extended = gtsApi.injectEndpoints({
|
||||||
...removeFromCacheOnMutation("domainBlocks", {
|
...removeFromCacheOnMutation("domainBlocks", {
|
||||||
key: (_draft, newData) => {
|
key: (_draft, newData) => {
|
||||||
return newData.domain;
|
return newData.domain;
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeDomainAllow: build.mutation<DomainPerm, string>({
|
removeDomainAllow: build.mutation<DomainPerm, string>({
|
||||||
|
@ -75,8 +75,8 @@ const extended = gtsApi.injectEndpoints({
|
||||||
...removeFromCacheOnMutation("domainAllows", {
|
...removeFromCacheOnMutation("domainAllows", {
|
||||||
key: (_draft, newData) => {
|
key: (_draft, newData) => {
|
||||||
return newData.domain;
|
return newData.domain;
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -105,5 +105,5 @@ export {
|
||||||
useAddDomainBlockMutation,
|
useAddDomainBlockMutation,
|
||||||
useAddDomainAllowMutation,
|
useAddDomainAllowMutation,
|
||||||
useRemoveDomainBlockMutation,
|
useRemoveDomainBlockMutation,
|
||||||
useRemoveDomainAllowMutation
|
useRemoveDomainAllowMutation,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { gtsApi } from "../../gts-api";
|
import { gtsApi } from "../../gts-api";
|
||||||
import { HeaderPermission } from "../../../types/http-header-permissions";
|
import type { HeaderPermission } from "../../../types/http-header-permissions";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
|
@ -27,7 +27,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
getHeaderAllows: build.query<HeaderPermission[], void>({
|
getHeaderAllows: build.query<HeaderPermission[], void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/admin/header_allows`
|
url: `/api/v1/admin/header_allows`,
|
||||||
}),
|
}),
|
||||||
providesTags: (res) =>
|
providesTags: (res) =>
|
||||||
res
|
res
|
||||||
|
@ -40,7 +40,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
getHeaderAllow: build.query<HeaderPermission, string>({
|
getHeaderAllow: build.query<HeaderPermission, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
url: `/api/v1/admin/header_allows/${id}`
|
url: `/api/v1/admin/header_allows/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
|
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
|
||||||
}),
|
}),
|
||||||
|
@ -51,7 +51,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/header_allows`,
|
url: `/api/v1/admin/header_allows`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
invalidatesTags: [{ type: "HTTPHeaderAllows", id: "LIST" }],
|
invalidatesTags: [{ type: "HTTPHeaderAllows", id: "LIST" }],
|
||||||
}),
|
}),
|
||||||
|
@ -59,7 +59,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
deleteHeaderAllow: build.mutation<HeaderPermission, string>({
|
deleteHeaderAllow: build.mutation<HeaderPermission, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/v1/admin/header_allows/${id}`
|
url: `/api/v1/admin/header_allows/${id}`,
|
||||||
}),
|
}),
|
||||||
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
|
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderAllows", id }],
|
||||||
}),
|
}),
|
||||||
|
@ -68,7 +68,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
getHeaderBlocks: build.query<HeaderPermission[], void>({
|
getHeaderBlocks: build.query<HeaderPermission[], void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/admin/header_blocks`
|
url: `/api/v1/admin/header_blocks`,
|
||||||
}),
|
}),
|
||||||
providesTags: (res) =>
|
providesTags: (res) =>
|
||||||
res
|
res
|
||||||
|
@ -85,14 +85,14 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/header_blocks`,
|
url: `/api/v1/admin/header_blocks`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
invalidatesTags: [{ type: "HTTPHeaderBlocks", id: "LIST" }],
|
invalidatesTags: [{ type: "HTTPHeaderBlocks", id: "LIST" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getHeaderBlock: build.query<HeaderPermission, string>({
|
getHeaderBlock: build.query<HeaderPermission, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
url: `/api/v1/admin/header_blocks/${id}`
|
url: `/api/v1/admin/header_blocks/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
|
providesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
|
||||||
}),
|
}),
|
||||||
|
@ -100,7 +100,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
deleteHeaderBlock: build.mutation<HeaderPermission, string>({
|
deleteHeaderBlock: build.mutation<HeaderPermission, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/v1/admin/header_blocks/${id}`
|
url: `/api/v1/admin/header_blocks/${id}`,
|
||||||
}),
|
}),
|
||||||
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
|
invalidatesTags: (_res, _error, id) => [{ type: "HTTPHeaderBlocks", id }],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
import { replaceCacheOnMutation, removeFromCacheOnMutation } from "../query-modifiers";
|
import { replaceCacheOnMutation, removeFromCacheOnMutation } from "../query-modifiers";
|
||||||
import { gtsApi } from "../gts-api";
|
import { gtsApi } from "../gts-api";
|
||||||
import { listToKeyedObject } from "../transforms";
|
import { listToKeyedObject } from "../transforms";
|
||||||
import { ActionAccountParams, AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account";
|
import type { ActionAccountParams, AdminAccount, HandleSignupParams, SearchAccountParams, SearchAccountResp } from "../../types/account";
|
||||||
import { InstanceRule, MappedRules } from "../../types/rules";
|
import type { InstanceRule, MappedRules } from "../../types/rules";
|
||||||
import parse from "parse-link-header";
|
import parse from "parse-link-header";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
|
@ -32,17 +32,17 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/instance`,
|
url: `/api/v1/instance`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
...replaceCacheOnMutation("instanceV1"),
|
...replaceCacheOnMutation("instanceV1"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getAccount: build.query<AdminAccount, string>({
|
getAccount: build.query<AdminAccount, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
url: `/api/v1/admin/accounts/${id}`
|
url: `/api/v1/admin/accounts/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: (_result, _error, id) => [
|
providesTags: (_result, _error, id) => [
|
||||||
{ type: 'Account', id }
|
{ type: 'Account', id },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: `/api/v2/admin/accounts${query}`
|
url: `/api/v2/admin/accounts${query}`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Headers required for paging.
|
// Headers required for paging.
|
||||||
|
@ -73,7 +73,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
},
|
},
|
||||||
// Only provide LIST tag id since this model is not the
|
// Only provide LIST tag id since this model is not the
|
||||||
// same as getAccount model (due to transformResponse).
|
// same as getAccount model (due to transformResponse).
|
||||||
providesTags: [{ type: "Account", id: "TRANSFORMED" }]
|
providesTags: [{ type: "Account", id: "TRANSFORMED" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actionAccount: build.mutation<string, ActionAccountParams>({
|
actionAccount: build.mutation<string, ActionAccountParams>({
|
||||||
|
@ -83,8 +83,8 @@ const extended = gtsApi.injectEndpoints({
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: {
|
body: {
|
||||||
type: action,
|
type: action,
|
||||||
text: reason
|
text: reason,
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
// Do an optimistic update on this account to mark
|
// Do an optimistic update on this account to mark
|
||||||
// it according to whatever action was submitted.
|
// it according to whatever action was submitted.
|
||||||
|
@ -95,7 +95,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
draft.suspended = true;
|
draft.suspended = true;
|
||||||
draft.account.suspended = true;
|
draft.account.suspended = true;
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Revert optimistic
|
// Revert optimistic
|
||||||
|
@ -105,7 +105,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
} catch {
|
} catch {
|
||||||
patchResult.undo();
|
patchResult.undo();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
handleSignup: build.mutation<AdminAccount, HandleSignupParams>({
|
handleSignup: build.mutation<AdminAccount, HandleSignupParams>({
|
||||||
|
@ -124,7 +124,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
// Just invalidate this ID and getAccounts.
|
// Just invalidate this ID and getAccounts.
|
||||||
dispatch(extended.util.invalidateTags([
|
dispatch(extended.util.invalidateTags([
|
||||||
{ type: "Account", id: id },
|
{ type: "Account", id: id },
|
||||||
{ type: "Account", id: "TRANSFORMED" }
|
{ type: "Account", id: "TRANSFORMED" },
|
||||||
]));
|
]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
const patchResult = dispatch(
|
const patchResult = dispatch(
|
||||||
extended.util.updateQueryData("getAccount", id, (draft) => {
|
extended.util.updateQueryData("getAccount", id, (draft) => {
|
||||||
draft.approved = true;
|
draft.approved = true;
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Revert optimistic
|
// Revert optimistic
|
||||||
|
@ -142,14 +142,14 @@ const extended = gtsApi.injectEndpoints({
|
||||||
} catch {
|
} catch {
|
||||||
patchResult.undo();
|
patchResult.undo();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
instanceRules: build.query<MappedRules, void>({
|
instanceRules: build.query<MappedRules, void>({
|
||||||
query: () => ({
|
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>({
|
addInstanceRule: build.mutation<MappedRules, any>({
|
||||||
|
@ -158,7 +158,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/instance/rules`,
|
url: `/api/v1/admin/instance/rules`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
transformResponse: listToKeyedObject<InstanceRule>("id"),
|
transformResponse: listToKeyedObject<InstanceRule>("id"),
|
||||||
...replaceCacheOnMutation("instanceRules"),
|
...replaceCacheOnMutation("instanceRules"),
|
||||||
|
@ -170,11 +170,11 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/admin/instance/rules/${id}`,
|
url: `/api/v1/admin/instance/rules/${id}`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: edit,
|
body: edit,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
transformResponse: (data) => {
|
transformResponse: (data) => {
|
||||||
return {
|
return {
|
||||||
[data.id]: data
|
[data.id]: data,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
...replaceCacheOnMutation("instanceRules"),
|
...replaceCacheOnMutation("instanceRules"),
|
||||||
|
@ -183,13 +183,13 @@ const extended = gtsApi.injectEndpoints({
|
||||||
deleteInstanceRule: build.mutation({
|
deleteInstanceRule: build.mutation({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: `/api/v1/admin/instance/rules/${id}`
|
url: `/api/v1/admin/instance/rules/${id}`,
|
||||||
}),
|
}),
|
||||||
...removeFromCacheOnMutation("instanceRules", {
|
...removeFromCacheOnMutation("instanceRules", {
|
||||||
key: (_draft, rule) => rule.id,
|
key: (_draft, rule) => rule.id,
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -44,7 +44,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: `/api/v1/admin/reports${query}`
|
url: `/api/v1/admin/reports${query}`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Headers required for paging.
|
// Headers required for paging.
|
||||||
|
@ -56,15 +56,15 @@ const extended = gtsApi.injectEndpoints({
|
||||||
},
|
},
|
||||||
// Only provide LIST tag id since this model is not the
|
// Only provide LIST tag id since this model is not the
|
||||||
// same as getReport model (due to transformResponse).
|
// same as getReport model (due to transformResponse).
|
||||||
providesTags: [{ type: "Report", id: "TRANSFORMED" }]
|
providesTags: [{ type: "Report", id: "TRANSFORMED" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getReport: build.query<AdminReport, string>({
|
getReport: build.query<AdminReport, string>({
|
||||||
query: (id) => ({
|
query: (id) => ({
|
||||||
url: `/api/v1/admin/reports/${id}`
|
url: `/api/v1/admin/reports/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: (_result, _error, 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`,
|
url: `/api/v1/admin/reports/${formData.id}/resolve`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData
|
body: formData,
|
||||||
}),
|
}),
|
||||||
invalidatesTags: (res) =>
|
invalidatesTags: (res) =>
|
||||||
res
|
res
|
||||||
? [{ type: "Report", id: "TRANSFORMED" }, { type: "Report", id: res.id }]
|
? [{ 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 { serialize as serializeForm } from "object-to-formdata";
|
||||||
import type { FetchBaseQueryMeta } from "@reduxjs/toolkit/dist/query/fetchBaseQuery";
|
import type { FetchBaseQueryMeta } from "@reduxjs/toolkit/dist/query/fetchBaseQuery";
|
||||||
import type { RootState } from '../../redux/store';
|
import type { RootState } from '../../redux/store';
|
||||||
import { InstanceV1 } from '../types/instance';
|
import type { InstanceV1 } from '../types/instance';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GTSFetchArgs extends standard FetchArgs used by
|
* GTSFetchArgs extends standard FetchArgs used by
|
||||||
|
@ -173,10 +173,10 @@ export const gtsApi = createApi({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
instanceV1: build.query<InstanceV1, void>({
|
instanceV1: build.query<InstanceV1, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/instance`
|
url: `/api/v1/instance`,
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,8 +25,8 @@ import {
|
||||||
remove as oauthRemove,
|
remove as oauthRemove,
|
||||||
authorize as oauthAuthorize,
|
authorize as oauthAuthorize,
|
||||||
} from "../../../redux/oauth";
|
} from "../../../redux/oauth";
|
||||||
import { RootState } from '../../../redux/store';
|
import type { RootState } from '../../../redux/store';
|
||||||
import { Account } from '../../types/account';
|
import type { Account } from '../../types/account';
|
||||||
|
|
||||||
export interface OauthTokenRequestBody {
|
export interface OauthTokenRequestBody {
|
||||||
client_id: string;
|
client_id: string;
|
||||||
|
@ -45,7 +45,7 @@ function getSettingsURL() {
|
||||||
Also drops anything past /settings/, because authorization urls that are too long
|
Also drops anything past /settings/, because authorization urls that are too long
|
||||||
get rejected by GTS.
|
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`;
|
return `${window.location.origin}${pre}/settings`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,14 +71,14 @@ const extended = gtsApi.injectEndpoints({
|
||||||
// return a standard verify_credentials query.
|
// return a standard verify_credentials query.
|
||||||
if (oauthState.loginState != 'callback') {
|
if (oauthState.loginState != 'callback') {
|
||||||
return fetchWithBQ({
|
return fetchWithBQ({
|
||||||
url: `/api/v1/accounts/verify_credentials`
|
url: `/api/v1/accounts/verify_credentials`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're in the middle of an auth/callback flow.
|
// We're in the middle of an auth/callback flow.
|
||||||
// Try to retrieve callback code from URL query.
|
// Try to retrieve callback code from URL query.
|
||||||
let urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
let code = urlParams.get("code");
|
const code = urlParams.get("code");
|
||||||
if (code == undefined) {
|
if (code == undefined) {
|
||||||
return {
|
return {
|
||||||
error: {
|
error: {
|
||||||
|
@ -91,7 +91,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
// Retrieve app with which the
|
// Retrieve app with which the
|
||||||
// callback code was generated.
|
// callback code was generated.
|
||||||
let app = oauthState.app;
|
const app = oauthState.app;
|
||||||
if (app == undefined || app.client_id == undefined) {
|
if (app == undefined || app.client_id == undefined) {
|
||||||
return {
|
return {
|
||||||
error: {
|
error: {
|
||||||
|
@ -109,7 +109,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
client_secret: app.client_secret,
|
client_secret: app.client_secret,
|
||||||
redirect_uri: SETTINGS_URL,
|
redirect_uri: SETTINGS_URL,
|
||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
code: code
|
code: code,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tokenResult = await fetchWithBQ({
|
const tokenResult = await fetchWithBQ({
|
||||||
|
@ -118,7 +118,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
body: tokenReqBody,
|
body: tokenReqBody,
|
||||||
});
|
});
|
||||||
if (tokenResult.error) {
|
if (tokenResult.error) {
|
||||||
return { error: tokenResult.error as FetchBaseQueryError };
|
return { error: tokenResult.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove ?code= query param from
|
// Remove ?code= query param from
|
||||||
|
@ -131,9 +131,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
// We're now authed! So return
|
// We're now authed! So return
|
||||||
// standard verify_credentials query.
|
// standard verify_credentials query.
|
||||||
return fetchWithBQ({
|
return fetchWithBQ({
|
||||||
url: `/api/v1/accounts/verify_credentials`
|
url: `/api/v1/accounts/verify_credentials`,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
authorizeFlow: build.mutation({
|
authorizeFlow: build.mutation({
|
||||||
|
@ -147,7 +147,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceUrl = new URL(formData.instance).origin;
|
instanceUrl = new URL(formData.instance).origin;
|
||||||
if (oauthState?.instanceUrl == instanceUrl && oauthState.app) {
|
if (oauthState.instanceUrl == instanceUrl && oauthState.app) {
|
||||||
return { data: oauthState.app };
|
return { data: oauthState.app };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,31 +159,31 @@ const extended = gtsApi.injectEndpoints({
|
||||||
client_name: "GoToSocial Settings",
|
client_name: "GoToSocial Settings",
|
||||||
scopes: formData.scopes,
|
scopes: formData.scopes,
|
||||||
redirect_uris: SETTINGS_URL,
|
redirect_uris: SETTINGS_URL,
|
||||||
website: SETTINGS_URL
|
website: SETTINGS_URL,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
if (appResult.error) {
|
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;
|
app.scopes = formData.scopes;
|
||||||
api.dispatch(oauthAuthorize({
|
api.dispatch(oauthAuthorize({
|
||||||
instanceUrl: instanceUrl,
|
instanceUrl: instanceUrl,
|
||||||
app: app,
|
app: app,
|
||||||
loginState: "callback",
|
loginState: "callback",
|
||||||
expectingRedirect: true
|
expectingRedirect: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let url = new URL(instanceUrl);
|
const url = new URL(instanceUrl);
|
||||||
url.pathname = "/oauth/authorize";
|
url.pathname = "/oauth/authorize";
|
||||||
url.searchParams.set("client_id", app.client_id);
|
url.searchParams.set("client_id", app.client_id);
|
||||||
url.searchParams.set("redirect_uri", SETTINGS_URL);
|
url.searchParams.set("redirect_uri", SETTINGS_URL);
|
||||||
url.searchParams.set("response_type", "code");
|
url.searchParams.set("response_type", "code");
|
||||||
url.searchParams.set("scope", app.scopes);
|
url.searchParams.set("scope", app.scopes);
|
||||||
|
|
||||||
let redirectURL = url.toString();
|
const redirectURL = url.toString();
|
||||||
window.location.assign(redirectURL);
|
window.location.assign(redirectURL);
|
||||||
return { data: null };
|
return { data: null };
|
||||||
},
|
},
|
||||||
|
@ -193,9 +193,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
api.dispatch(oauthRemove());
|
api.dispatch(oauthRemove());
|
||||||
return { data: null };
|
return { data: null };
|
||||||
},
|
},
|
||||||
invalidatesTags: ["Auth"]
|
invalidatesTags: ["Auth"],
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -86,13 +86,13 @@ function makeCacheMutation(action: Action): CacheMutation {
|
||||||
key = key(draft, newData);
|
key = key(draft, newData);
|
||||||
}
|
}
|
||||||
action(draft, newData, { key });
|
action(draft, newData, { key });
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(`rolling back pessimistic update of ${queryName}: ${JSON.stringify(e)}`);
|
console.error(`rolling back pessimistic update of ${queryName}: ${JSON.stringify(e)}`);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,15 @@
|
||||||
import fileDownload from "js-file-download";
|
import fileDownload from "js-file-download";
|
||||||
|
|
||||||
import { gtsApi } from "../gts-api";
|
import { gtsApi } from "../gts-api";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { AccountExportStats } from "../../types/account";
|
import type { AccountExportStats } from "../../types/account";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
exportStats: build.query<AccountExportStats, void>({
|
exportStats: build.query<AccountExportStats, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/exports/stats`
|
url: `/api/v1/exports/stats`,
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
exportFollowing: build.mutation<string | null, void>({
|
exportFollowing: build.mutation<string | null, void>({
|
||||||
|
@ -38,7 +38,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
acceptContentType: "text/csv",
|
acceptContentType: "text/csv",
|
||||||
});
|
});
|
||||||
if (csvRes.error) {
|
if (csvRes.error) {
|
||||||
return { error: csvRes.error as FetchBaseQueryError };
|
return { error: csvRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csvRes.meta?.response?.status !== 200) {
|
if (csvRes.meta?.response?.status !== 200) {
|
||||||
|
@ -47,7 +47,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
fileDownload(csvRes.data, "following.csv", "text/csv");
|
fileDownload(csvRes.data, "following.csv", "text/csv");
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
exportFollowers: build.mutation<string | null, void>({
|
exportFollowers: build.mutation<string | null, void>({
|
||||||
|
@ -57,7 +57,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
acceptContentType: "text/csv",
|
acceptContentType: "text/csv",
|
||||||
});
|
});
|
||||||
if (csvRes.error) {
|
if (csvRes.error) {
|
||||||
return { error: csvRes.error as FetchBaseQueryError };
|
return { error: csvRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csvRes.meta?.response?.status !== 200) {
|
if (csvRes.meta?.response?.status !== 200) {
|
||||||
|
@ -66,7 +66,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
fileDownload(csvRes.data, "followers.csv", "text/csv");
|
fileDownload(csvRes.data, "followers.csv", "text/csv");
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
exportLists: build.mutation<string | null, void>({
|
exportLists: build.mutation<string | null, void>({
|
||||||
|
@ -76,7 +76,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
acceptContentType: "text/csv",
|
acceptContentType: "text/csv",
|
||||||
});
|
});
|
||||||
if (csvRes.error) {
|
if (csvRes.error) {
|
||||||
return { error: csvRes.error as FetchBaseQueryError };
|
return { error: csvRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csvRes.meta?.response?.status !== 200) {
|
if (csvRes.meta?.response?.status !== 200) {
|
||||||
|
@ -85,7 +85,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
fileDownload(csvRes.data, "lists.csv", "text/csv");
|
fileDownload(csvRes.data, "lists.csv", "text/csv");
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
exportBlocks: build.mutation<string | null, void>({
|
exportBlocks: build.mutation<string | null, void>({
|
||||||
|
@ -95,7 +95,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
acceptContentType: "text/csv",
|
acceptContentType: "text/csv",
|
||||||
});
|
});
|
||||||
if (csvRes.error) {
|
if (csvRes.error) {
|
||||||
return { error: csvRes.error as FetchBaseQueryError };
|
return { error: csvRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csvRes.meta?.response?.status !== 200) {
|
if (csvRes.meta?.response?.status !== 200) {
|
||||||
|
@ -104,7 +104,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
fileDownload(csvRes.data, "blocks.csv", "text/csv");
|
fileDownload(csvRes.data, "blocks.csv", "text/csv");
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
exportMutes: build.mutation<string | null, void>({
|
exportMutes: build.mutation<string | null, void>({
|
||||||
|
@ -114,7 +114,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
acceptContentType: "text/csv",
|
acceptContentType: "text/csv",
|
||||||
});
|
});
|
||||||
if (csvRes.error) {
|
if (csvRes.error) {
|
||||||
return { error: csvRes.error as FetchBaseQueryError };
|
return { error: csvRes.error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csvRes.meta?.response?.status !== 200) {
|
if (csvRes.meta?.response?.status !== 200) {
|
||||||
|
@ -123,7 +123,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
|
|
||||||
fileDownload(csvRes.data, "mutes.csv", "text/csv");
|
fileDownload(csvRes.data, "mutes.csv", "text/csv");
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
importData: build.mutation({
|
importData: build.mutation({
|
||||||
|
@ -132,10 +132,10 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/import`,
|
url: `/api/v1/import`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -21,11 +21,11 @@ import { replaceCacheOnMutation } from "../query-modifiers";
|
||||||
import { gtsApi } from "../gts-api";
|
import { gtsApi } from "../gts-api";
|
||||||
import type {
|
import type {
|
||||||
MoveAccountFormData,
|
MoveAccountFormData,
|
||||||
UpdateAliasesFormData
|
UpdateAliasesFormData,
|
||||||
} from "../../types/migration";
|
} from "../../types/migration";
|
||||||
import type { Theme } from "../../types/theme";
|
import type { Theme } from "../../types/theme";
|
||||||
import { User } from "../../types/user";
|
import type { User } from "../../types/user";
|
||||||
import { DefaultInteractionPolicies, UpdateDefaultInteractionPolicies } from "../../types/interaction";
|
import type { DefaultInteractionPolicies, UpdateDefaultInteractionPolicies } from "../../types/interaction";
|
||||||
|
|
||||||
const extended = gtsApi.injectEndpoints({
|
const extended = gtsApi.injectEndpoints({
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
|
@ -35,36 +35,36 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/accounts/update_credentials`,
|
url: `/api/v1/accounts/update_credentials`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: formData,
|
body: formData,
|
||||||
discardEmpty: true
|
discardEmpty: true,
|
||||||
}),
|
}),
|
||||||
...replaceCacheOnMutation("verifyCredentials")
|
...replaceCacheOnMutation("verifyCredentials"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
user: build.query<User, void>({
|
user: build.query<User, void>({
|
||||||
query: () => ({url: `/api/v1/user`})
|
query: () => ({url: `/api/v1/user`}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
passwordChange: build.mutation({
|
passwordChange: build.mutation({
|
||||||
query: (data) => ({
|
query: (data) => ({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/user/password_change`,
|
url: `/api/v1/user/password_change`,
|
||||||
body: data
|
body: data,
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
emailChange: build.mutation<User, { password: string, new_email: string }>({
|
emailChange: build.mutation<User, { password: string, new_email: string }>({
|
||||||
query: (data) => ({
|
query: (data) => ({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/user/email_change`,
|
url: `/api/v1/user/email_change`,
|
||||||
body: data
|
body: data,
|
||||||
}),
|
}),
|
||||||
...replaceCacheOnMutation("user")
|
...replaceCacheOnMutation("user"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
aliasAccount: build.mutation<any, UpdateAliasesFormData>({
|
aliasAccount: build.mutation<any, UpdateAliasesFormData>({
|
||||||
async queryFn(formData, _api, _extraOpts, fetchWithBQ) {
|
async queryFn(formData, _api, _extraOpts, fetchWithBQ) {
|
||||||
// Pull entries out from the hooked form.
|
// Pull entries out from the hooked form.
|
||||||
const entries: String[] = [];
|
const entries: string[] = [];
|
||||||
formData.also_known_as_uris.forEach(entry => {
|
formData.also_known_as_uris.forEach(entry => {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
|
@ -76,28 +76,28 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/accounts/alias`,
|
url: `/api/v1/accounts/alias`,
|
||||||
body: { also_known_as_uris: entries },
|
body: { also_known_as_uris: entries },
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
moveAccount: build.mutation<any, MoveAccountFormData>({
|
moveAccount: build.mutation<any, MoveAccountFormData>({
|
||||||
query: (data) => ({
|
query: (data) => ({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/accounts/move`,
|
url: `/api/v1/accounts/move`,
|
||||||
body: data
|
body: data,
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
accountThemes: build.query<Theme[], void>({
|
accountThemes: build.query<Theme[], void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/accounts/themes`
|
url: `/api/v1/accounts/themes`,
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultInteractionPolicies: build.query<DefaultInteractionPolicies, void>({
|
defaultInteractionPolicies: build.query<DefaultInteractionPolicies, void>({
|
||||||
query: () => ({
|
query: () => ({
|
||||||
url: `/api/v1/interaction_policies/defaults`
|
url: `/api/v1/interaction_policies/defaults`,
|
||||||
}),
|
}),
|
||||||
providesTags: ["DefaultInteractionPolicies"]
|
providesTags: ["DefaultInteractionPolicies"],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
updateDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, UpdateDefaultInteractionPolicies>({
|
updateDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, UpdateDefaultInteractionPolicies>({
|
||||||
|
@ -106,7 +106,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/interaction_policies/defaults`,
|
url: `/api/v1/interaction_policies/defaults`,
|
||||||
body: data,
|
body: data,
|
||||||
}),
|
}),
|
||||||
...replaceCacheOnMutation("defaultInteractionPolicies")
|
...replaceCacheOnMutation("defaultInteractionPolicies"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
resetDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, void>({
|
resetDefaultInteractionPolicies: build.mutation<DefaultInteractionPolicies, void>({
|
||||||
|
@ -115,9 +115,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/interaction_policies/defaults`,
|
url: `/api/v1/interaction_policies/defaults`,
|
||||||
body: {},
|
body: {},
|
||||||
}),
|
}),
|
||||||
invalidatesTags: ["DefaultInteractionPolicies"]
|
invalidatesTags: ["DefaultInteractionPolicies"],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import type {
|
||||||
InteractionRequest,
|
InteractionRequest,
|
||||||
SearchInteractionRequestsParams,
|
SearchInteractionRequestsParams,
|
||||||
SearchInteractionRequestsResp,
|
SearchInteractionRequestsResp,
|
||||||
|
@ -33,7 +33,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
url: `/api/v1/interaction_requests/${id}`,
|
url: `/api/v1/interaction_requests/${id}`,
|
||||||
}),
|
}),
|
||||||
providesTags: (_result, _error, id) => [
|
providesTags: (_result, _error, id) => [
|
||||||
{ type: 'InteractionRequest', id }
|
{ type: 'InteractionRequest', id },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: `/api/v1/interaction_requests${query}`
|
url: `/api/v1/interaction_requests${query}`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Headers required for paging.
|
// Headers required for paging.
|
||||||
|
@ -62,7 +62,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
const links = parse(linksStr);
|
const links = parse(linksStr);
|
||||||
return { requests, links };
|
return { requests, links };
|
||||||
},
|
},
|
||||||
providesTags: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
|
providesTags: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
approveInteractionRequest: build.mutation<InteractionRequest, string>({
|
approveInteractionRequest: build.mutation<InteractionRequest, string>({
|
||||||
|
@ -73,7 +73,7 @@ const extended = gtsApi.injectEndpoints({
|
||||||
invalidatesTags: (res) =>
|
invalidatesTags: (res) =>
|
||||||
res
|
res
|
||||||
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
|
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
|
||||||
: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
|
: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
rejectInteractionRequest: build.mutation<any, string>({
|
rejectInteractionRequest: build.mutation<any, string>({
|
||||||
|
@ -84,9 +84,9 @@ const extended = gtsApi.injectEndpoints({
|
||||||
invalidatesTags: (res) =>
|
invalidatesTags: (res) =>
|
||||||
res
|
res
|
||||||
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
|
? [{ type: "InteractionRequest", id: "TRANSFORMED" }, { type: "InteractionRequest", id: res.id }]
|
||||||
: [{ type: "InteractionRequest", id: "TRANSFORMED" }]
|
: [{ type: "InteractionRequest", id: "TRANSFORMED" }],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Links } from "parse-link-header";
|
import type { Links } from "parse-link-header";
|
||||||
import { CustomEmoji } from "./custom-emoji";
|
import type { CustomEmoji } from "./custom-emoji";
|
||||||
|
|
||||||
export interface AdminAccount {
|
export interface AdminAccount {
|
||||||
id: string,
|
id: string,
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import typia from "typia";
|
import typia from "typia";
|
||||||
import { PermType } from "./perm";
|
import type { PermType } from "./perm";
|
||||||
|
|
||||||
export const validateDomainPerms = typia.createValidate<DomainPerm[]>();
|
export const validateDomainPerms = typia.createValidate<DomainPerm[]>();
|
||||||
|
|
||||||
|
|
|
@ -18,80 +18,80 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface InstanceV1 {
|
export interface InstanceV1 {
|
||||||
uri: string;
|
uri: string;
|
||||||
account_domain: string;
|
account_domain: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
description_text?: string;
|
description_text?: string;
|
||||||
short_description: string;
|
short_description: string;
|
||||||
short_description_text?: string;
|
short_description_text?: string;
|
||||||
email: string;
|
email: string;
|
||||||
version: string;
|
version: string;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
languages: any[]; // TODO: define this
|
languages: any[]; // TODO: define this
|
||||||
registrations: boolean;
|
registrations: boolean;
|
||||||
approval_required: boolean;
|
approval_required: boolean;
|
||||||
invites_enabled: boolean;
|
invites_enabled: boolean;
|
||||||
configuration: InstanceConfiguration;
|
configuration: InstanceConfiguration;
|
||||||
urls: InstanceUrls;
|
urls: InstanceUrls;
|
||||||
stats: InstanceStats;
|
stats: InstanceStats;
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
contact_account: Object; // TODO: define this.
|
contact_account: object; // TODO: define this.
|
||||||
max_toot_chars: number;
|
max_toot_chars: number;
|
||||||
rules: any[]; // TODO: define this
|
rules: any[]; // TODO: define this
|
||||||
terms?: string;
|
terms?: string;
|
||||||
terms_text?: string;
|
terms_text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceConfiguration {
|
export interface InstanceConfiguration {
|
||||||
statuses: InstanceStatuses;
|
statuses: InstanceStatuses;
|
||||||
media_attachments: InstanceMediaAttachments;
|
media_attachments: InstanceMediaAttachments;
|
||||||
polls: InstancePolls;
|
polls: InstancePolls;
|
||||||
accounts: InstanceAccounts;
|
accounts: InstanceAccounts;
|
||||||
emojis: InstanceEmojis;
|
emojis: InstanceEmojis;
|
||||||
oidc_enabled?: boolean;
|
oidc_enabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceAccounts {
|
export interface InstanceAccounts {
|
||||||
allow_custom_css: boolean;
|
allow_custom_css: boolean;
|
||||||
max_featured_tags: number;
|
max_featured_tags: number;
|
||||||
max_profile_fields: number;
|
max_profile_fields: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceEmojis {
|
export interface InstanceEmojis {
|
||||||
emoji_size_limit: number;
|
emoji_size_limit: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceMediaAttachments {
|
export interface InstanceMediaAttachments {
|
||||||
supported_mime_types: string[];
|
supported_mime_types: string[];
|
||||||
image_size_limit: number;
|
image_size_limit: number;
|
||||||
image_matrix_limit: number;
|
image_matrix_limit: number;
|
||||||
video_size_limit: number;
|
video_size_limit: number;
|
||||||
video_frame_rate_limit: number;
|
video_frame_rate_limit: number;
|
||||||
video_matrix_limit: number;
|
video_matrix_limit: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstancePolls {
|
export interface InstancePolls {
|
||||||
max_options: number;
|
max_options: number;
|
||||||
max_characters_per_option: number;
|
max_characters_per_option: number;
|
||||||
min_expiration: number;
|
min_expiration: number;
|
||||||
max_expiration: number;
|
max_expiration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceStatuses {
|
export interface InstanceStatuses {
|
||||||
max_characters: number;
|
max_characters: number;
|
||||||
max_media_attachments: number;
|
max_media_attachments: number;
|
||||||
characters_reserved_per_url: number;
|
characters_reserved_per_url: number;
|
||||||
supported_mime_types: string[];
|
supported_mime_types: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceStats {
|
export interface InstanceStats {
|
||||||
domain_count: number;
|
domain_count: number;
|
||||||
status_count: number;
|
status_count: number;
|
||||||
user_count: number;
|
user_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceUrls {
|
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/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Links } from "parse-link-header";
|
import type { Links } from "parse-link-header";
|
||||||
import { Account } from "./account";
|
import type { Account } from "./account";
|
||||||
import { Status } from "./status";
|
import type { Status } from "./status";
|
||||||
|
|
||||||
export interface DefaultInteractionPolicies {
|
export interface DefaultInteractionPolicies {
|
||||||
direct: InteractionPolicy;
|
direct: InteractionPolicy;
|
||||||
|
@ -71,7 +71,7 @@ export {
|
||||||
* Interaction request targeting a status by an account.
|
* Interaction request targeting a status by an account.
|
||||||
*/
|
*/
|
||||||
export interface InteractionRequest {
|
export interface InteractionRequest {
|
||||||
/**
|
/**
|
||||||
* ID of the request.
|
* ID of the request.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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
|
* Pass into a query when you don't
|
||||||
|
@ -46,25 +46,25 @@ interface MutationStartedParams {
|
||||||
/**
|
/**
|
||||||
* A method to get the current state for the store.
|
* A method to get the current state for the store.
|
||||||
*/
|
*/
|
||||||
getState,
|
getState,
|
||||||
/**
|
/**
|
||||||
* extra as provided as thunk.extraArgument to the configureStore getDefaultMiddleware option.
|
* extra as provided as thunk.extraArgument to the configureStore getDefaultMiddleware option.
|
||||||
*/
|
*/
|
||||||
extra,
|
extra,
|
||||||
/**
|
/**
|
||||||
* A unique ID generated for the query/mutation.
|
* 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
|
* 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
|
* 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.
|
* 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.
|
* A function that gets the current value of the cache entry.
|
||||||
*/
|
*/
|
||||||
getCacheEntry,
|
getCacheEntry,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Action = (
|
export type Action = (
|
||||||
|
|
|
@ -17,16 +17,16 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Links } from "parse-link-header";
|
import type { Links } from "parse-link-header";
|
||||||
import { AdminAccount } from "./account";
|
import type { AdminAccount } from "./account";
|
||||||
import { Status } from "./status";
|
import type { Status } from "./status";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Admin model of a report. Differs from the client
|
* Admin model of a report. Differs from the client
|
||||||
* model, which contains less detailed information.
|
* model, which contains less detailed information.
|
||||||
*/
|
*/
|
||||||
export interface AdminReport {
|
export interface AdminReport {
|
||||||
/**
|
/**
|
||||||
* ID of the report.
|
* ID of the report.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -83,7 +83,7 @@ export interface AdminReport {
|
||||||
* Rules broken according to the reporter, if any.
|
* Rules broken according to the reporter, if any.
|
||||||
* TODO: model this properly.
|
* TODO: model this properly.
|
||||||
*/
|
*/
|
||||||
rules: Object[];
|
rules: object[];
|
||||||
/**
|
/**
|
||||||
* Comment stored about what action (if any) was taken.
|
* 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.
|
* Parameters for POST to /api/v1/admin/reports/{id}/resolve.
|
||||||
*/
|
*/
|
||||||
export interface AdminReportResolveParams {
|
export interface AdminReportResolveParams {
|
||||||
/**
|
/**
|
||||||
* The ID of the report to resolve.
|
* The ID of the report to resolve.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Account } from "./account";
|
import type { Account } from "./account";
|
||||||
import { CustomEmoji } from "./custom-emoji";
|
import type { CustomEmoji } from "./custom-emoji";
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { get } from "psl";
|
||||||
export function isValidDomainPermission(domain: string): boolean {
|
export function isValidDomainPermission(domain: string): boolean {
|
||||||
return isValidDomain(domain, {
|
return isValidDomain(domain, {
|
||||||
wildcard: false,
|
wildcard: false,
|
||||||
allowUnicode: true
|
allowUnicode: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { AdminAccount } from "../types/account";
|
import type { AdminAccount } from "../types/account";
|
||||||
import { store } from "../../redux/store";
|
import { store } from "../../redux/store";
|
||||||
|
|
||||||
export function yesOrNo(b: boolean): string {
|
export function yesOrNo(b: boolean): string {
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 type { Checkable } from "../lib/form/types";
|
||||||
import { useReducer } from "react";
|
import { useReducer } from "react";
|
||||||
|
|
||||||
|
@ -57,12 +58,12 @@ function initialHookState({
|
||||||
}
|
}
|
||||||
|
|
||||||
return [ key, { ...entry, key, checked } ];
|
return [ key, { ...entry, key, checked } ];
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
entries: mappedEntries,
|
entries: mappedEntries,
|
||||||
selectedEntries
|
selectedEntries,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ const checklistSlice = createSlice({
|
||||||
}
|
}
|
||||||
|
|
||||||
return [entry.key, { ...entry, checked } ];
|
return [entry.key, { ...entry, checked } ];
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return { entries, selectedEntries };
|
return { entries, selectedEntries };
|
||||||
|
@ -97,7 +98,7 @@ const checklistSlice = createSlice({
|
||||||
|
|
||||||
state.entries[key] = {
|
state.entries[key] = {
|
||||||
...state.entries[key],
|
...state.entries[key],
|
||||||
...value
|
...value,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
updateMultiple: (state, { payload }: PayloadAction<Array<[key: string, value: Partial<Checkable>]>>) => {
|
updateMultiple: (state, { payload }: PayloadAction<Array<[key: string, value: Partial<Checkable>]>>) => {
|
||||||
|
@ -112,11 +113,11 @@ const checklistSlice = createSlice({
|
||||||
|
|
||||||
state.entries[key] = {
|
state.entries[key] = {
|
||||||
...state.entries[key],
|
...state.entries[key],
|
||||||
...value
|
...value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actions = checklistSlice.actions;
|
export const actions = checklistSlice.actions;
|
||||||
|
@ -153,6 +154,6 @@ export const useChecklistReducer = (entries: Checkable[], uniqueKey: string, ini
|
||||||
return useReducer(
|
return useReducer(
|
||||||
checklistSlice.reducer,
|
checklistSlice.reducer,
|
||||||
initialState,
|
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/>.
|
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
|
* OAuthToken represents a response
|
||||||
|
@ -78,8 +79,8 @@ export const oauthSlice = createSlice({
|
||||||
delete state.token;
|
delete state.token;
|
||||||
delete state.app;
|
delete state.app;
|
||||||
state.loginState = "logout";
|
state.loginState = "logout";
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|
|
@ -50,13 +50,13 @@ const persistedReducer = persistReducer({
|
||||||
|
|
||||||
// This is a cheeky workaround for
|
// This is a cheeky workaround for
|
||||||
// redux-persist being a stickler.
|
// redux-persist being a stickler.
|
||||||
let anyState = state as any;
|
const anyState = state as any;
|
||||||
if (anyState?.oauth != undefined) {
|
if (anyState?.oauth != undefined) {
|
||||||
anyState.oauth.expectingRedirect = false;
|
anyState.oauth.expectingRedirect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return anyState;
|
return anyState;
|
||||||
}
|
},
|
||||||
}, combinedReducers);
|
}, combinedReducers);
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
|
@ -71,10 +71,10 @@ export const store = configureStore({
|
||||||
PERSIST,
|
PERSIST,
|
||||||
PURGE,
|
PURGE,
|
||||||
REGISTER,
|
REGISTER,
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}).concat(gtsApi.middleware);
|
}).concat(gtsApi.middleware);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const persistor = persistStore(store);
|
export const persistor = persistStore(store);
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default function Test({}) {
|
||||||
|
|
||||||
const form = {
|
const form = {
|
||||||
email: useTextInput("email", { defaultValue: instance?.email }),
|
email: useTextInput("email", { defaultValue: instance?.email }),
|
||||||
message: useTextInput("message")
|
message: useTextInput("message"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [submit, result] = useFormSubmit(form, useSendTestEmailMutation(), { changedOnly: false });
|
const [submit, result] = useFormSubmit(form, useSendTestEmailMutation(), { changedOnly: false });
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default function ExpireRemote({}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "invalid domain";
|
return "invalid domain";
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [expire, expireResult] = useInstanceKeysExpireMutation();
|
const [expire, expireResult] = useInstanceKeysExpireMutation();
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { useTextInput } from "../../../../lib/form";
|
||||||
import { useLazyApURLQuery } from "../../../../lib/query/admin/debug";
|
import { useLazyApURLQuery } from "../../../../lib/query/admin/debug";
|
||||||
import { TextInput } from "../../../../components/form/inputs";
|
import { TextInput } from "../../../../components/form/inputs";
|
||||||
import MutationButton from "../../../../components/form/mutation-button";
|
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";
|
import Loading from "../../../../components/loading";
|
||||||
|
|
||||||
// Used for syntax highlighting of json result.
|
// Used for syntax highlighting of json result.
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { matchSorter } from "match-sorter";
|
||||||
import ComboBox from "../../../components/combo-box";
|
import ComboBox from "../../../components/combo-box";
|
||||||
import { useListEmojiQuery } from "../../../lib/query/admin/custom-emoji";
|
import { useListEmojiQuery } from "../../../lib/query/admin/custom-emoji";
|
||||||
import { CustomEmoji } from "../../../lib/types/custom-emoji";
|
import type { CustomEmoji } from "../../../lib/types/custom-emoji";
|
||||||
import { ComboboxFormInputHook } from "../../../lib/form/types";
|
import type { ComboboxFormInputHook } from "../../../lib/form/types";
|
||||||
import Loading from "../../../components/loading";
|
import Loading from "../../../components/loading";
|
||||||
import { Error } from "../../../components/error";
|
import { Error } from "../../../components/error";
|
||||||
|
|
||||||
|
@ -97,7 +98,7 @@ export function CategorySelect({ field, children }: PropsWithChildren<CategorySe
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{categoryName}
|
{categoryName}
|
||||||
</>
|
</>,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default function EmojiDetail() {
|
||||||
function EmojiDetailForm({ data: emoji }) {
|
function EmojiDetailForm({ data: emoji }) {
|
||||||
const { data: instance } = useInstanceV1Query();
|
const { data: instance } = useInstanceV1Query();
|
||||||
const emojiMaxSize = useMemo(() => {
|
const emojiMaxSize = useMemo(() => {
|
||||||
return instance?.configuration?.emojis?.emoji_size_limit ?? 50 * 1024;
|
return instance?.configuration.emojis.emoji_size_limit ?? 50 * 1024;
|
||||||
}, [instance]);
|
}, [instance]);
|
||||||
|
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
|
@ -56,8 +56,8 @@ function EmojiDetailForm({ data: emoji }) {
|
||||||
category: useComboBoxInput("category", { source: emoji }),
|
category: useComboBoxInput("category", { source: emoji }),
|
||||||
image: useFileInput("image", {
|
image: useFileInput("image", {
|
||||||
withPreview: true,
|
withPreview: true,
|
||||||
maxSize: emojiMaxSize
|
maxSize: emojiMaxSize,
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [modifyEmoji, result] = useFormSubmit(form, useEditEmojiMutation());
|
const [modifyEmoji, result] = useFormSubmit(form, useEditEmojiMutation());
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useFileInput, useComboBoxInput } from "../../../../lib/form";
|
||||||
import useShortcode from "./use-shortcode";
|
import useShortcode from "./use-shortcode";
|
||||||
import useFormSubmit from "../../../../lib/form/submit";
|
import useFormSubmit from "../../../../lib/form/submit";
|
||||||
|
@ -32,7 +33,7 @@ import prettierBytes from "prettier-bytes";
|
||||||
export default function NewEmojiForm() {
|
export default function NewEmojiForm() {
|
||||||
const { data: instance } = useInstanceV1Query();
|
const { data: instance } = useInstanceV1Query();
|
||||||
const emojiMaxSize = useMemo(() => {
|
const emojiMaxSize = useMemo(() => {
|
||||||
return instance?.configuration?.emojis?.emoji_size_limit ?? 50 * 1024;
|
return instance?.configuration.emojis.emoji_size_limit ?? 50 * 1024;
|
||||||
}, [instance]);
|
}, [instance]);
|
||||||
|
|
||||||
const prettierMaxSize = useMemo(() => {
|
const prettierMaxSize = useMemo(() => {
|
||||||
|
@ -43,7 +44,7 @@ export default function NewEmojiForm() {
|
||||||
shortcode: useShortcode(),
|
shortcode: useShortcode(),
|
||||||
image: useFileInput("image", {
|
image: useFileInput("image", {
|
||||||
withPreview: true,
|
withPreview: true,
|
||||||
maxSize: emojiMaxSize
|
maxSize: emojiMaxSize,
|
||||||
}),
|
}),
|
||||||
category: useComboBoxInput("category"),
|
category: useComboBoxInput("category"),
|
||||||
};
|
};
|
||||||
|
@ -59,7 +60,7 @@ export default function NewEmojiForm() {
|
||||||
form.shortcode.reset();
|
form.shortcode.reset();
|
||||||
form.image.reset();
|
form.image.reset();
|
||||||
form.category.reset();
|
form.category.reset();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ export default function NewEmojiForm() {
|
||||||
(form.shortcode.value === undefined || form.shortcode.value.length === 0) &&
|
(form.shortcode.value === undefined || form.shortcode.value.length === 0) &&
|
||||||
form.image.value !== undefined
|
form.image.value !== undefined
|
||||||
) {
|
) {
|
||||||
let [name, _ext] = form.image.value.name.split(".");
|
const [name, _ext] = form.image.value.name.split(".");
|
||||||
form.shortcode.setter(name);
|
form.shortcode.setter(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import Loading from "../../../../components/loading";
|
||||||
import { Error } from "../../../../components/error";
|
import { Error } from "../../../../components/error";
|
||||||
import { TextInput } from "../../../../components/form/inputs";
|
import { TextInput } from "../../../../components/form/inputs";
|
||||||
import { useListEmojiQuery } from "../../../../lib/query/admin/custom-emoji";
|
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() {
|
export default function EmojiOverview() {
|
||||||
const { data: emoji = [], isLoading, isError, error } = useListEmojiQuery({ filter: "domain:local" });
|
const { data: emoji = [], isLoading, isError, error } = useListEmojiQuery({ filter: "domain:local" });
|
||||||
|
@ -87,7 +87,7 @@ function EmojiList({ emoji }: EmojiListParams) {
|
||||||
// Filter from emojis in this category.
|
// Filter from emojis in this category.
|
||||||
emojiByCategory.forEach((entries, category) => {
|
emojiByCategory.forEach((entries, category) => {
|
||||||
const filteredEntries = matchSorter(entries, filter, {
|
const filteredEntries = matchSorter(entries, filter, {
|
||||||
keys: ["shortcode"]
|
keys: ["shortcode"],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (filteredEntries.length == 0) {
|
if (filteredEntries.length == 0) {
|
||||||
|
@ -164,8 +164,12 @@ function EmojiPreview({ emoji }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
onMouseEnter={() => { setAnimate(true); }}
|
onMouseEnter={() => {
|
||||||
onMouseLeave={() => { setAnimate(false); }}
|
setAnimate(true);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setAnimate(false);
|
||||||
|
}}
|
||||||
src={animate ? emoji.url : emoji.static_url}
|
src={animate ? emoji.url : emoji.static_url}
|
||||||
alt={emoji.shortcode}
|
alt={emoji.shortcode}
|
||||||
title={emoji.shortcode}
|
title={emoji.shortcode}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const shortcodeRegex = /^\w{2,30}$/;
|
||||||
|
|
||||||
export default function useShortcode() {
|
export default function useShortcode() {
|
||||||
const { data: emoji = [] } = useListEmojiQuery({
|
const { data: emoji = [] } = useListEmojiQuery({
|
||||||
filter: "domain:local"
|
filter: "domain:local",
|
||||||
});
|
});
|
||||||
|
|
||||||
const emojiCodes = useMemo(() => {
|
const emojiCodes = useMemo(() => {
|
||||||
|
@ -36,7 +36,9 @@ export default function useShortcode() {
|
||||||
return useTextInput("shortcode", {
|
return useTextInput("shortcode", {
|
||||||
validator: function validateShortcode(code) {
|
validator: function validateShortcode(code) {
|
||||||
// technically invalid, but hacky fix to prevent validation error on page load
|
// technically invalid, but hacky fix to prevent validation error on page load
|
||||||
if (code == "") { return ""; }
|
if (code == "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if (emojiCodes.has(code)) {
|
if (emojiCodes.has(code)) {
|
||||||
return "Shortcode already in use";
|
return "Shortcode already in use";
|
||||||
|
@ -51,6 +53,6 @@ export default function useShortcode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ export default function RemoteEmoji() {
|
||||||
const {
|
const {
|
||||||
data: emoji = [],
|
data: emoji = [],
|
||||||
isLoading,
|
isLoading,
|
||||||
error
|
error,
|
||||||
} = useListEmojiQuery({ filter: "domain:local" });
|
} = useListEmojiQuery({ filter: "domain:local" });
|
||||||
|
|
||||||
const emojiCodes = useMemo(() => new Set(emoji.map((e) => e.shortcode)), [emoji]);
|
const emojiCodes = useMemo(() => new Set(emoji.map((e) => e.shortcode)), [emoji]);
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default function StealThisLook({ emojiCodes }) {
|
||||||
"fa fa-fw",
|
"fa fa-fw",
|
||||||
(result.isLoading
|
(result.isLoading
|
||||||
? "fa-refresh fa-spin"
|
? "fa-refresh fa-spin"
|
||||||
: "fa-search")
|
: "fa-search"),
|
||||||
].join(" ")} aria-hidden="true" title="Search" />
|
].join(" ")} aria-hidden="true" title="Search" />
|
||||||
<span className="sr-only">Search</span>
|
<span className="sr-only">Search</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -108,9 +108,9 @@ function CopyEmojiForm({ localEmojiCodes, type, emojiList }) {
|
||||||
const form = {
|
const form = {
|
||||||
selectedEmoji: useCheckListInput("selectedEmoji", {
|
selectedEmoji: useCheckListInput("selectedEmoji", {
|
||||||
entries: emojiList,
|
entries: emojiList,
|
||||||
uniqueKey: "id"
|
uniqueKey: "id",
|
||||||
}),
|
}),
|
||||||
category: useComboBoxInput("category")
|
category: useComboBoxInput("category"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [formSubmit, result] = useFormSubmit(
|
const [formSubmit, result] = useFormSubmit(
|
||||||
|
@ -126,18 +126,18 @@ function CopyEmojiForm({ localEmojiCodes, type, emojiList }) {
|
||||||
});
|
});
|
||||||
form.selectedEmoji.updateMultiple(processed);
|
form.selectedEmoji.updateMultiple(processed);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const buttonsInactive = form.selectedEmoji.someSelected
|
const buttonsInactive = form.selectedEmoji.someSelected
|
||||||
? {
|
? {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
title: ""
|
title: "",
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
title: "No emoji selected, cannot perform any actions"
|
title: "No emoji selected, cannot perform any actions",
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkListExtraProps = useCallback(() => ({ localEmojiCodes }), [localEmojiCodes]);
|
const checkListExtraProps = useCallback(() => ({ localEmojiCodes }), [localEmojiCodes]);
|
||||||
|
@ -205,7 +205,7 @@ function EmojiEntry({ entry: emoji, onChange, extraProps: { localEmojiCodes } })
|
||||||
return (emoji.checked && localEmojiCodes.has(code))
|
return (emoji.checked && localEmojiCodes.has(code))
|
||||||
? "Shortcode already in use"
|
? "Shortcode already in use"
|
||||||
: "";
|
: "";
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { useTextInput } from "../../../lib/form";
|
||||||
import useFormSubmit from "../../../lib/form/submit";
|
import useFormSubmit from "../../../lib/form/submit";
|
||||||
import { TextInput } from "../../../components/form/inputs";
|
import { TextInput } from "../../../components/form/inputs";
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import { PermType } from "../../../lib/types/perm";
|
import type { PermType } from "../../../lib/types/perm";
|
||||||
import { RE2JS } from "re2js";
|
import { RE2JS } from "re2js";
|
||||||
|
|
||||||
export default function HeaderPermCreateForm({ permType }: { permType: PermType }) {
|
export default function HeaderPermCreateForm({ permType }: { permType: PermType }) {
|
||||||
|
@ -44,7 +44,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
regex: useTextInput("regex", {
|
regex: useTextInput("regex", {
|
||||||
validator: (val: string) => {
|
validator: (val: string) => {
|
||||||
|
@ -63,7 +63,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType
|
||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
Header Name
|
Header Name
|
||||||
<a
|
<a
|
||||||
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"
|
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="docslink"
|
className="docslink"
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
|
|
||||||
import React, { useEffect, useMemo } from "react";
|
import React, { useEffect, useMemo } from "react";
|
||||||
import { useLocation, useParams } from "wouter";
|
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 { useDeleteHeaderAllowMutation, useDeleteHeaderBlockMutation, useGetHeaderAllowQuery, useGetHeaderBlockQuery } from "../../../lib/query/admin/http-header-permissions";
|
||||||
import { HeaderPermission } from "../../../lib/types/http-header-permissions";
|
import type { HeaderPermission } from "../../../lib/types/http-header-permissions";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { SerializedError } from "@reduxjs/toolkit";
|
import type { SerializedError } from "@reduxjs/toolkit";
|
||||||
import Loading from "../../../components/loading";
|
import Loading from "../../../components/loading";
|
||||||
import { Error } from "../../../components/error";
|
import { Error } from "../../../components/error";
|
||||||
import { useLazyGetAccountQuery } from "../../../lib/query/admin";
|
import { useLazyGetAccountQuery } from "../../../lib/query/admin";
|
||||||
|
@ -42,7 +42,7 @@ Some Test Value
|
||||||
Another Test Value`;
|
Another Test Value`;
|
||||||
|
|
||||||
export default function HeaderPermDetail() {
|
export default function HeaderPermDetail() {
|
||||||
let params = useParams();
|
const params = useParams();
|
||||||
if (params.permType !== "blocks" && params.permType !== "allows") {
|
if (params.permType !== "blocks" && params.permType !== "allows") {
|
||||||
throw "unrecognized perm type " + params.permType;
|
throw "unrecognized perm type " + params.permType;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ export default function HeaderPermDetail() {
|
||||||
return params.permType?.slice(0, -1) as PermType;
|
return params.permType?.slice(0, -1) as PermType;
|
||||||
}, [params]);
|
}, [params]);
|
||||||
|
|
||||||
let permID = params.permId as string | undefined;
|
const permID = params.permId;
|
||||||
if (!permID) {
|
if (!permID) {
|
||||||
throw "no perm ID";
|
throw "no perm ID";
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ function PermDeets({
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
} else if (isErrorAccount || account === undefined) {
|
} else if (isErrorAccount || account === undefined) {
|
||||||
// Fall back to account ID.
|
// Fall back to account ID.
|
||||||
return perm?.created_by;
|
return perm.created_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -21,18 +21,18 @@ import React, { useMemo } from "react";
|
||||||
import { useGetHeaderAllowsQuery, useGetHeaderBlocksQuery } from "../../../lib/query/admin/http-header-permissions";
|
import { useGetHeaderAllowsQuery, useGetHeaderBlocksQuery } from "../../../lib/query/admin/http-header-permissions";
|
||||||
import { NoArg } from "../../../lib/types/query";
|
import { NoArg } from "../../../lib/types/query";
|
||||||
import { PageableList } from "../../../components/pageable-list";
|
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 { useLocation, useParams } from "wouter";
|
||||||
import { PermType } from "../../../lib/types/perm";
|
import type { PermType } from "../../../lib/types/perm";
|
||||||
import { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
import type { FetchBaseQueryError } from "@reduxjs/toolkit/query";
|
||||||
import { SerializedError } from "@reduxjs/toolkit";
|
import type { SerializedError } from "@reduxjs/toolkit";
|
||||||
import HeaderPermCreateForm from "./create";
|
import HeaderPermCreateForm from "./create";
|
||||||
|
|
||||||
export default function HeaderPermsOverview() {
|
export default function HeaderPermsOverview() {
|
||||||
const [ location, setLocation ] = useLocation();
|
const [ location, setLocation ] = useLocation();
|
||||||
|
|
||||||
// Parse perm type from routing params.
|
// Parse perm type from routing params.
|
||||||
let params = useParams();
|
const params = useParams();
|
||||||
if (params.permType !== "blocks" && params.permType !== "allows") {
|
if (params.permType !== "blocks" && params.permType !== "allows") {
|
||||||
throw "unrecognized perm type " + params.permType;
|
throw "unrecognized perm type " + params.permType;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export default function HeaderPermsOverview() {
|
||||||
isFetching: isFetchingBlocks,
|
isFetching: isFetchingBlocks,
|
||||||
isSuccess: isSuccessBlocks,
|
isSuccess: isSuccessBlocks,
|
||||||
isError: isErrorBlocks,
|
isError: isErrorBlocks,
|
||||||
error: errorBlocks
|
error: errorBlocks,
|
||||||
} = useGetHeaderBlocksQuery(NoArg, { skip: permType !== "block" });
|
} = useGetHeaderBlocksQuery(NoArg, { skip: permType !== "block" });
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -62,7 +62,7 @@ export default function HeaderPermsOverview() {
|
||||||
isFetching: isFetchingAllows,
|
isFetching: isFetchingAllows,
|
||||||
isSuccess: isSuccessAllows,
|
isSuccess: isSuccessAllows,
|
||||||
isError: isErrorAllows,
|
isError: isErrorAllows,
|
||||||
error: errorAllows
|
error: errorAllows,
|
||||||
} = useGetHeaderAllowsQuery(NoArg, { skip: permType !== "allow" });
|
} = useGetHeaderAllowsQuery(NoArg, { skip: permType !== "allow" });
|
||||||
|
|
||||||
const itemToEntry = (perm: HeaderPermission) => {
|
const itemToEntry = (perm: HeaderPermission) => {
|
||||||
|
@ -77,7 +77,7 @@ export default function HeaderPermsOverview() {
|
||||||
// Store the back location in
|
// Store the back location in
|
||||||
// history so the detail view
|
// history so the detail view
|
||||||
// can use it to return here.
|
// can use it to return here.
|
||||||
state: { backLocation: location }
|
state: { backLocation: location },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
role="link"
|
role="link"
|
||||||
|
|
|
@ -56,7 +56,7 @@ function EditInstanceRuleForm({ rule }) {
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
const form = {
|
const form = {
|
||||||
id: useValue("id", rule.id),
|
id: useValue("id", rule.id),
|
||||||
rule: useTextInput("text", { defaultValue: rule.text })
|
rule: useTextInput("text", { defaultValue: rule.text }),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [submitForm, result] = useFormSubmit(form, useUpdateInstanceRuleMutation());
|
const [submitForm, result] = useFormSubmit(form, useUpdateInstanceRuleMutation());
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { useTextInput } from "../../../lib/form";
|
||||||
import useFormSubmit from "../../../lib/form/submit";
|
import useFormSubmit from "../../../lib/form/submit";
|
||||||
import { TextArea } from "../../../components/form/inputs";
|
import { TextArea } from "../../../components/form/inputs";
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
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";
|
import FormWithData from "../../../lib/form/form-with-data";
|
||||||
|
|
||||||
export default function InstanceRules() {
|
export default function InstanceRules() {
|
||||||
|
@ -46,7 +46,9 @@ function InstanceRulesForm({ data: rules }: { data: MappedRules }) {
|
||||||
|
|
||||||
const [submitForm, result] = useFormSubmit({ newRule }, useAddInstanceRuleMutation(), {
|
const [submitForm, result] = useFormSubmit({ newRule }, useAddInstanceRuleMutation(), {
|
||||||
changedOnly: true,
|
changedOnly: true,
|
||||||
onFinish: () => newRule.reset()
|
onFinish: () => {
|
||||||
|
newRule.reset();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { TextInput, TextArea, FileInput } from "../../../components/form/inputs"
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import { useInstanceV1Query } from "../../../lib/query/gts-api";
|
import { useInstanceV1Query } from "../../../lib/query/gts-api";
|
||||||
import { useUpdateInstanceMutation } from "../../../lib/query/admin";
|
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 FormWithData from "../../../lib/form/form-with-data";
|
||||||
import useFormSubmit from "../../../lib/form/submit";
|
import useFormSubmit from "../../../lib/form/submit";
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
const form = {
|
const form = {
|
||||||
title: useTextInput("title", {
|
title: useTextInput("title", {
|
||||||
source: instance,
|
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 }),
|
thumbnail: useFileInput("thumbnail", { withPreview: true }),
|
||||||
thumbnailDesc: useTextInput("thumbnail_description", { source: instance }),
|
thumbnailDesc: useTextInput("thumbnail_description", { source: instance }),
|
||||||
|
@ -58,22 +58,22 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
source: instance,
|
source: instance,
|
||||||
// Select "raw" text version of parsed field for editing.
|
// Select "raw" text version of parsed field for editing.
|
||||||
valueSelector: (s: InstanceV1) => s.short_description_text,
|
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", {
|
description: useTextInput("description", {
|
||||||
source: instance,
|
source: instance,
|
||||||
// Select "raw" text version of parsed field for editing.
|
// Select "raw" text version of parsed field for editing.
|
||||||
valueSelector: (s: InstanceV1) => s.description_text,
|
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", {
|
terms: useTextInput("terms", {
|
||||||
source: instance,
|
source: instance,
|
||||||
// Select "raw" text version of parsed field for editing.
|
// Select "raw" text version of parsed field for editing.
|
||||||
valueSelector: (s: InstanceV1) => s.terms_text,
|
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 }),
|
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());
|
const [submitForm, result] = useFormSubmit(form, useUpdateInstanceMutation());
|
||||||
|
@ -109,8 +109,8 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
<div className="file-upload-with-preview">
|
<div className="file-upload-with-preview">
|
||||||
<img
|
<img
|
||||||
className="preview avatar"
|
className="preview avatar"
|
||||||
src={form.thumbnail.previewValue ?? instance?.thumbnail}
|
src={form.thumbnail.previewValue ?? instance.thumbnail}
|
||||||
alt={form.thumbnailDesc.value ?? (instance?.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")}
|
alt={form.thumbnailDesc.value ?? (instance.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")}
|
||||||
/>
|
/>
|
||||||
<div className="file-input-with-image-description">
|
<div className="file-input-with-image-description">
|
||||||
<FileInput
|
<FileInput
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
useBoolInput,
|
useBoolInput,
|
||||||
} from "../../../../lib/form";
|
} from "../../../../lib/form";
|
||||||
import { Checkbox, Select, TextInput } from "../../../../components/form/inputs";
|
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";
|
import { useLocation } from "wouter";
|
||||||
|
|
||||||
export interface AccountActionsProps {
|
export interface AccountActionsProps {
|
||||||
|
@ -65,7 +65,7 @@ export function AccountActions({ account, backLocation }: AccountActionsProps) {
|
||||||
function ModerateAccount({ account }: { account: AdminAccount }) {
|
function ModerateAccount({ account }: { account: AdminAccount }) {
|
||||||
const form = {
|
const form = {
|
||||||
id: useValue("id", account.id),
|
id: useValue("id", account.id),
|
||||||
reason: useTextInput("text")
|
reason: useTextInput("text"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const reallySuspend = useBoolInput("reallySuspend");
|
const reallySuspend = useBoolInput("reallySuspend");
|
||||||
|
@ -96,7 +96,7 @@ function ModerateAccount({ account }: { account: AdminAccount }) {
|
||||||
/>
|
/>
|
||||||
<div className="action-buttons">
|
<div className="action-buttons">
|
||||||
<MutationButton
|
<MutationButton
|
||||||
disabled={account.suspended || reallySuspend.value === undefined || reallySuspend.value === false}
|
disabled={account.suspended || reallySuspend.value === undefined || !reallySuspend.value}
|
||||||
label="Suspend"
|
label="Suspend"
|
||||||
name="suspend"
|
name="suspend"
|
||||||
result={result}
|
result={result}
|
||||||
|
@ -140,7 +140,7 @@ function HandleSignup({ account, backLocation }: { account: AdminAccount, backLo
|
||||||
// redirect to accounts page.
|
// redirect to accounts page.
|
||||||
setLocation(backLocation);
|
setLocation(backLocation);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -22,7 +22,7 @@ import React from "react";
|
||||||
import { useGetAccountQuery } from "../../../../lib/query/admin";
|
import { useGetAccountQuery } from "../../../../lib/query/admin";
|
||||||
import FormWithData from "../../../../lib/form/form-with-data";
|
import FormWithData from "../../../../lib/form/form-with-data";
|
||||||
import FakeProfile from "../../../../components/profile";
|
import FakeProfile from "../../../../components/profile";
|
||||||
import { AdminAccount } from "../../../../lib/types/account";
|
import type { AdminAccount } from "../../../../lib/types/account";
|
||||||
import { AccountActions } from "./actions";
|
import { AccountActions } from "./actions";
|
||||||
import { useParams } from "wouter";
|
import { useParams } from "wouter";
|
||||||
import { useBaseUrl } from "../../../../lib/navigation/util";
|
import { useBaseUrl } from "../../../../lib/navigation/util";
|
||||||
|
@ -32,7 +32,7 @@ import { UseOurInstanceAccount, yesOrNo } from "../../../../lib/util";
|
||||||
export default function AccountDetail() {
|
export default function AccountDetail() {
|
||||||
const params: { accountID: string } = useParams();
|
const params: { accountID: string } = useParams();
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
|
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="account-detail">
|
<div className="account-detail">
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useSearchAccountsQuery } from "../../../../lib/query/admin";
|
||||||
import { PageableList } from "../../../../components/pageable-list";
|
import { PageableList } from "../../../../components/pageable-list";
|
||||||
import { useLocation } from "wouter";
|
import { useLocation } from "wouter";
|
||||||
import Username from "../../../../components/username";
|
import Username from "../../../../components/username";
|
||||||
import { AdminAccount } from "../../../../lib/types/account";
|
import type { AdminAccount } from "../../../../lib/types/account";
|
||||||
|
|
||||||
export default function AccountsPending() {
|
export default function AccountsPending() {
|
||||||
const [ location, _setLocation ] = useLocation();
|
const [ location, _setLocation ] = useLocation();
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useLazySearchAccountsQuery } from "../../../../lib/query/admin";
|
||||||
import { useTextInput } from "../../../../lib/form";
|
import { useTextInput } from "../../../../lib/form";
|
||||||
|
@ -25,7 +26,7 @@ import { PageableList } from "../../../../components/pageable-list";
|
||||||
import { Select, TextInput } from "../../../../components/form/inputs";
|
import { Select, TextInput } from "../../../../components/form/inputs";
|
||||||
import MutationButton from "../../../../components/form/mutation-button";
|
import MutationButton from "../../../../components/form/mutation-button";
|
||||||
import { useLocation, useSearch } from "wouter";
|
import { useLocation, useSearch } from "wouter";
|
||||||
import { AdminAccount } from "../../../../lib/types/account";
|
import type { AdminAccount } from "../../../../lib/types/account";
|
||||||
import Username from "../../../../components/username";
|
import Username from "../../../../components/username";
|
||||||
import isValidDomain from "is-valid-domain";
|
import isValidDomain from "is-valid-domain";
|
||||||
|
|
||||||
|
@ -66,11 +67,11 @@ export function AccountSearchForm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "invalid domain";
|
return "invalid domain";
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
email: useTextInput("email", { defaultValue: urlQueryParams.get("email") ?? ""}),
|
email: useTextInput("email", { defaultValue: urlQueryParams.get("email") ?? ""}),
|
||||||
ip: useTextInput("ip", { defaultValue: urlQueryParams.get("ip") ?? ""}),
|
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,
|
// On mount, if urlQueryParams were provided,
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useLocation, useParams, useSearch } from "wouter";
|
||||||
|
|
||||||
import { useTextInput, useBoolInput } from "../../../lib/form";
|
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 { useDomainAllowsQuery, useDomainBlocksQuery } from "../../../lib/query/admin/domain-permissions/get";
|
||||||
import { useAddDomainAllowMutation, useAddDomainBlockMutation, useRemoveDomainAllowMutation, useRemoveDomainBlockMutation } from "../../../lib/query/admin/domain-permissions/update";
|
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 { NoArg } from "../../../lib/types/query";
|
||||||
import { Error } from "../../../components/error";
|
import { Error } from "../../../components/error";
|
||||||
import { useBaseUrl } from "../../../lib/navigation/util";
|
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";
|
import isValidDomain from "is-valid-domain";
|
||||||
|
|
||||||
export default function DomainPermDetail() {
|
export default function DomainPermDetail() {
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
|
|
||||||
// Parse perm type from routing params.
|
// Parse perm type from routing params.
|
||||||
let params = useParams();
|
const params = useParams();
|
||||||
if (params.permType !== "blocks" && params.permType !== "allows") {
|
if (params.permType !== "blocks" && params.permType !== "allows") {
|
||||||
throw "unrecognized perm type " + params.permType;
|
throw "unrecognized perm type " + params.permType;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +131,7 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps)
|
||||||
const disabledForm = isExistingPerm
|
const disabledForm = isExistingPerm
|
||||||
? {
|
? {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
title: "Domain permissions currently cannot be edited."
|
title: "Domain permissions currently cannot be edited.",
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
@ -164,11 +163,11 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "invalid domain";
|
return "invalid domain";
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
obfuscate: useBoolInput("obfuscate", { source: perm }),
|
obfuscate: useBoolInput("obfuscate", { source: perm }),
|
||||||
commentPrivate: useTextInput("private_comment", { 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
|
// 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
|
// but if domain input changes, that doesn't match anymore
|
||||||
// and causes issues later on so, before submitting the form,
|
// and causes issues later on so, before submitting the form,
|
||||||
// silently change url, and THEN submit.
|
// silently change url, and THEN submit.
|
||||||
let correctUrl = `/${permType}s/${form.domain.value}`;
|
const correctUrl = `/${permType}s/${form.domain.value}`;
|
||||||
if (location != correctUrl) {
|
if (location != correctUrl) {
|
||||||
setLocation(correctUrl);
|
setLocation(correctUrl);
|
||||||
}
|
}
|
||||||
return submitForm(e);
|
submitForm(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useExportDomainListMutation } from "../../../lib/query/admin/domain-permissions/export";
|
||||||
import useFormSubmit from "../../../lib/form/submit";
|
import useFormSubmit from "../../../lib/form/submit";
|
||||||
import {
|
import {
|
||||||
|
@ -96,7 +95,9 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp
|
||||||
<MutationButton
|
<MutationButton
|
||||||
label="Import"
|
label="Import"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => submitParse()}
|
onClick={() => {
|
||||||
|
submitParse();
|
||||||
|
}}
|
||||||
result={parseResult}
|
result={parseResult}
|
||||||
showError={false}
|
showError={false}
|
||||||
disabled={form.permType.value === undefined || form.permType.value.length === 0}
|
disabled={form.permType.value === undefined || form.permType.value.length === 0}
|
||||||
|
@ -116,7 +117,9 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp
|
||||||
<MutationButton
|
<MutationButton
|
||||||
label="Export"
|
label="Export"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => submitExport("export")}
|
onClick={() => {
|
||||||
|
submitExport("export");
|
||||||
|
}}
|
||||||
result={exportResult} showError={false}
|
result={exportResult} showError={false}
|
||||||
disabled={form.permType.value === undefined || form.permType.value.length === 0}
|
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"
|
label="Export to file"
|
||||||
wrapperClassName="export-file-button"
|
wrapperClassName="export-file-button"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => submitExport("export-file")}
|
onClick={() => {
|
||||||
|
submitExport("export-file");
|
||||||
|
}}
|
||||||
result={exportResult}
|
result={exportResult}
|
||||||
showError={false}
|
showError={false}
|
||||||
disabled={form.permType.value === undefined || form.permType.value.length === 0}
|
disabled={form.permType.value === undefined || form.permType.value.length === 0}
|
||||||
|
|
|
@ -37,8 +37,8 @@ export default function ImportExport() {
|
||||||
options: {
|
options: {
|
||||||
block: "Domain blocks",
|
block: "Domain blocks",
|
||||||
allow: "Domain allows",
|
allow: "Domain allows",
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [submitParse, parseResult] = useFormSubmit(form, useProcessDomainPermissionsMutation(), { changedOnly: false });
|
const [submitParse, parseResult] = useFormSubmit(form, useProcessDomainPermissionsMutation(), { changedOnly: false });
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { Link, useLocation, useParams } from "wouter";
|
||||||
import { matchSorter } from "match-sorter";
|
import { matchSorter } from "match-sorter";
|
||||||
import { useTextInput } from "../../../lib/form";
|
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 { useDomainAllowsQuery, useDomainBlocksQuery } from "../../../lib/query/admin/domain-permissions/get";
|
||||||
import type { MappedDomainPerms } from "../../../lib/types/domain-permission";
|
import type { MappedDomainPerms } from "../../../lib/types/domain-permission";
|
||||||
import { NoArg } from "../../../lib/types/query";
|
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";
|
import { useBaseUrl } from "../../../lib/navigation/util";
|
||||||
|
|
||||||
export default function DomainPermissionsOverview() {
|
export default function DomainPermissionsOverview() {
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
|
|
||||||
// Parse perm type from routing params.
|
// Parse perm type from routing params.
|
||||||
let params = useParams();
|
const params = useParams();
|
||||||
if (params.permType !== "blocks" && params.permType !== "allows") {
|
if (params.permType !== "blocks" && params.permType !== "allows") {
|
||||||
throw "unrecognized perm type " + params.permType;
|
throw "unrecognized perm type " + params.permType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { memo, useMemo, useCallback, useEffect } from "react";
|
||||||
import { memo, useMemo, useCallback, useEffect } from "react";
|
|
||||||
import { isValidDomainPermission, hasBetterScope } from "../../../lib/util/domain-permission";
|
import { isValidDomainPermission, hasBetterScope } from "../../../lib/util/domain-permission";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -45,7 +44,7 @@ import FormWithData from "../../../lib/form/form-with-data";
|
||||||
import { useImportDomainPermsMutation } from "../../../lib/query/admin/domain-permissions/import";
|
import { useImportDomainPermsMutation } from "../../../lib/query/admin/domain-permissions/import";
|
||||||
import {
|
import {
|
||||||
useDomainAllowsQuery,
|
useDomainAllowsQuery,
|
||||||
useDomainBlocksQuery
|
useDomainBlocksQuery,
|
||||||
} from "../../../lib/query/admin/domain-permissions/get";
|
} from "../../../lib/query/admin/domain-permissions/get";
|
||||||
|
|
||||||
import type { DomainPerm, MappedDomainPerms } from "../../../lib/types/domain-permission";
|
import type { DomainPerm, MappedDomainPerms } from "../../../lib/types/domain-permission";
|
||||||
|
@ -68,7 +67,7 @@ export const ProcessImport = memo(
|
||||||
{...{ list, permType }}
|
{...{ list, permType }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface ImportListProps {
|
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.
|
domains: useCheckListInput("domains", { entries: list }), // DomainPerm is actually also a Checkable.
|
||||||
obfuscate: useBoolInput("obfuscate"),
|
obfuscate: useBoolInput("obfuscate"),
|
||||||
privateComment: useTextInput("private_comment", {
|
privateComment: useTextInput("private_comment", {
|
||||||
defaultValue: `Imported on ${new Date().toLocaleString()}`
|
defaultValue: `Imported on ${new Date().toLocaleString()}`,
|
||||||
}),
|
}),
|
||||||
privateCommentBehavior: useRadioInput("private_comment_behavior", {
|
privateCommentBehavior: useRadioInput("private_comment_behavior", {
|
||||||
defaultValue: "append",
|
defaultValue: "append",
|
||||||
options: {
|
options: {
|
||||||
append: "Append to",
|
append: "Append to",
|
||||||
replace: "Replace"
|
replace: "Replace",
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
publicComment: useTextInput("public_comment"),
|
publicComment: useTextInput("public_comment"),
|
||||||
publicCommentBehavior: useRadioInput("public_comment_behavior", {
|
publicCommentBehavior: useRadioInput("public_comment_behavior", {
|
||||||
defaultValue: "append",
|
defaultValue: "append",
|
||||||
options: {
|
options: {
|
||||||
append: "Append to",
|
append: "Append to",
|
||||||
replace: "Replace"
|
replace: "Replace",
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
permType: permType,
|
permType: permType,
|
||||||
};
|
};
|
||||||
|
@ -218,7 +217,7 @@ function DomainCheckList({ field, domainPerms, commentType, permType }: DomainCh
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CheckList
|
<CheckList
|
||||||
field={field as ChecklistInputHook}
|
field={field}
|
||||||
header={<>
|
header={<>
|
||||||
<b>Domain</b>
|
<b>Domain</b>
|
||||||
<b>
|
<b>
|
||||||
|
@ -252,7 +251,7 @@ const UpdateHint = memo(
|
||||||
|
|
||||||
function changeAll() {
|
function changeAll() {
|
||||||
updateMultiple(
|
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>}
|
{entries.length > 0 && <a onClick={changeAll}>change all</a>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface UpdateableEntryProps {
|
interface UpdateableEntryProps {
|
||||||
|
@ -290,7 +289,7 @@ const UpdateableEntry = memo(
|
||||||
}>change</a>
|
}>change</a>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function domainValidationError(isValid) {
|
function domainValidationError(isValid) {
|
||||||
|
@ -312,7 +311,7 @@ function DomainEntry({ entry, onChange, extraProps: { alreadyExists, comment, pe
|
||||||
defaultValue: entry.domain,
|
defaultValue: entry.domain,
|
||||||
showValidation: entry.checked,
|
showValidation: entry.checked,
|
||||||
initValidation: domainValidationError(entry.valid),
|
initValidation: domainValidationError(entry.valid),
|
||||||
validator: (value) => domainValidationError(isValidDomainPermission(value))
|
validator: (value) => domainValidationError(isValidDomainPermission(value)),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -28,14 +28,14 @@ import MutationButton from "../../../components/form/mutation-button";
|
||||||
import Username from "../../../components/username";
|
import Username from "../../../components/username";
|
||||||
import { useGetReportQuery, useResolveReportMutation } from "../../../lib/query/admin/reports";
|
import { useGetReportQuery, useResolveReportMutation } from "../../../lib/query/admin/reports";
|
||||||
import { useBaseUrl } from "../../../lib/navigation/util";
|
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 { yesOrNo } from "../../../lib/util";
|
||||||
import { Status } from "../../../components/status";
|
import { Status } from "../../../components/status";
|
||||||
|
|
||||||
export default function ReportDetail({ }) {
|
export default function ReportDetail({ }) {
|
||||||
const params: { reportId: string } = useParams();
|
const params: { reportId: string } = useParams();
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
|
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="report-detail">
|
<div className="report-detail">
|
||||||
|
@ -200,7 +200,7 @@ function ReportHistory({ report, baseUrl, location }: ReportSectionProps) {
|
||||||
function ReportActionForm({ report }) {
|
function ReportActionForm({ report }) {
|
||||||
const form = {
|
const form = {
|
||||||
id: useValue("id", report.id),
|
id: useValue("id", report.id),
|
||||||
comment: useTextInput("action_taken_comment")
|
comment: useTextInput("action_taken_comment"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [submit, result] = useFormSubmit(form, useResolveReportMutation(), { changedOnly: false });
|
const [submit, result] = useFormSubmit(form, useResolveReportMutation(), { changedOnly: false });
|
||||||
|
@ -249,7 +249,7 @@ function ReportStatuses({ report }: { report: AdminReport }) {
|
||||||
<Status
|
<Status
|
||||||
key={status.id}
|
key={status.id}
|
||||||
status={status}
|
status={status}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useLazySearchReportsQuery } from "../../../lib/query/admin/reports";
|
||||||
import { useTextInput } from "../../../lib/form";
|
import { useTextInput } from "../../../lib/form";
|
||||||
|
@ -26,7 +27,7 @@ import { Select } from "../../../components/form/inputs";
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import { useLocation, useSearch } from "wouter";
|
import { useLocation, useSearch } from "wouter";
|
||||||
import Username from "../../../components/username";
|
import Username from "../../../components/username";
|
||||||
import { AdminReport } from "../../../lib/types/report";
|
import type { AdminReport } from "../../../lib/types/report";
|
||||||
|
|
||||||
export default function ReportsSearch() {
|
export default function ReportsSearch() {
|
||||||
return (
|
return (
|
||||||
|
@ -61,7 +62,7 @@ function ReportSearchForm() {
|
||||||
resolved: useTextInput("resolved", { defaultValue: resolved }),
|
resolved: useTextInput("resolved", { defaultValue: resolved }),
|
||||||
account_id: useTextInput("account_id", { defaultValue: urlQueryParams.get("account_id") ?? "" }),
|
account_id: useTextInput("account_id", { defaultValue: urlQueryParams.get("account_id") ?? "" }),
|
||||||
target_account_id: useTextInput("target_account_id", { defaultValue: urlQueryParams.get("target_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;
|
const setResolved = form.resolved.setter;
|
||||||
|
@ -196,7 +197,7 @@ function ReportListEntry({ report, linkTo, backLocation }: ReportEntryProps) {
|
||||||
// Store the back location in history so
|
// Store the back location in history so
|
||||||
// the detail view can use it to return to
|
// the detail view can use it to return to
|
||||||
// this page (including query parameters).
|
// this page (including query parameters).
|
||||||
state: { backLocation: backLocation }
|
state: { backLocation: backLocation },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
role="link"
|
role="link"
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { TextInput } from "../../components/form/inputs";
|
||||||
import MutationButton from "../../components/form/mutation-button";
|
import MutationButton from "../../components/form/mutation-button";
|
||||||
import { useEmailChangeMutation, usePasswordChangeMutation, useUserQuery } from "../../lib/query/user";
|
import { useEmailChangeMutation, usePasswordChangeMutation, useUserQuery } from "../../lib/query/user";
|
||||||
import Loading from "../../components/loading";
|
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";
|
import { useInstanceV1Query } from "../../lib/query/gts-api";
|
||||||
|
|
||||||
export default function EmailPassword() {
|
export default function EmailPassword() {
|
||||||
|
@ -42,7 +42,7 @@ function PasswordChange() {
|
||||||
const {
|
const {
|
||||||
data: instance,
|
data: instance,
|
||||||
isFetching: isFetchingInstance,
|
isFetching: isFetchingInstance,
|
||||||
isLoading: isLoadingInstance
|
isLoading: isLoadingInstance,
|
||||||
} = useInstanceV1Query();
|
} = useInstanceV1Query();
|
||||||
if (isFetchingInstance || isLoadingInstance) {
|
if (isFetchingInstance || isLoadingInstance) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
|
@ -64,8 +64,8 @@ function PasswordChangeForm({ oidcEnabled }: { oidcEnabled?: boolean }) {
|
||||||
return "New password same as old password";
|
return "New password same as old password";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const verifyNewPassword = useTextInput("verifyNewPassword", {
|
const verifyNewPassword = useTextInput("verifyNewPassword", {
|
||||||
|
@ -74,7 +74,7 @@ function PasswordChangeForm({ oidcEnabled }: { oidcEnabled?: boolean }) {
|
||||||
return "Passwords do not match";
|
return "Passwords do not match";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [submitForm, result] = useFormSubmit(form, usePasswordChangeMutation());
|
const [submitForm, result] = useFormSubmit(form, usePasswordChangeMutation());
|
||||||
|
@ -138,14 +138,14 @@ function EmailChange() {
|
||||||
const {
|
const {
|
||||||
data: instance,
|
data: instance,
|
||||||
isFetching: isFetchingInstance,
|
isFetching: isFetchingInstance,
|
||||||
isLoading: isLoadingInstance
|
isLoading: isLoadingInstance,
|
||||||
} = useInstanceV1Query();
|
} = useInstanceV1Query();
|
||||||
|
|
||||||
// Load user data.
|
// Load user data.
|
||||||
const {
|
const {
|
||||||
data: user,
|
data: user,
|
||||||
isFetching: isFetchingUser,
|
isFetching: isFetchingUser,
|
||||||
isLoading: isLoadingUser
|
isLoading: isLoadingUser,
|
||||||
} = useUserQuery();
|
} = useUserQuery();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -170,7 +170,7 @@ function EmailChangeForm({user, oidcEnabled}: { user: User, oidcEnabled?: boolea
|
||||||
const form = {
|
const form = {
|
||||||
currentEmail: useTextInput("current_email", {
|
currentEmail: useTextInput("current_email", {
|
||||||
defaultValue: user.email,
|
defaultValue: user.email,
|
||||||
nosubmit: true
|
nosubmit: true,
|
||||||
}),
|
}),
|
||||||
newEmail: useTextInput("new_email", {
|
newEmail: useTextInput("new_email", {
|
||||||
validator: (value: string | undefined) => {
|
validator: (value: string | undefined) => {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import useFormSubmit from "../../../lib/form/submit";
|
import useFormSubmit from "../../../lib/form/submit";
|
||||||
import { useValue } from "../../../lib/form";
|
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 }) {
|
export default function Export({ exportStats }: { exportStats: AccountExportStats }) {
|
||||||
const [exportFollowing, exportFollowingResult] = useFormSubmit(
|
const [exportFollowing, exportFollowingResult] = useFormSubmit(
|
||||||
|
@ -92,7 +92,7 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="docslink"
|
className="docslink"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
Learn more about this section (opens in a new tab)
|
Learn more about this section (opens in a new tab)
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -105,7 +105,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="text-cutoff"
|
className="text-cutoff"
|
||||||
label="Download following.csv"
|
label="Download following.csv"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportFollowing()}
|
onClick={() => {
|
||||||
|
exportFollowing();
|
||||||
|
}}
|
||||||
result={exportFollowingResult}
|
result={exportFollowingResult}
|
||||||
showError={true}
|
showError={true}
|
||||||
disabled={exportStats.following_count === 0}
|
disabled={exportStats.following_count === 0}
|
||||||
|
@ -119,7 +121,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="text-cutoff"
|
className="text-cutoff"
|
||||||
label="Download followers.csv"
|
label="Download followers.csv"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportFollowers()}
|
onClick={() => {
|
||||||
|
exportFollowers();
|
||||||
|
}}
|
||||||
result={exportFollowersResult}
|
result={exportFollowersResult}
|
||||||
showError={true}
|
showError={true}
|
||||||
disabled={exportStats.followers_count === 0}
|
disabled={exportStats.followers_count === 0}
|
||||||
|
@ -133,7 +137,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="text-cutoff"
|
className="text-cutoff"
|
||||||
label="Download lists.csv"
|
label="Download lists.csv"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportLists()}
|
onClick={() => {
|
||||||
|
exportLists();
|
||||||
|
}}
|
||||||
result={exportListsResult}
|
result={exportListsResult}
|
||||||
showError={true}
|
showError={true}
|
||||||
disabled={exportStats.lists_count === 0}
|
disabled={exportStats.lists_count === 0}
|
||||||
|
@ -147,7 +153,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="text-cutoff"
|
className="text-cutoff"
|
||||||
label="Download blocks.csv"
|
label="Download blocks.csv"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportBlocks()}
|
onClick={() => {
|
||||||
|
exportBlocks();
|
||||||
|
}}
|
||||||
result={exportBlocksResult}
|
result={exportBlocksResult}
|
||||||
showError={true}
|
showError={true}
|
||||||
disabled={exportStats.blocks_count === 0}
|
disabled={exportStats.blocks_count === 0}
|
||||||
|
@ -161,7 +169,9 @@ export default function Export({ exportStats }: { exportStats: AccountExportStat
|
||||||
className="text-cutoff"
|
className="text-cutoff"
|
||||||
label="Download mutes.csv"
|
label="Download mutes.csv"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportMutes()}
|
onClick={() => {
|
||||||
|
exportMutes();
|
||||||
|
}}
|
||||||
result={exportMutesResult}
|
result={exportMutesResult}
|
||||||
showError={true}
|
showError={true}
|
||||||
disabled={exportStats.mutes_count === 0}
|
disabled={exportStats.mutes_count === 0}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export default function Import() {
|
||||||
const form = {
|
const form = {
|
||||||
data: useFileInput("data"),
|
data: useFileInput("data"),
|
||||||
type: useTextInput("type", { defaultValue: "" }),
|
type: useTextInput("type", { defaultValue: "" }),
|
||||||
mode: useTextInput("mode", { defaultValue: "" })
|
mode: useTextInput("mode", { defaultValue: "" }),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [submitForm, result] = useFormSubmit(form, useImportDataMutation(), {
|
const [submitForm, result] = useFormSubmit(form, useImportDataMutation(), {
|
||||||
|
@ -37,7 +37,7 @@ export default function Import() {
|
||||||
form.data.reset();
|
form.data.reset();
|
||||||
form.type.reset();
|
form.type.reset();
|
||||||
form.mode.reset();
|
form.mode.reset();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -23,7 +23,7 @@ import FormWithData from "../../../lib/form/form-with-data";
|
||||||
import BackButton from "../../../components/back-button";
|
import BackButton from "../../../components/back-button";
|
||||||
import { useBaseUrl } from "../../../lib/navigation/util";
|
import { useBaseUrl } from "../../../lib/navigation/util";
|
||||||
import { useApproveInteractionRequestMutation, useGetInteractionRequestQuery, useRejectInteractionRequestMutation } from "../../../lib/query/user/interactions";
|
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 { useIcon, useNoun, useVerbed } from "./util";
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import { Status } from "../../../components/status";
|
import { Status } from "../../../components/status";
|
||||||
|
@ -31,7 +31,7 @@ import { Status } from "../../../components/status";
|
||||||
export default function InteractionRequestDetail({ }) {
|
export default function InteractionRequestDetail({ }) {
|
||||||
const params: { reqId: string } = useParams();
|
const params: { reqId: string } = useParams();
|
||||||
const baseUrl = useBaseUrl();
|
const baseUrl = useBaseUrl();
|
||||||
const backLocation: String = history.state?.backLocation ?? `~${baseUrl}`;
|
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="interaction-request-detail">
|
<div className="interaction-request-detail">
|
||||||
|
|
|
@ -17,14 +17,15 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
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 { useBoolInput, useTextInput } from "../../../lib/form";
|
||||||
import { PageableList } from "../../../components/pageable-list";
|
import { PageableList } from "../../../components/pageable-list";
|
||||||
import MutationButton from "../../../components/form/mutation-button";
|
import MutationButton from "../../../components/form/mutation-button";
|
||||||
import { useLocation, useSearch } from "wouter";
|
import { useLocation, useSearch } from "wouter";
|
||||||
import { useApproveInteractionRequestMutation, useLazySearchInteractionRequestsQuery, useRejectInteractionRequestMutation } from "../../../lib/query/user/interactions";
|
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 { Checkbox } from "../../../components/form/inputs";
|
||||||
import { useContent, useIcon, useNoun, useVerbed } from "./util";
|
import { useContent, useIcon, useNoun, useVerbed } from "./util";
|
||||||
|
|
||||||
|
@ -46,16 +47,16 @@ export default function InteractionRequestsSearchForm() {
|
||||||
// urlQueryParams, to allow paging.
|
// urlQueryParams, to allow paging.
|
||||||
const form = {
|
const form = {
|
||||||
statusID: useTextInput("status_id", {
|
statusID: useTextInput("status_id", {
|
||||||
defaultValue: urlQueryParams.get("status_id") ?? ""
|
defaultValue: urlQueryParams.get("status_id") ?? "",
|
||||||
}),
|
}),
|
||||||
likes: useBoolInput("favourites", {
|
likes: useBoolInput("favourites", {
|
||||||
defaultValue: defaultTrue(urlQueryParams.get("favourites"))
|
defaultValue: defaultTrue(urlQueryParams.get("favourites")),
|
||||||
}),
|
}),
|
||||||
replies: useBoolInput("replies", {
|
replies: useBoolInput("replies", {
|
||||||
defaultValue: defaultTrue(urlQueryParams.get("replies"))
|
defaultValue: defaultTrue(urlQueryParams.get("replies")),
|
||||||
}),
|
}),
|
||||||
boosts: useBoolInput("reblogs", {
|
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
|
// Store the back location in history so
|
||||||
// the detail view can use it to return to
|
// the detail view can use it to return to
|
||||||
// this page (including query parameters).
|
// this page (including query parameters).
|
||||||
state: { backLocation: backLocation }
|
state: { backLocation: backLocation },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
role="link"
|
role="link"
|
||||||
|
|
|
@ -20,8 +20,9 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import sanitize from "sanitize-html";
|
import sanitize from "sanitize-html";
|
||||||
import { compile, HtmlToTextOptions } from "html-to-text";
|
import type { HtmlToTextOptions } from "html-to-text";
|
||||||
import { Status } from "../../../lib/types/status";
|
import { compile } from "html-to-text";
|
||||||
|
import type { Status } from "../../../lib/types/status";
|
||||||
|
|
||||||
// Options for converting HTML statuses
|
// Options for converting HTML statuses
|
||||||
// to plaintext representations.
|
// to plaintext representations.
|
||||||
|
@ -29,7 +30,7 @@ const convertOptions: HtmlToTextOptions = {
|
||||||
selectors: [
|
selectors: [
|
||||||
// Don't fancy format links, just use their text value.
|
// Don't fancy format links, just use their text value.
|
||||||
{ selector: 'a', options: { ignoreHref: true } },
|
{ selector: 'a', options: { ignoreHref: true } },
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
const convertHTML = compile(convertOptions);
|
const convertHTML = compile(convertOptions);
|
||||||
|
|
||||||
|
|
|
@ -142,8 +142,8 @@ function AlsoKnownAsURI({ index, data }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function MoveForm({ data: profile }) {
|
function MoveForm({ data: profile }) {
|
||||||
let urlStr = store.getState().oauth.instanceUrl ?? "";
|
const urlStr = store.getState().oauth.instanceUrl ?? "";
|
||||||
let url = new URL(urlStr);
|
const url = new URL(urlStr);
|
||||||
|
|
||||||
const form = {
|
const form = {
|
||||||
movedToURI: useTextInput("moved_to_uri", {
|
movedToURI: useTextInput("moved_to_uri", {
|
||||||
|
@ -162,10 +162,10 @@ function MoveForm({ data: profile }) {
|
||||||
<div className="form-section-docs">
|
<div className="form-section-docs">
|
||||||
<h3>Move Account</h3>
|
<h3>Move Account</h3>
|
||||||
<p>
|
<p>
|
||||||
For a move to be successful, you must have already set an alias from the
|
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),
|
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.
|
using the settings panel of the instance on which the target account resides.
|
||||||
To do this, provide the following details to the other instance:
|
To do this, provide the following details to the other instance:
|
||||||
</p>
|
</p>
|
||||||
<dl className="migration-details">
|
<dl className="migration-details">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { Select, Checkbox } from "../../../../components/form/inputs";
|
||||||
import Languages from "../../../../components/languages";
|
import Languages from "../../../../components/languages";
|
||||||
import MutationButton from "../../../../components/form/mutation-button";
|
import MutationButton from "../../../../components/form/mutation-button";
|
||||||
import { useUpdateCredentialsMutation } from "../../../../lib/query/user";
|
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 }) {
|
export default function BasicSettings({ account }: { account: Account }) {
|
||||||
/* form keys
|
/* form keys
|
||||||
|
@ -36,7 +36,7 @@ export default function BasicSettings({ account }: { account: Account }) {
|
||||||
const form = {
|
const form = {
|
||||||
defaultPrivacy: useTextInput("source[privacy]", { source: account, defaultValue: "unlisted" }),
|
defaultPrivacy: useTextInput("source[privacy]", { source: account, defaultValue: "unlisted" }),
|
||||||
isSensitive: useBoolInput("source[sensitive]", { source: account }),
|
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" }),
|
statusContentType: useTextInput("source[status_content_type]", { source: account, defaultValue: "text/plain" }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export default function BasicSettings({ account }: { account: Account }) {
|
||||||
className="docslink"
|
className="docslink"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
Learn more about these settings (opens in a new tab)
|
Learn more about these settings (opens in a new tab)
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Select field={form.language} label="Default post language" options={
|
<Select field={form.language} label="Default post language" options={
|
||||||
|
|
|
@ -18,15 +18,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
|
import type {
|
||||||
|
InteractionPolicyValue} from "../../../../lib/types/interaction";
|
||||||
import {
|
import {
|
||||||
InteractionPolicyValue,
|
|
||||||
PolicyValueAuthor,
|
PolicyValueAuthor,
|
||||||
PolicyValueFollowers,
|
PolicyValueFollowers,
|
||||||
PolicyValueMentioned,
|
PolicyValueMentioned,
|
||||||
PolicyValuePublic,
|
PolicyValuePublic,
|
||||||
} from "../../../../lib/types/interaction";
|
} from "../../../../lib/types/interaction";
|
||||||
import { useTextInput } from "../../../../lib/form";
|
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,
|
// Based on the given visibility, action, and states,
|
||||||
// derives what the initial basic Select value should be.
|
// derives what the initial basic Select value should be.
|
||||||
|
|
|
@ -26,11 +26,12 @@ import {
|
||||||
import Loading from "../../../../components/loading";
|
import Loading from "../../../../components/loading";
|
||||||
import { Error } from "../../../../components/error";
|
import { Error } from "../../../../components/error";
|
||||||
import MutationButton from "../../../../components/form/mutation-button";
|
import MutationButton from "../../../../components/form/mutation-button";
|
||||||
import {
|
import type {
|
||||||
DefaultInteractionPolicies,
|
DefaultInteractionPolicies,
|
||||||
InteractionPolicy,
|
InteractionPolicy,
|
||||||
InteractionPolicyEntry,
|
InteractionPolicyEntry,
|
||||||
InteractionPolicyValue,
|
InteractionPolicyValue} from "../../../../lib/types/interaction";
|
||||||
|
import {
|
||||||
PolicyValueAuthor,
|
PolicyValueAuthor,
|
||||||
PolicyValueFollowers,
|
PolicyValueFollowers,
|
||||||
PolicyValueFollowing,
|
PolicyValueFollowing,
|
||||||
|
@ -39,10 +40,11 @@ import {
|
||||||
} from "../../../../lib/types/interaction";
|
} from "../../../../lib/types/interaction";
|
||||||
import { useTextInput } from "../../../../lib/form";
|
import { useTextInput } from "../../../../lib/form";
|
||||||
import { Select } from "../../../../components/form/inputs";
|
import { Select } from "../../../../components/form/inputs";
|
||||||
import { TextFormInputHook } from "../../../../lib/form/types";
|
import type { TextFormInputHook } from "../../../../lib/form/types";
|
||||||
import { useBasicFor } from "./basic";
|
import { useBasicFor } from "./basic";
|
||||||
import { PolicyFormSomethingElse, useSomethingElseFor } from "./something-else";
|
import type { PolicyFormSomethingElse} from "./something-else";
|
||||||
import { Action, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
|
import { useSomethingElseFor } from "./something-else";
|
||||||
|
import type { Action, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
|
||||||
|
|
||||||
export default function InteractionPolicySettings() {
|
export default function InteractionPolicySettings() {
|
||||||
const {
|
const {
|
||||||
|
@ -134,7 +136,7 @@ function InteractionPoliciesForm({ defaultPolicies }: InteractionPoliciesFormPro
|
||||||
these settings; they do not apply retroactively.
|
these settings; they do not apply retroactively.
|
||||||
<br/>
|
<br/>
|
||||||
The word "anyone" in the below options means <em>anyone with
|
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/>
|
<br/>
|
||||||
Bear in mind that no matter what you set below, you will always
|
Bear in mind that no matter what you set below, you will always
|
||||||
be able to like, reply-to, and boost your own posts.
|
be able to like, reply-to, and boost your own posts.
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useMemo } from "react";
|
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 { useTextInput } from "../../../../lib/form";
|
||||||
import { Action, Audience, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
|
import type { Action, Audience, PolicyFormSub, SomethingElseValue, Visibility } from "./types";
|
||||||
|
|
||||||
export interface PolicyFormSomethingElse {
|
export interface PolicyFormSomethingElse {
|
||||||
followers: PolicyFormSub,
|
followers: PolicyFormSub,
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { TextFormInputHook } from "../../../../lib/form/types";
|
import type { TextFormInputHook } from "../../../../lib/form/types";
|
||||||
import React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
export interface PolicyFormSub {
|
export interface PolicyFormSub {
|
||||||
field: TextFormInputHook;
|
field: TextFormInputHook;
|
||||||
|
|
|
@ -34,18 +34,17 @@ import {
|
||||||
TextArea,
|
TextArea,
|
||||||
FileInput,
|
FileInput,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Select
|
Select,
|
||||||
} from "../../components/form/inputs";
|
} from "../../components/form/inputs";
|
||||||
|
|
||||||
import FormWithData from "../../lib/form/form-with-data";
|
import FormWithData from "../../lib/form/form-with-data";
|
||||||
import FakeProfile from "../../components/profile";
|
import FakeProfile from "../../components/profile";
|
||||||
import MutationButton from "../../components/form/mutation-button";
|
import MutationButton from "../../components/form/mutation-button";
|
||||||
|
|
||||||
import { useAccountThemesQuery } from "../../lib/query/user";
|
import { useAccountThemesQuery , useUpdateCredentialsMutation } from "../../lib/query/user";
|
||||||
import { useUpdateCredentialsMutation } from "../../lib/query/user";
|
|
||||||
import { useVerifyCredentialsQuery } from "../../lib/query/oauth";
|
import { useVerifyCredentialsQuery } from "../../lib/query/oauth";
|
||||||
import { useInstanceV1Query } from "../../lib/query/gts-api";
|
import { useInstanceV1Query } from "../../lib/query/gts-api";
|
||||||
import { Account } from "../../lib/types/account";
|
import type { Account } from "../../lib/types/account";
|
||||||
|
|
||||||
export default function UserProfile() {
|
export default function UserProfile() {
|
||||||
return (
|
return (
|
||||||
|
@ -78,18 +77,18 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
|
||||||
const { data: instance } = useInstanceV1Query();
|
const { data: instance } = useInstanceV1Query();
|
||||||
const instanceConfig = React.useMemo(() => {
|
const instanceConfig = React.useMemo(() => {
|
||||||
return {
|
return {
|
||||||
allowCustomCSS: instance?.configuration?.accounts?.allow_custom_css === true,
|
allowCustomCSS: instance?.configuration.accounts.allow_custom_css === true,
|
||||||
maxPinnedFields: instance?.configuration?.accounts?.max_profile_fields ?? 6
|
maxPinnedFields: instance?.configuration.accounts.max_profile_fields ?? 6,
|
||||||
};
|
};
|
||||||
}, [instance]);
|
}, [instance]);
|
||||||
|
|
||||||
// Parse out available theme options into nice format.
|
// Parse out available theme options into nice format.
|
||||||
const { data: themes } = useAccountThemesQuery();
|
const { data: themes } = useAccountThemesQuery();
|
||||||
const themeOptions = useMemo(() => {
|
const themeOptions = useMemo(() => {
|
||||||
let themeOptions = [
|
const themeOptions = [
|
||||||
<option key="" value="">
|
<option key="" value="">
|
||||||
Default
|
Default
|
||||||
</option>
|
</option>,
|
||||||
];
|
];
|
||||||
|
|
||||||
themes?.forEach((theme) => {
|
themes?.forEach((theme) => {
|
||||||
|
@ -101,7 +100,7 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
|
||||||
themeOptions.push(
|
themeOptions.push(
|
||||||
<option key={value} value={value}>
|
<option key={value} value={value}>
|
||||||
{text}
|
{text}
|
||||||
</option>
|
</option>,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -122,8 +121,8 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
|
||||||
hideCollections: useBoolInput("hide_collections", { source: profile }),
|
hideCollections: useBoolInput("hide_collections", { source: profile }),
|
||||||
webVisibility: useTextInput("web_visibility", { source: profile, valueSelector: (p) => p.source?.web_visibility }),
|
webVisibility: useTextInput("web_visibility", { source: profile, valueSelector: (p) => p.source?.web_visibility }),
|
||||||
fields: useFieldArrayInput("fields_attributes", {
|
fields: useFieldArrayInput("fields_attributes", {
|
||||||
defaultValue: profile?.source?.fields,
|
defaultValue: profile.source?.fields,
|
||||||
length: instanceConfig.maxPinnedFields
|
length: instanceConfig.maxPinnedFields,
|
||||||
}),
|
}),
|
||||||
customCSS: useTextInput("custom_css", { source: profile, nosubmit: !instanceConfig.allowCustomCSS }),
|
customCSS: useTextInput("custom_css", { source: profile, nosubmit: !instanceConfig.allowCustomCSS }),
|
||||||
theme: useTextInput("theme", { source: profile }),
|
theme: useTextInput("theme", { source: profile }),
|
||||||
|
@ -134,7 +133,7 @@ function UserProfileForm({ data: profile }: UserProfileFormProps) {
|
||||||
onFinish: () => {
|
onFinish: () => {
|
||||||
form.avatar.reset();
|
form.avatar.reset();
|
||||||
form.header.reset();
|
form.header.reset();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const noAvatarSet = !profile.avatar_media_id;
|
const noAvatarSet = !profile.avatar_media_id;
|
||||||
|
@ -322,7 +321,7 @@ function ProfileFields({ field: formField }) {
|
||||||
function Field({ index, data }) {
|
function Field({ index, data }) {
|
||||||
const form = useWithFormContext(index, {
|
const form = useWithFormContext(index, {
|
||||||
name: useTextInput("name", { defaultValue: data.name }),
|
name: useTextInput("name", { defaultValue: data.name }),
|
||||||
value: useTextInput("value", { defaultValue: data.value })
|
value: useTextInput("value", { defaultValue: data.value }),
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue