From ddcf49e2434ec247f52df41e8893b584c23ef881 Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:01:32 +0900 Subject: [PATCH 1/7] [Refactor] Integrate DeepL authentication key URL and enhance OpenWebpage_DeeplAuthKey component to accept props. --- src-ui/logics/ui_configs.js | 4 ++++ .../_components/deepl_auth_key/DeeplAuthKey.jsx | 7 +++---- .../setting_section/setting_box/_templates/Templates.jsx | 2 +- .../setting_box/translation/Translation.jsx | 4 ++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src-ui/logics/ui_configs.js b/src-ui/logics/ui_configs.js index dc941165..191693c8 100644 --- a/src-ui/logics/ui_configs.js +++ b/src-ui/logics/ui_configs.js @@ -128,5 +128,9 @@ export const whisper_weight_type_status = [ { id: "large-v3-turbo", capacity: "1.58GB"}, ].map(item => ({ ...item, is_downloaded: false, progress: null })); + +export const deepl_auth_key_url = "https://www.deepl.com/ja/your-account/keys"; + + export const supporters_data_url = "https://shiinasakamoto.github.io/vrct_supporters/assets/supporters/data.json"; export const supporters_images_url = "https://ShiinaSakamoto.github.io/vrct_supporters/assets/supporters"; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx index effdd2c9..7c71ffd7 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx @@ -59,12 +59,11 @@ export const DeeplAuthKey = (props) => { }; -export const OpenWebpage_DeeplAuthKey = () => { - const { t } = useI18n(); +export const OpenWebpage_DeeplAuthKey = (props) => { return (
- -

{t("config_page.translation.deepl_auth_key.open_auth_key_webpage")}

+
+

{props.open_webpage_label}

diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx index 96378587..700b9058 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx @@ -148,7 +148,7 @@ export const DeeplAuthKeyContainer = (props) => {
- +
diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index cb5ad232..4f1e27e6 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -22,6 +22,8 @@ import { LabelComponent, } from "../_components"; +import { deepl_auth_key_url } from "@ui_configs"; + export const Translation = () => { return ( <> @@ -230,6 +232,8 @@ const DeeplAuthKey_Box = () => { "config_page.translation.deepl_auth_key.desc", {translator: t("main_page.translator")} )} + webpage_url={deepl_auth_key_url} + open_webpage_label={t("config_page.translation.deepl_auth_key.open_auth_key_webpage")} variable={input_value} state={currentDeepLAuthKey.state} onChangeFunction={onChangeFunction} From ef4a19d0bb90f0be6320b6fb4f23069e1fff23cf Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:17:18 +0900 Subject: [PATCH 2/7] [Refactor] Implement _OpenWebpageButton component and integrate it into DeeplAuthKeyContainer. --- .../_OpenWebpageButton.jsx | 13 ++++++++ .../_OpenWebpageButton.module.scss | 32 ++++++++++++++++++ .../deepl_auth_key/DeeplAuthKey.jsx | 13 -------- .../deepl_auth_key/DeeplAuthKey.module.scss | 33 ------------------- .../setting_box/_components/index.js | 2 +- .../setting_box/_templates/Templates.jsx | 5 +-- 6 files changed, 49 insertions(+), 49 deletions(-) create mode 100644 src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx create mode 100644 src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx new file mode 100644 index 00000000..7df7b16f --- /dev/null +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx @@ -0,0 +1,13 @@ +import styles from "./_OpenWebpageButton.module.scss"; +import ExternalLink from "@images/external_link.svg?react"; + +export const _OpenWebpageButton = (props) => { + return ( +
+ +

{props.open_webpage_label}

+ +
+
+ ); +}; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss new file mode 100644 index 00000000..fd300952 --- /dev/null +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss @@ -0,0 +1,32 @@ +.open_webpage_button_wrapper { + display: flex; + justify-content: center; + align-items: center; +} + +.open_webpage_button { + padding: 0.6rem 2.8rem; + display: flex; + gap: 1rem; + justify-content: center; + align-items: center; + border-radius: 0.4rem; + cursor: pointer; + flex-shrink: 0; + &:hover { + background-color: var(--dark_825_color); + } + &:active { + background-color: var(--dark_900_color); + } +} + +.open_webpage_text { + font-size: 1.2rem; +} + +.external_link_svg { + color: var(--dark_500_color); + width: 1.6rem; + flex-shrink: 0; +} \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx index 7c71ffd7..3eaa21f9 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx @@ -2,7 +2,6 @@ import styles from "./DeeplAuthKey.module.scss"; import { useI18n } from "@useI18n"; import clsx from "clsx"; import CircularProgress from "@mui/material/CircularProgress"; -import ExternalLink from "@images/external_link.svg?react"; import { _Entry } from "../_atoms/_entry/_Entry"; import { useState, useRef } from "react"; import { useEffect } from "react"; @@ -56,16 +55,4 @@ export const DeeplAuthKey = (props) => { ); -}; - - -export const OpenWebpage_DeeplAuthKey = (props) => { - return ( -
- -

{props.open_webpage_label}

- -
-
- ); }; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss index 1f5a530e..ce58182c 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss @@ -62,37 +62,4 @@ .save_button_label { font-size: 1.4rem; -} - -.open_webpage_button_wrapper { - display: flex; - justify-content: center; - align-items: center; -} - -.open_webpage_button { - padding: 0.6rem 2.8rem; - display: flex; - gap: 1rem; - justify-content: center; - align-items: center; - border-radius: 0.4rem; - cursor: pointer; - flex-shrink: 0; - &:hover { - background-color: var(--dark_825_color); - } - &:active { - background-color: var(--dark_900_color); - } -} - -.open_webpage_text { - font-size: 1.2rem; -} - -.external_link_svg { - color: var(--dark_500_color); - width: 1.6rem; - flex-shrink: 0; } \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js index db5ad1cb..5d791c94 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js @@ -1,6 +1,6 @@ export { ActionButton } from "./action_button/ActionButton"; export { ComputeDevice } from "./compute_device/ComputeDevice"; -export { DeeplAuthKey, OpenWebpage_DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey"; +export { DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey"; export { DropdownMenu, MultiDropdownMenu } from "./dropdown_menu/DropdownMenu"; export { Entry } from "./entry/Entry"; export { EntryWithSaveButton } from "./entry_with_save_button/EntryWithSaveButton"; diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx index 700b9058..af2ba4d9 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx @@ -12,7 +12,6 @@ import { EntryWithSaveButton, HotkeysEntry, RadioButton, - OpenWebpage_DeeplAuthKey, DeeplAuthKey, ActionButton, ComputeDevice, @@ -23,6 +22,8 @@ import { } from "../_components"; import { Checkbox } from "@common_components"; +import { _OpenWebpageButton } from "../_components/_atoms/_open_webpage_button/_OpenWebpageButton"; + export const useOnMouseLeaveDropdownMenu = () => { const { updateIsOpenedDropdownMenu } = useStore_IsOpenedDropdownMenu(); @@ -148,7 +149,7 @@ export const DeeplAuthKeyContainer = (props) => {
- + <_OpenWebpageButton {...props} />
From 3a31b0a9fef002f220ee7997115b7e5c45d0031a Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Thu, 13 Nov 2025 12:58:34 +0900 Subject: [PATCH 3/7] [Refactor] Introduce AuthKey component and update related containers and styles. --- .../DeeplAuthKey.jsx => auth_key/AuthKey.jsx} | 4 ++-- .../AuthKey.module.scss} | 0 .../setting_box/_components/index.js | 2 +- .../label_component/LabelComponent.jsx | 2 ++ .../setting_box/_templates/Templates.jsx | 22 ++++++++----------- .../setting_box/translation/Translation.jsx | 4 ++-- 6 files changed, 16 insertions(+), 18 deletions(-) rename src-ui/views/app/config_page/setting_section/setting_box/_components/{deepl_auth_key/DeeplAuthKey.jsx => auth_key/AuthKey.jsx} (93%) rename src-ui/views/app/config_page/setting_section/setting_box/_components/{deepl_auth_key/DeeplAuthKey.module.scss => auth_key/AuthKey.module.scss} (100%) diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx similarity index 93% rename from src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx rename to src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx index 3eaa21f9..85ae9928 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx @@ -1,4 +1,4 @@ -import styles from "./DeeplAuthKey.module.scss"; +import styles from "./AuthKey.module.scss"; import { useI18n } from "@useI18n"; import clsx from "clsx"; import CircularProgress from "@mui/material/CircularProgress"; @@ -6,7 +6,7 @@ import { _Entry } from "../_atoms/_entry/_Entry"; import { useState, useRef } from "react"; import { useEffect } from "react"; -export const DeeplAuthKey = (props) => { +export const AuthKey = (props) => { const { t } = useI18n(); const [is_editable, seIsEditable] = useState(false); const entryRef = useRef(null); diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.module.scss similarity index 100% rename from src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss rename to src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.module.scss diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js index 5d791c94..2e7b54ca 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js @@ -1,6 +1,6 @@ export { ActionButton } from "./action_button/ActionButton"; export { ComputeDevice } from "./compute_device/ComputeDevice"; -export { DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey"; +export { AuthKey } from "./auth_key/AuthKey"; export { DropdownMenu, MultiDropdownMenu } from "./dropdown_menu/DropdownMenu"; export { Entry } from "./entry/Entry"; export { EntryWithSaveButton } from "./entry_with_save_button/EntryWithSaveButton"; diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx index a4a520db..ffcb9a89 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx @@ -1,4 +1,5 @@ import styles from "./LabelComponent.module.scss"; +import { _OpenWebpageButton } from "../_atoms/_open_webpage_button/_OpenWebpageButton"; export const LabelComponent = (props) => { return ( @@ -8,6 +9,7 @@ export const LabelComponent = (props) => { ?

{props.desc}

: null } + {props.webpage_url && <_OpenWebpageButton webpage_url={props.webpage_url} open_webpage_label={props.open_webpage_label} /> } ); }; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx index af2ba4d9..0c0845e1 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx @@ -12,7 +12,7 @@ import { EntryWithSaveButton, HotkeysEntry, RadioButton, - DeeplAuthKey, + AuthKey, ActionButton, ComputeDevice, WordFilter, @@ -22,8 +22,6 @@ import { } from "../_components"; import { Checkbox } from "@common_components"; -import { _OpenWebpageButton } from "../_components/_atoms/_open_webpage_button/_OpenWebpageButton"; - export const useOnMouseLeaveDropdownMenu = () => { const { updateIsOpenedDropdownMenu } = useStore_IsOpenedDropdownMenu(); @@ -97,7 +95,7 @@ const CommonContainer = ({ if (label_type === "label_component") { return ( - + ); @@ -110,7 +108,7 @@ const CommonContainer = ({ } else if (label_type === "label_only") { return ( - + ); } @@ -144,15 +142,13 @@ export const RadioButtonContainer = (props) => ( ); -export const DeeplAuthKeyContainer = (props) => { +export const AuthKeyContainer = (props) => { + const webpage_settings = { + webpage_url: props.webpage_url, + open_webpage_label: props.open_webpage_label, + }; return ( - -
- - <_OpenWebpageButton {...props} /> -
- -
+ ); }; diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index 4f1e27e6..b6ca3ec7 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -10,7 +10,7 @@ import { import { DownloadModelsContainer, - DeeplAuthKeyContainer, + AuthKeyContainer, MultiDropdownMenuContainer, useOnMouseLeaveDropdownMenu, @@ -226,7 +226,7 @@ const DeeplAuthKey_Box = () => { return ( <> - Date: Thu, 13 Nov 2025 15:55:00 +0900 Subject: [PATCH 4/7] [bugfix] Ensure the delete function is callable and correctly handled in config setters. --- .../config_page_setter/ui_config_setter.js | 27 +++++++++---------- .../config_page_setter/useSettingsLogics.js | 26 ++++++++++++++++++ src-ui/logics/useReceiveRoutes.js | 10 +++++++ .../setting_box/translation/Translation.jsx | 4 ++- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src-ui/logics/configs/config_page_setter/ui_config_setter.js b/src-ui/logics/configs/config_page_setter/ui_config_setter.js index 5b228cb4..4cc07310 100644 --- a/src-ui/logics/configs/config_page_setter/ui_config_setter.js +++ b/src-ui/logics/configs/config_page_setter/ui_config_setter.js @@ -226,7 +226,7 @@ export const SETTINGS_ARRAY = [ Base_Name: "DeepLAuthKey", default_value: "", ui_template_id: "input", - logics_template_id: "get_set", + logics_template_id: "get_set_delete", base_endpoint_name: "deepl_auth_key", }, @@ -558,24 +558,19 @@ for (const setting_data of SETTINGS_ARRAY) { const buildCategoryApiFromSettings = (settings, settingsArray, Category, extraFunctions = {}) => { const api = {}; const filtered = settingsArray.filter((s) => s.Category === Category); + const COMMON_PROPS = [ "current", "update", "get", "set", "toggle", "setSuccess", "delete", "deleteSuccess", "updateFromBackend" ]; for (const s of filtered) { const base = s.Base_Name; - const currentKey = `current${base}`; - const updateKey = `update${base}`; - const getKey = `get${base}`; - const setKey = `set${base}`; - const toggleKey = `toggle${base}`; - const setSuccessKey = `setSuccess${base}`; - const updateFromBackendKey = `updateFromBackend${base}`; - if (settings[currentKey] !== undefined) api[currentKey] = settings[currentKey]; - if (settings[updateKey] !== undefined) api[updateKey] = settings[updateKey]; - if (typeof settings[getKey] === "function") api[getKey] = settings[getKey]; - if (typeof settings[setKey] === "function") api[setKey] = settings[setKey]; - if (typeof settings[toggleKey] === "function") api[toggleKey] = settings[toggleKey]; - if (typeof settings[setSuccessKey] === "function") api[setSuccessKey] = settings[setSuccessKey]; - if (typeof settings[updateFromBackendKey] === "function") api[updateFromBackendKey] = settings[updateFromBackendKey]; + COMMON_PROPS.forEach(prop => { + const key = `${prop}${base}`; + const settingValue = settings[key]; + + if (settingValue !== undefined) { + api[key] = settingValue; + } + }); if (s.logics_template_id === "weight_download_status") { const updateDownloadProgressKey = `updateDownloadProgress${base}`; @@ -589,6 +584,8 @@ const buildCategoryApiFromSettings = (settings, settingsArray, Category, extraFu if (typeof settings[pendingKey] === "function") api[pendingKey] = settings[pendingKey]; if (typeof settings[downloadedKey] === "function") api[downloadedKey] = settings[downloadedKey]; if (typeof settings[downloadKey] === "function") api[downloadKey] = settings[downloadKey]; + + const updateFromBackendKey = `updateFromBackend${base}`; if (typeof settings[updateFromBackendKey] === "function") api[updateFromBackendKey] = settings[updateFromBackendKey]; } } diff --git a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js index a00d816b..63e714b9 100644 --- a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js +++ b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js @@ -55,8 +55,10 @@ export const useSettingsLogics = (settingsArray, Category) => { const updateFromBackendExportName = `updateFromBackend${base}`; const getExportName = `get${base}`; const setExportName = `set${base}`; + const deleteExportName = `delete${base}`; const toggleExportName = `toggle${base}`; const setSuccessExportName = `setSuccess${base}`; + const deleteSuccessExportName = `deleteSuccess${base}`; const runExportName = `runSuccess${base}`; @@ -75,6 +77,13 @@ export const useSettingsLogics = (settingsArray, Category) => { }; }; + const buildDelete = () => { + return (value) => { + if (pending) pending(); + asyncStdoutToPython(`/delete/data/${s.base_endpoint_name}`, value); + }; + }; + const buildRun = () => { return () => { asyncStdoutToPython(`/run/${s.base_endpoint_name}`); @@ -91,6 +100,14 @@ export const useSettingsLogics = (settingsArray, Category) => { }; }; + const buildDeleteSuccess = (transformName) => { + return (payload) => { + const transformed = transformResponse(transformName, payload); + if (update) update(transformed); + showNotification_SaveSuccess(); + }; + }; + const buildUpdateFromBackend = (transformName) => { return (payload) => { const transformed = transformResponse(transformName, payload); @@ -120,6 +137,15 @@ export const useSettingsLogics = (settingsArray, Category) => { continue; } + if (s.logics_template_id === "get_set_delete") { + result[getExportName] = buildGet(); + result[setExportName] = buildSet(); + result[setSuccessExportName] = buildSetSuccess(s.response_transform ?? null); + result[deleteExportName] = buildDelete(); + result[deleteSuccessExportName] = buildDeleteSuccess(s.response_transform ?? null); + continue; + } + if (s.logics_template_id === "toggle_enable_disable") { result[getExportName] = buildGet(); result[toggleExportName] = () => { diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index 5a6e6384..e9936936 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -210,6 +210,7 @@ const buildRouteMetaList = () => { const ep = s.base_endpoint_name; const hookName = `use${category}`; const setSuccessMethodName = `setSuccess${base}`; + const deleteSuccessMethodName = `deleteSuccess${base}`; const updateFromBackendMethodName = `updateFromBackend${base}`; @@ -231,6 +232,15 @@ const buildRouteMetaList = () => { method_name: updateFromBackendMethodName, }); + if (s.logics_template_id === "get_set_delete") { + generated.push({ + endpoint: `/delete/data/${ep}`, + ns: namespace_module, + hook_name: hookName, + method_name: deleteSuccessMethodName, + }); + } + if (s.logics_template_id !== "get_list") { generated.push({ endpoint: `/set/data/${ep}`, diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index b6ca3ec7..8a8e95cf 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -215,7 +215,9 @@ const DeeplAuthKey_Box = () => { }; const saveFunction = () => { - if (input_value === "") return deleteDeepLAuthKey(); + if (input_value === "" || input_value === null) { + return deleteDeepLAuthKey(); + }; setDeepLAuthKey(input_value); }; From 11c16fadbd7954524bb811acecc2c406212a8cea Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:40:25 +0900 Subject: [PATCH 5/7] [Update] UI: Add Plamo, OpenAI and Gemini authentication key components and integrate them into the Translation section. --- .../config_page_setter/ui_config_setter.js | 85 +++++++ .../config_page_setter/useSettingsLogics.js | 4 +- src-ui/logics/utils.js | 7 + .../setting_box/translation/Translation.jsx | 229 ++++++++++++++++++ 4 files changed, 324 insertions(+), 1 deletion(-) diff --git a/src-ui/logics/configs/config_page_setter/ui_config_setter.js b/src-ui/logics/configs/config_page_setter/ui_config_setter.js index 4cc07310..a59b8e2b 100644 --- a/src-ui/logics/configs/config_page_setter/ui_config_setter.js +++ b/src-ui/logics/configs/config_page_setter/ui_config_setter.js @@ -221,6 +221,7 @@ export const SETTINGS_ARRAY = [ logics_template_id: "get_set", base_endpoint_name: "selected_translation_compute_device", }, + // DeepL { Category: "Translation", Base_Name: "DeepLAuthKey", @@ -229,6 +230,90 @@ export const SETTINGS_ARRAY = [ logics_template_id: "get_set_delete", base_endpoint_name: "deepl_auth_key", }, + // Plamo + { + Category: "Translation", + Base_Name: "PlamoAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "plamo_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectablePlamoModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_plamo_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedPlamoModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_plamo_model", + }, + // Gemini + { + Category: "Translation", + Base_Name: "GeminiAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "gemini_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectableGeminiModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_gemini_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedGeminiModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_gemini_model", + }, + // OpenAI + { + Category: "Translation", + Base_Name: "OpenAIAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "openai_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectableOpenAIModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_openai_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedOpenAIModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_openai_model", + }, // Transcription // Mic diff --git a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js index 63e714b9..58702b06 100644 --- a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js +++ b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js @@ -1,7 +1,7 @@ import * as stores from "@store"; import { useStdoutToPython } from "@useStdoutToPython"; import { useNotificationStatus } from "@logics_common"; -import { arrayToObject } from "@utils"; +import { arrayToObject, arrayToIdLabel } from "@utils"; const transformResponse = (transformName, payload) => { if (!transformName) return payload; @@ -9,6 +9,8 @@ const transformResponse = (transformName, payload) => { switch (transformName) { case "arrayToObject": return arrayToObject(payload); + case "arrayToIdLabel": + return arrayToIdLabel(payload); default: return payload; } diff --git a/src-ui/logics/utils.js b/src-ui/logics/utils.js index 2f5f8bdc..bf7d3f19 100644 --- a/src-ui/logics/utils.js +++ b/src-ui/logics/utils.js @@ -5,6 +5,13 @@ export const arrayToObject = (array) => { }, {}); }; +export const arrayToIdLabel = (array) => { + return array.map((element) => ({ + id: element, + label: element, + })); +}; + export const chunkArray = (array, size) => { const chunked = []; for (let i = 0; i < array.length; i += size) { diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index 8a8e95cf..28b0f9f2 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -12,6 +12,8 @@ import { DownloadModelsContainer, AuthKeyContainer, MultiDropdownMenuContainer, + RadioButtonContainer, + DropdownMenuContainer, useOnMouseLeaveDropdownMenu, } from "../_templates/Templates"; @@ -29,7 +31,17 @@ export const Translation = () => { <> + + + + + + + + + + ); }; @@ -245,6 +257,223 @@ const DeeplAuthKey_Box = () => { ); }; +const PlamoAuthKey_Box = () => { + const { t } = useI18n(); + const { currentPlamoAuthKey, setPlamoAuthKey, deletePlamoAuthKey } = useTranslation(); + const [input_value, seInputValue] = useState(currentPlamoAuthKey.data); + + const onChangeFunction = (value) => { + seInputValue(value); + }; + + const saveFunction = () => { + if (input_value === "" || input_value === null) { + return deletePlamoAuthKey(); + }; + setPlamoAuthKey(input_value); + }; + + useEffect(() => { + if (currentPlamoAuthKey.state === "pending") return; + seInputValue(currentPlamoAuthKey.data); + }, [currentPlamoAuthKey]); + + return ( + <> + + + ); +}; +const PlamoModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectablePlamoModelList, + + currentSelectedPlamoModel, + setSelectedPlamoModel, + } = useTranslation(); + + if (currentSelectablePlamoModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedPlamoModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + + +const GeminiAuthKey_Box = () => { + const { t } = useI18n(); + const { currentGeminiAuthKey, setGeminiAuthKey, deleteGeminiAuthKey } = useTranslation(); + const [input_value, seInputValue] = useState(currentGeminiAuthKey.data); + + const onChangeFunction = (value) => { + seInputValue(value); + }; + + const saveFunction = () => { + if (input_value === "" || input_value === null) { + return deleteGeminiAuthKey(); + }; + setGeminiAuthKey(input_value); + }; + + useEffect(() => { + if (currentGeminiAuthKey.state === "pending") return; + seInputValue(currentGeminiAuthKey.data); + }, [currentGeminiAuthKey]); + + return ( + <> + + + ); +}; +const GeminiModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableGeminiModelList, + + currentSelectedGeminiModel, + setSelectedGeminiModel, + } = useTranslation(); + + if (currentSelectableGeminiModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedGeminiModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + +const OpenAIAuthKey_Box = () => { + const { t } = useI18n(); + const { currentOpenAIAuthKey, setOpenAIAuthKey, deleteOpenAIAuthKey } = useTranslation(); + const [input_value, seInputValue] = useState(currentOpenAIAuthKey.data); + + const onChangeFunction = (value) => { + seInputValue(value); + }; + + const saveFunction = () => { + if (input_value === "" || input_value === null) { + return deleteOpenAIAuthKey(); + }; + setOpenAIAuthKey(input_value); + }; + + useEffect(() => { + if (currentOpenAIAuthKey.state === "pending") return; + seInputValue(currentOpenAIAuthKey.data); + }, [currentOpenAIAuthKey]); + + return ( + <> + + + ); +}; +const OpenAIModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableOpenAIModelList, + + currentSelectedOpenAIModel, + setSelectedOpenAIModel, + } = useTranslation(); + + if (currentSelectableOpenAIModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedOpenAIModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + // Duplicate const transformDeviceArray = (devices) => { const name_counts = Object.values(devices).reduce((counts, device) => { From 28b65deb957068a12d8ba3565dfd7fc5d85fcc8f Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:07:04 +0900 Subject: [PATCH 6/7] [Refactor] Implement useSaveButtonLogic for managing save functionality in Translation settings. --- .../config_page_setter/useSettingsLogics.js | 33 +++++ src-ui/logics/configs/index.js | 1 + .../setting_box/translation/Translation.jsx | 123 +++++------------- 3 files changed, 66 insertions(+), 91 deletions(-) diff --git a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js index 58702b06..35fe4152 100644 --- a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js +++ b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js @@ -309,6 +309,39 @@ export const useSliderLogic = ({ }; }; + +export const useSaveButtonLogic = ({ + variable, + state, + setFunction, + deleteFunction +}) => { + const [input_value, setInputValue] = useState(variable); + + const onChangeFunction = (value) => { + setInputValue(value); + }; + + const saveFunction = () => { + if (input_value === "" || input_value === null) { + return deleteFunction(); + } + setFunction(input_value); + }; + + useEffect(() => { + if (state === "pending") return; + setInputValue(variable); + + }, [variable]); + + return { + variable: input_value, + onChangeFunction: onChangeFunction, + saveFunction: saveFunction, + }; +}; + const createMarks = (min, max, marks_step = 1, labelFormatter = (value) => value) => { const marks = []; let variable = min; diff --git a/src-ui/logics/configs/index.js b/src-ui/logics/configs/index.js index 1b20c3c6..42676fdd 100644 --- a/src-ui/logics/configs/index.js +++ b/src-ui/logics/configs/index.js @@ -18,4 +18,5 @@ export { useSettingBoxScrollPosition } from "./config_page_setter/_aux/useSettin export { useSliderLogic, + useSaveButtonLogic, } from "./config_page_setter/useSettingsLogics.js"; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index 28b0f9f2..b7bdf99f 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -6,6 +6,8 @@ import { useStore_IsBreakPoint } from "@store"; import { useTranslation, + + useSaveButtonLogic, } from "@logics_configs"; import { @@ -32,7 +34,7 @@ export const Translation = () => { - + @@ -217,26 +219,16 @@ const TranslationComputeDevice_Box = () => { ); }; -const DeeplAuthKey_Box = () => { +const DeepLAuthKey_Box = () => { const { t } = useI18n(); const { currentDeepLAuthKey, setDeepLAuthKey, deleteDeepLAuthKey } = useTranslation(); - const [input_value, seInputValue] = useState(currentDeepLAuthKey.data); - const onChangeFunction = (value) => { - seInputValue(value); - }; - - const saveFunction = () => { - if (input_value === "" || input_value === null) { - return deleteDeepLAuthKey(); - }; - setDeepLAuthKey(input_value); - }; - - useEffect(() => { - if (currentDeepLAuthKey.state === "pending") return; - seInputValue(currentDeepLAuthKey.data); - }, [currentDeepLAuthKey]); + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentDeepLAuthKey.data, + state: currentDeepLAuthKey.state, + setFunction: setDeepLAuthKey, + deleteFunction: deleteDeepLAuthKey, + }); return ( <> @@ -248,7 +240,7 @@ const DeeplAuthKey_Box = () => { )} webpage_url={deepl_auth_key_url} open_webpage_label={t("config_page.translation.deepl_auth_key.open_auth_key_webpage")} - variable={input_value} + variable={variable} state={currentDeepLAuthKey.state} onChangeFunction={onChangeFunction} saveFunction={saveFunction} @@ -260,37 +252,22 @@ const DeeplAuthKey_Box = () => { const PlamoAuthKey_Box = () => { const { t } = useI18n(); const { currentPlamoAuthKey, setPlamoAuthKey, deletePlamoAuthKey } = useTranslation(); - const [input_value, seInputValue] = useState(currentPlamoAuthKey.data); - const onChangeFunction = (value) => { - seInputValue(value); - }; - - const saveFunction = () => { - if (input_value === "" || input_value === null) { - return deletePlamoAuthKey(); - }; - setPlamoAuthKey(input_value); - }; - - useEffect(() => { - if (currentPlamoAuthKey.state === "pending") return; - seInputValue(currentPlamoAuthKey.data); - }, [currentPlamoAuthKey]); + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentPlamoAuthKey.data, + state: currentPlamoAuthKey.state, + setFunction: setPlamoAuthKey, + deleteFunction: deletePlamoAuthKey, + }); return ( <> { { const GeminiAuthKey_Box = () => { const { t } = useI18n(); const { currentGeminiAuthKey, setGeminiAuthKey, deleteGeminiAuthKey } = useTranslation(); - const [input_value, seInputValue] = useState(currentGeminiAuthKey.data); - const onChangeFunction = (value) => { - seInputValue(value); - }; - - const saveFunction = () => { - if (input_value === "" || input_value === null) { - return deleteGeminiAuthKey(); - }; - setGeminiAuthKey(input_value); - }; - - useEffect(() => { - if (currentGeminiAuthKey.state === "pending") return; - seInputValue(currentGeminiAuthKey.data); - }, [currentGeminiAuthKey]); + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentGeminiAuthKey.data, + state: currentGeminiAuthKey.state, + setFunction: setGeminiAuthKey, + deleteFunction: deleteGeminiAuthKey, + }); return ( <> { { const OpenAIAuthKey_Box = () => { const { t } = useI18n(); const { currentOpenAIAuthKey, setOpenAIAuthKey, deleteOpenAIAuthKey } = useTranslation(); - const [input_value, seInputValue] = useState(currentOpenAIAuthKey.data); - const onChangeFunction = (value) => { - seInputValue(value); - }; - - const saveFunction = () => { - if (input_value === "" || input_value === null) { - return deleteOpenAIAuthKey(); - }; - setOpenAIAuthKey(input_value); - }; - - useEffect(() => { - if (currentOpenAIAuthKey.state === "pending") return; - seInputValue(currentOpenAIAuthKey.data); - }, [currentOpenAIAuthKey]); + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentOpenAIAuthKey.data, + state: currentOpenAIAuthKey.state, + setFunction: setOpenAIAuthKey, + deleteFunction: deleteOpenAIAuthKey, + }); return ( <> { Date: Fri, 14 Nov 2025 12:41:05 +0900 Subject: [PATCH 7/7] [Update] UI: Add LM Studio and Ollama model components to the Translation section. --- .../config_page_setter/ui_config_setter.js | 56 ++++++++++++ .../setting_box/translation/Translation.jsx | 88 +++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/src-ui/logics/configs/config_page_setter/ui_config_setter.js b/src-ui/logics/configs/config_page_setter/ui_config_setter.js index a59b8e2b..f3790a6c 100644 --- a/src-ui/logics/configs/config_page_setter/ui_config_setter.js +++ b/src-ui/logics/configs/config_page_setter/ui_config_setter.js @@ -314,6 +314,62 @@ export const SETTINGS_ARRAY = [ add_endpoint_run_array: ["from_backend"], base_endpoint_name: "selected_openai_model", }, + // LM Studio + { + Category: "Translation", + Base_Name: "LMStudioURL", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set", + base_endpoint_name: "lmstudio_url", + }, + { + Category: "Translation", + Base_Name: "SelectableLMStudioModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_lmstudio_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedLMStudioModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_lmstudio_model", + }, + // Ollama + { + Category: "Translation", + Base_Name: "OllamaURL", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set", + base_endpoint_name: "ollama_url", + }, + { + Category: "Translation", + Base_Name: "SelectableOllamaModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_ollama_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedOllamaModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_ollama_model", + }, // Transcription // Mic diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index b7bdf99f..7ad243ff 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -14,6 +14,7 @@ import { DownloadModelsContainer, AuthKeyContainer, MultiDropdownMenuContainer, + EntryWithSaveButtonContainer, RadioButtonContainer, DropdownMenuContainer, @@ -44,6 +45,11 @@ export const Translation = () => { + + + + + ); }; @@ -415,6 +421,88 @@ const OpenAIModelContainer = () => { }; + +const LMStudioURL_Box = () => { + const { t } = useI18n(); + const { currentLMStudioURL, setLMStudioURL, deleteLMStudioURL } = useTranslation(); + + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentLMStudioURL.data, + state: currentLMStudioURL.state, + setFunction: setLMStudioURL, + deleteFunction: deleteLMStudioURL, + }); + + return ( + <> + + + ); +}; +const LMStudioModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableLMStudioModelList, + + currentSelectedLMStudioModel, + setSelectedLMStudioModel, + } = useTranslation(); + + if (currentSelectableLMStudioModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedLMStudioModel(selected_data.selected_id); + }; + + return ( + + ); +}; + +const OllamaModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableOllamaModelList, + + currentSelectedOllamaModel, + setSelectedOllamaModel, + } = useTranslation(); + + if (currentSelectableOllamaModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedOllamaModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + // Duplicate const transformDeviceArray = (devices) => { const name_counts = Object.values(devices).reduce((counts, device) => {