diff options
author | LASER-Yi <[email protected]> | 2022-10-25 08:22:00 +0800 |
---|---|---|
committer | LASER-Yi <[email protected]> | 2022-10-25 08:22:06 +0800 |
commit | c08ba5f7937fcd86533a91ddc1a0675d7fc623fb (patch) | |
tree | 95d9fbd0ce9ef8e00b19c0d5cb697c0788fee038 /frontend | |
parent | 70fe14562f788c514666a7a87fa736f30aad1139 (diff) | |
download | bazarr-c08ba5f7937fcd86533a91ddc1a0675d7fc623fb.tar.gz bazarr-c08ba5f7937fcd86533a91ddc1a0675d7fc623fb.zip |
Try to fix languages profiles editor by introducing a new submit hooks source in the settings page #1924v1.1.3-beta.6
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/src/pages/Settings/components/Layout.tsx | 85 | ||||
-rw-r--r-- | frontend/src/pages/Settings/utilities/HooksProvider.tsx | 95 | ||||
-rw-r--r-- | frontend/src/pages/Settings/utilities/hooks.ts | 10 |
3 files changed, 139 insertions, 51 deletions
diff --git a/frontend/src/pages/Settings/components/Layout.tsx b/frontend/src/pages/Settings/components/Layout.tsx index 7aae8a991..623893fff 100644 --- a/frontend/src/pages/Settings/components/Layout.tsx +++ b/frontend/src/pages/Settings/components/Layout.tsx @@ -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,30 +85,36 @@ const Layout: FunctionComponent<Props> = (props) => { return ( <SettingsProvider value={settings}> <LoadingProvider value={isLoading || isMutating}> - <form onSubmit={form.onSubmit(submit)}> - <Toolbox> - <Group> - <Toolbox.Button - type="submit" - icon={faSave} - loading={isMutating} - disabled={totalStagedCount === 0} - rightIcon={ - <Badge size="xs" radius="sm" hidden={totalStagedCount === 0}> - {totalStagedCount} - </Badge> - } - > - Save - </Toolbox.Button> - </Group> - </Toolbox> - <FormContext.Provider value={form}> - <Container size="xl" mx={0}> - {children} - </Container> - </FormContext.Provider> - </form> + <SubmitHooksProvider value={submitHooks}> + <form onSubmit={form.onSubmit(submit)}> + <Toolbox> + <Group> + <Toolbox.Button + type="submit" + icon={faSave} + loading={isMutating} + disabled={totalStagedCount === 0} + rightIcon={ + <Badge + size="xs" + radius="sm" + hidden={totalStagedCount === 0} + > + {totalStagedCount} + </Badge> + } + > + Save + </Toolbox.Button> + </Group> + </Toolbox> + <FormContext.Provider value={form}> + <Container size="xl" mx={0}> + {children} + </Container> + </FormContext.Provider> + </form> + </SubmitHooksProvider> </LoadingProvider> </SettingsProvider> ); diff --git a/frontend/src/pages/Settings/utilities/HooksProvider.tsx b/frontend/src/pages/Settings/utilities/HooksProvider.tsx new file mode 100644 index 000000000..2c49f174a --- /dev/null +++ b/frontend/src/pages/Settings/utilities/HooksProvider.tsx @@ -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] + ); +} diff --git a/frontend/src/pages/Settings/utilities/hooks.ts b/frontend/src/pages/Settings/utilities/hooks.ts index 09f054cc3..5f011e7e9 100644 --- a/frontend/src/pages/Settings/utilities/hooks.ts +++ b/frontend/src/pages/Settings/utilities/hooks.ts @@ -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; |