diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/_atoms/_entry/_Entry.jsx b/src-ui/app/config_page/setting_section/setting_box/_components/_atoms/_entry/_Entry.jsx index d9b0d4cb..641e7104 100644 --- a/src-ui/app/config_page/setting_section/setting_box/_components/_atoms/_entry/_Entry.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/_components/_atoms/_entry/_Entry.jsx @@ -24,7 +24,7 @@ const _Entry = forwardRef((props, ref) => {
{ + const { t } = useTranslation(); + const onChangeFunction = (e) => { + props.onChangeFunction?.(e.target.value); + }; + const saveFunction = () => { + props.saveFunction(); + }; + const is_disabled = props.state === "pending"; + + const save_button_class_names = clsx(styles.save_button, { + [styles.is_disabled]: is_disabled + }); + + return ( +
+ <_Entry width={props.width} onChange={onChangeFunction} ui_variable={props.variable} is_disabled={is_disabled}/> + +
+ ); +}; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/entry_with_save_button/EntryWithSaveButton.module.scss b/src-ui/app/config_page/setting_section/setting_box/_components/entry_with_save_button/EntryWithSaveButton.module.scss new file mode 100644 index 00000000..deb86f89 --- /dev/null +++ b/src-ui/app/config_page/setting_section/setting_box/_components/entry_with_save_button/EntryWithSaveButton.module.scss @@ -0,0 +1,30 @@ +.container { + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + flex-shrink: 0; +} + +.save_button { + padding: 0.8rem 1.2rem; + background-color: var(--primary_600_color); + border-radius: 0.4rem; + text-align: center; + flex-shrink: 0; + min-width: 5.4rem; + &:hover { + background-color: var(--primary_500_color); + } + &:active { + background-color: var(--primary_700_color); + } + &.is_disabled { + pointer-events: none; + background-color: var(--primary_800_color); + } +} + +.save_button_label { + font-size: 1.4rem; +} \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/index.js b/src-ui/app/config_page/setting_section/setting_box/_components/index.js index 3a295d3c..7b695b35 100644 --- a/src-ui/app/config_page/setting_section/setting_box/_components/index.js +++ b/src-ui/app/config_page/setting_section/setting_box/_components/index.js @@ -3,6 +3,7 @@ export { ComputeDevice } from "./compute_device/ComputeDevice"; export { DeeplAuthKey, OpenWebpage_DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey"; export { DropdownMenu } from "./dropdown_menu/DropdownMenu"; export { Entry } from "./entry/Entry"; +export { EntryWithSaveButton } from "./entry_with_save_button/EntryWithSaveButton"; export { HotkeysEntry } from "./hotkeys_entry/HotkeysEntry"; export { LabelComponent } from "./label_component/LabelComponent"; export { RadioButton } from "./radio_button/RadioButton"; diff --git a/src-ui/app/config_page/setting_section/setting_box/_templates/Templates.jsx b/src-ui/app/config_page/setting_section/setting_box/_templates/Templates.jsx index 716a15c9..b25af8b9 100644 --- a/src-ui/app/config_page/setting_section/setting_box/_templates/Templates.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/_templates/Templates.jsx @@ -8,6 +8,7 @@ import { Slider, SwitchBox, Entry, + EntryWithSaveButton, HotkeysEntry, RadioButton, OpenWebpage_DeeplAuthKey, @@ -75,6 +76,9 @@ export const SwitchBoxContainer = (props) => ( export const EntryContainer = (props) => ( ); +export const EntryWithSaveButtonContainer = (props) => ( + +); export const HotkeysEntryContainer = (props) => ( diff --git a/src-ui/app/config_page/setting_section/setting_box/advanced_settings/AdvancedSettings.jsx b/src-ui/app/config_page/setting_section/setting_box/advanced_settings/AdvancedSettings.jsx index 94dcd358..966a3c21 100644 --- a/src-ui/app/config_page/setting_section/setting_box/advanced_settings/AdvancedSettings.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/advanced_settings/AdvancedSettings.jsx @@ -11,6 +11,7 @@ import { import { ActionButtonContainer, EntryContainer, + EntryWithSaveButtonContainer, } from "../_templates/Templates"; @@ -30,54 +31,58 @@ export const AdvancedSettings = () => { const OscIpAddressContainer = () => { const { t } = useTranslation(); - const [ui_variable, setUiVariable] = useState(""); const { currentOscIpAddress, setOscIpAddress } = useOscIpAddress(); - const onChangeFunction = (e) => { - const value = e.currentTarget.value; - if (value === "") { - setUiVariable(""); - } else { - setUiVariable(value); - setOscIpAddress(value); - } + const [input_value, seInputValue] = useState(currentOscIpAddress.data); + + const onChangeFunction = (value) => { + seInputValue(value); + }; + + const saveFunction = () => { + setOscIpAddress(input_value); }; useEffect(()=> { - setUiVariable(currentOscIpAddress.data); + seInputValue(currentOscIpAddress.data); }, [currentOscIpAddress]); return ( - ); }; const OscPortContainer = () => { const { t } = useTranslation(); - const [ui_variable, setUiVariable] = useState(""); const { currentOscPort, setOscPort } = useOscPort(); - const onChangeFunction = (e) => { - const value = e.currentTarget.value; - if (value === "") { - setUiVariable(""); - } else { - setUiVariable(value); - setOscPort(value); - } + const [input_value, seInputValue] = useState(currentOscPort.data); + + const onChangeFunction = (value) => { + seInputValue(value); + }; + + const saveFunction = () => { + setOscPort(input_value); }; useEffect(()=> { - setUiVariable(currentOscPort.data); + seInputValue(currentOscPort.data); }, [currentOscPort]); return ( - ); }; diff --git a/src-ui/logics/_useBackendErrorHandling.js b/src-ui/logics/_useBackendErrorHandling.js index 446330cc..1145cd80 100644 --- a/src-ui/logics/_useBackendErrorHandling.js +++ b/src-ui/logics/_useBackendErrorHandling.js @@ -14,6 +14,10 @@ import { useSpeakerMaxWords, useDeepLAuthKey, + + + useOscIpAddress, + useOscPort, } from "@logics_configs"; import { ui_configs } from "../ui_configs"; @@ -29,9 +33,13 @@ export const _useBackendErrorHandling = () => { const { updateSpeakerPhraseTimeout } = useSpeakerPhraseTimeout(); const { updateSpeakerMaxWords } = useSpeakerMaxWords(); - const { updateDeepLAuthKey } = useDeepLAuthKey(); + const { updateDeepLAuthKey, saveErrorDeepLAuthKey } = useDeepLAuthKey(); - const errorHandling_Backend = ({message, data, endpoint}) => { + + const { saveErrorOscIpAddress } = useOscIpAddress(); + const { saveErrorOscPort } = useOscPort(); + + const errorHandling_Backend = ({message, data, endpoint, _result}) => { switch (message) { case "No mic device detected": showNotification_Error(t("common_error.no_device_mic")); @@ -111,8 +119,12 @@ export const _useBackendErrorHandling = () => { break; default: - if (endpoint === "/set/data/deepl_auth_key") updateDeepLAuthKey(data); - showNotification_Error(message); + // determine by endpoint, not message. + if (endpoint === "/set/data/deepl_auth_key") saveErrorDeepLAuthKey({message, data, endpoint, _result}); + if (endpoint === "/set/data/osc_ip_address") saveErrorOscIpAddress({message, data, endpoint, _result}); + if (endpoint === "/set/data/osc_port") saveErrorOscPort({message, data, endpoint, _result}); + + break; } diff --git a/src-ui/logics/configs/advanced_settings/useOscIpAddress.js b/src-ui/logics/configs/advanced_settings/useOscIpAddress.js index 702a6d98..354e2751 100644 --- a/src-ui/logics/configs/advanced_settings/useOscIpAddress.js +++ b/src-ui/logics/configs/advanced_settings/useOscIpAddress.js @@ -1,7 +1,9 @@ import { useStore_OscIpAddress } from "@store"; import { useStdoutToPython } from "@logics/useStdoutToPython"; +import { useNotificationStatus } from "@logics_common"; export const useOscIpAddress = () => { + const { showNotification_Error } = useNotificationStatus(); const { asyncStdoutToPython } = useStdoutToPython(); const { currentOscIpAddress, updateOscIpAddress, pendingOscIpAddress } = useStore_OscIpAddress(); @@ -15,10 +17,17 @@ export const useOscIpAddress = () => { asyncStdoutToPython("/set/data/osc_ip_address", osc_ip_address); }; + const saveErrorOscIpAddress = ({data, message, _result}) => { + updateOscIpAddress(d => d.data); + showNotification_Error(_result); + }; + return { currentOscIpAddress, getOscIpAddress, updateOscIpAddress, setOscIpAddress, + + saveErrorOscIpAddress, }; }; \ No newline at end of file diff --git a/src-ui/logics/configs/advanced_settings/useOscPort.js b/src-ui/logics/configs/advanced_settings/useOscPort.js index 947d613d..d3e28557 100644 --- a/src-ui/logics/configs/advanced_settings/useOscPort.js +++ b/src-ui/logics/configs/advanced_settings/useOscPort.js @@ -1,7 +1,9 @@ import { useStore_OscPort } from "@store"; import { useStdoutToPython } from "@logics/useStdoutToPython"; +import { useNotificationStatus } from "@logics_common"; export const useOscPort = () => { + const { showNotification_Error } = useNotificationStatus(); const { asyncStdoutToPython } = useStdoutToPython(); const { currentOscPort, updateOscPort, pendingOscPort } = useStore_OscPort(); @@ -15,10 +17,17 @@ export const useOscPort = () => { asyncStdoutToPython("/set/data/osc_port", osc_port); }; + const saveErrorOscPort = ({data, message, _result}) => { + updateOscPort(d => d.data); + showNotification_Error(_result); + }; + return { currentOscPort, getOscPort, updateOscPort, setOscPort, + + saveErrorOscPort, }; }; \ No newline at end of file diff --git a/src-ui/logics/configs/translation/useDeepLAuthKey.js b/src-ui/logics/configs/translation/useDeepLAuthKey.js index 3d66dfba..f93fdd4f 100644 --- a/src-ui/logics/configs/translation/useDeepLAuthKey.js +++ b/src-ui/logics/configs/translation/useDeepLAuthKey.js @@ -18,22 +18,30 @@ export const useDeepLAuthKey = () => { pendingDeepLAuthKey(); asyncStdoutToPython("/set/data/deepl_auth_key", selected_deepl_auth_key); }; - const saveSuccessDeepLAuthKey = (saved_deepl_auth_key) => { - updateDeepLAuthKey(saved_deepl_auth_key); - showNotification_Success(t("config_page.translation.deepl_auth_key.auth_key_success")); - }; const deleteDeepLAuthKey = () => { pendingDeepLAuthKey(); asyncStdoutToPython("/delete/data/deepl_auth_key"); }; + const savedDeepLAuthKey = (data) => { + updateDeepLAuthKey(data); + showNotification_Success(t("config_page.translation.deepl_auth_key.auth_key_success")); + }; + + const saveErrorDeepLAuthKey = ({data, message}) => { + updateDeepLAuthKey(data); + showNotification_Error(message); + }; + return { currentDeepLAuthKey, getDeepLAuthKey, updateDeepLAuthKey, setDeepLAuthKey, - saveSuccessDeepLAuthKey, deleteDeepLAuthKey, + + saveErrorDeepLAuthKey, + savedDeepLAuthKey, }; }; \ No newline at end of file diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index 53a2feb3..383f1faf 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -148,7 +148,7 @@ export const useReceiveRoutes = () => { const { updateSpeakerPhraseTimeout } = useSpeakerPhraseTimeout(); const { updateSpeakerMaxWords } = useSpeakerMaxWords(); - const { updateDeepLAuthKey, saveSuccessDeepLAuthKey } = useDeepLAuthKey(); + const { updateDeepLAuthKey, savedDeepLAuthKey } = useDeepLAuthKey(); const { updateSelectedCTranslate2WeightType } = useSelectedCTranslate2WeightType(); const { updateDownloadedCTranslate2WeightTypeStatus, @@ -352,7 +352,7 @@ export const useReceiveRoutes = () => { // Translation "/get/data/deepl_auth_key": updateDeepLAuthKey, - "/set/data/deepl_auth_key": saveSuccessDeepLAuthKey, + "/set/data/deepl_auth_key": savedDeepLAuthKey, "/delete/data/deepl_auth_key": () => updateDeepLAuthKey(""), "/get/data/ctranslate2_weight_type": updateSelectedCTranslate2WeightType, @@ -523,6 +523,9 @@ export const useReceiveRoutes = () => { "/set/data/speaker_record_timeout": errorHandling_Backend, "/set/data/speaker_phrase_timeout": errorHandling_Backend, "/set/data/speaker_max_phrases": errorHandling_Backend, + + "/set/data/osc_ip_address": errorHandling_Backend, + "/set/data/osc_port": errorHandling_Backend, }; @@ -555,12 +558,14 @@ export const useReceiveRoutes = () => { break; case 400: + case 500: const error_route = error_status_routes[parsed_data.endpoint]; if (error_route) { error_route({ message: parsed_data.result.message, data: parsed_data.result.data, endpoint: parsed_data.endpoint, + _result: parsed_data.result, }); } else { handleInvalidEndpoint(parsed_data);