mirror of
https://github.com/morpheus65535/bazarr
synced 2024-12-25 09:12:38 +00:00
Try to fix languages profiles editor by introducing a new submit hooks source in the settings page #1924
This commit is contained in:
parent
70fe14562f
commit
c08ba5f793
3 changed files with 139 additions and 51 deletions
|
@ -10,30 +10,13 @@ import { Badge, Container, Group, LoadingOverlay } from "@mantine/core";
|
|||
import { useForm } from "@mantine/form";
|
||||
import { useDocumentTitle } from "@mantine/hooks";
|
||||
import { FunctionComponent, ReactNode, useCallback, useMemo } from "react";
|
||||
import { enabledLanguageKey, languageProfileKey } from "../keys";
|
||||
import { FormContext, FormValues } from "../utilities/FormValues";
|
||||
import {
|
||||
SubmitHooksProvider,
|
||||
useSubmitHooksSource,
|
||||
} from "../utilities/HooksProvider";
|
||||
import { SettingsProvider } from "../utilities/SettingsProvider";
|
||||
|
||||
type SubmitHookType = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: (value: any) => unknown;
|
||||
};
|
||||
|
||||
export const submitHooks: SubmitHookType = {
|
||||
[languageProfileKey]: (value) => JSON.stringify(value),
|
||||
[enabledLanguageKey]: (value: Language.Info[]) => value.map((v) => v.code2),
|
||||
};
|
||||
|
||||
function invokeHooks(settings: LooseObject) {
|
||||
for (const key in settings) {
|
||||
if (key in submitHooks) {
|
||||
const value = settings[key];
|
||||
const fn = submitHooks[key];
|
||||
settings[key] = fn(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
children: ReactNode;
|
||||
|
@ -45,6 +28,8 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
const { data: settings, isLoading, isRefetching } = useSystemSettings();
|
||||
const { mutate, isLoading: isMutating } = useSettingsMutation();
|
||||
|
||||
const submitHooks = useSubmitHooksSource();
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
initialValues: {
|
||||
settings: {},
|
||||
|
@ -66,7 +51,7 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
|
||||
if (Object.keys(settings).length > 0) {
|
||||
const settingsToSubmit = { ...settings };
|
||||
invokeHooks(settingsToSubmit);
|
||||
submitHooks.invoke(settingsToSubmit);
|
||||
LOG("info", "submitting settings", settingsToSubmit);
|
||||
mutate(settingsToSubmit);
|
||||
}
|
||||
|
@ -77,7 +62,7 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
updateStorage(storagesToSubmit);
|
||||
}
|
||||
},
|
||||
[mutate, updateStorage]
|
||||
[mutate, submitHooks, updateStorage]
|
||||
);
|
||||
|
||||
const totalStagedCount = useMemo(() => {
|
||||
|
@ -100,6 +85,7 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
return (
|
||||
<SettingsProvider value={settings}>
|
||||
<LoadingProvider value={isLoading || isMutating}>
|
||||
<SubmitHooksProvider value={submitHooks}>
|
||||
<form onSubmit={form.onSubmit(submit)}>
|
||||
<Toolbox>
|
||||
<Group>
|
||||
|
@ -109,7 +95,11 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
loading={isMutating}
|
||||
disabled={totalStagedCount === 0}
|
||||
rightIcon={
|
||||
<Badge size="xs" radius="sm" hidden={totalStagedCount === 0}>
|
||||
<Badge
|
||||
size="xs"
|
||||
radius="sm"
|
||||
hidden={totalStagedCount === 0}
|
||||
>
|
||||
{totalStagedCount}
|
||||
</Badge>
|
||||
}
|
||||
|
@ -124,6 +114,7 @@ const Layout: FunctionComponent<Props> = (props) => {
|
|||
</Container>
|
||||
</FormContext.Provider>
|
||||
</form>
|
||||
</SubmitHooksProvider>
|
||||
</LoadingProvider>
|
||||
</SettingsProvider>
|
||||
);
|
||||
|
|
95
frontend/src/pages/Settings/utilities/HooksProvider.tsx
Normal file
95
frontend/src/pages/Settings/utilities/HooksProvider.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
import {
|
||||
createContext,
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { enabledLanguageKey, languageProfileKey } from "../keys";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type HookType = (value: any) => unknown;
|
||||
|
||||
export type SubmitHookType = {
|
||||
[key: string]: HookType;
|
||||
};
|
||||
|
||||
export type SubmitHookModifierType = {
|
||||
add: (key: string, fn: HookType) => void;
|
||||
remove: (key: string) => void;
|
||||
invoke: (settings: LooseObject) => void;
|
||||
};
|
||||
|
||||
const SubmitHooksContext = createContext<SubmitHookModifierType | null>(null);
|
||||
|
||||
type SubmitHooksProviderProps = {
|
||||
value: SubmitHookModifierType;
|
||||
};
|
||||
|
||||
export const SubmitHooksProvider: FunctionComponent<
|
||||
SubmitHooksProviderProps
|
||||
> = ({ value, children }) => {
|
||||
return (
|
||||
<SubmitHooksContext.Provider value={value}>
|
||||
{children}
|
||||
</SubmitHooksContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function useSubmitHooks() {
|
||||
const context = useContext(SubmitHooksContext);
|
||||
|
||||
if (context === null) {
|
||||
throw new Error(
|
||||
"useSubmitHooksModifier must be used within a SubmitHooksProvider"
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export function useSubmitHooksSource(): SubmitHookModifierType {
|
||||
const [submitHooks, setSubmitHooks] = useState<SubmitHookType>({
|
||||
[languageProfileKey]: (value) => JSON.stringify(value),
|
||||
[enabledLanguageKey]: (value: Language.Info[]) => value.map((v) => v.code2),
|
||||
});
|
||||
const hooksRef = useRef(submitHooks);
|
||||
|
||||
const invokeHooks = useCallback((settings: LooseObject) => {
|
||||
const hooks = hooksRef.current;
|
||||
for (const key in settings) {
|
||||
if (key in hooks) {
|
||||
const value = settings[key];
|
||||
const fn = hooks[key];
|
||||
settings[key] = fn(value);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const addHook = useCallback(
|
||||
(key: string, fn: (value: unknown) => unknown) => {
|
||||
setSubmitHooks((hooks) => ({ ...hooks, [key]: fn }));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const removeHook = useCallback((key: string) => {
|
||||
setSubmitHooks((hooks) => {
|
||||
const newHooks = { ...hooks };
|
||||
delete newHooks[key];
|
||||
|
||||
return newHooks;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
add: addHook,
|
||||
remove: removeHook,
|
||||
invoke: invokeHooks,
|
||||
}),
|
||||
[addHook, invokeHooks, removeHook]
|
||||
);
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
import { LOG } from "@/utilities/console";
|
||||
import { get, isNull, isUndefined, uniqBy } from "lodash";
|
||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { submitHooks } from "../components";
|
||||
import {
|
||||
FormKey,
|
||||
useFormActions,
|
||||
useStagedValues,
|
||||
} from "../utilities/FormValues";
|
||||
import { useSettings } from "../utilities/SettingsProvider";
|
||||
import { useSubmitHooks } from "./HooksProvider";
|
||||
|
||||
export interface BaseInput<T> {
|
||||
disabled?: boolean;
|
||||
|
@ -52,20 +52,22 @@ export function useSettingValue<T>(
|
|||
|
||||
const optionsRef = useRef(options);
|
||||
|
||||
const submitHooks = useSubmitHooks();
|
||||
|
||||
useEffect(() => {
|
||||
const onSubmit = optionsRef.current?.onSubmit;
|
||||
if (onSubmit) {
|
||||
LOG("info", "Adding submit hook for", key);
|
||||
submitHooks[key] = onSubmit;
|
||||
submitHooks.add(key, onSubmit);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (key in submitHooks) {
|
||||
LOG("info", "Removing submit hook for", key);
|
||||
delete submitHooks[key];
|
||||
submitHooks.remove(key);
|
||||
}
|
||||
};
|
||||
}, [key]);
|
||||
}, [key, submitHooks]);
|
||||
|
||||
const originalValue = useMemo(() => {
|
||||
const onLoaded = optionsRef.current?.onLoaded;
|
||||
|
|
Loading…
Reference in a new issue