diff --git a/src/components/displays/superuser/configuration/ConfigurationSecretKey.vue b/src/components/displays/superuser/configuration/ConfigurationSecretKey.vue index 86dadd8c..56a4ed4b 100644 --- a/src/components/displays/superuser/configuration/ConfigurationSecretKey.vue +++ b/src/components/displays/superuser/configuration/ConfigurationSecretKey.vue @@ -1,6 +1,9 @@ @@ -33,8 +77,8 @@ const parseErrorOnSave = (error) => {
- Warning: - The secret key is not set, please set it before enabling the integration. + {{ resolvedWarningTitle() }}: + {{ resolvedWarningMessage() }}
@@ -52,11 +96,16 @@ const parseErrorOnSave = (error) => { class="input" type="text" v-model="v_model" - :disabled="disabled || !isEditting" + :disabled="disabled || !isEditting || saving" />
- + diff --git a/src/i18n/generated/da-v2.json b/src/i18n/generated/da-v2.json index ed3e36df..86299f02 100644 --- a/src/i18n/generated/da-v2.json +++ b/src/i18n/generated/da-v2.json @@ -2541,6 +2541,7 @@ "zip": "Postnummer" }, "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/generated/de-v2.json b/src/i18n/generated/de-v2.json index bda5fdd5..3fa11d7c 100644 --- a/src/i18n/generated/de-v2.json +++ b/src/i18n/generated/de-v2.json @@ -2651,6 +2651,7 @@ "zip": "Postleitzahl" }, "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/generated/en-v2.json b/src/i18n/generated/en-v2.json index cd53a3e0..ed3dca1c 100644 --- a/src/i18n/generated/en-v2.json +++ b/src/i18n/generated/en-v2.json @@ -2372,6 +2372,7 @@ "zip": "@:{'words.generated.zip'} @:{'words.generated.code'}" }, "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/generated/global-v2.json b/src/i18n/generated/global-v2.json index 5221818c..b41ede5c 100644 --- a/src/i18n/generated/global-v2.json +++ b/src/i18n/generated/global-v2.json @@ -1255,6 +1255,7 @@ "workspace_id": "Workspace ID", "workspace_id_desc": "The canonical Bird workspace identifier. Existing workplaceId values remain readable during migration." }, + "secret_key_not_set": "@:{'templates.generated.compat.configuration.secret_key_not_set'}", "backups": { "active_jobs": "@:{'templates.generated.compat.configuration.backups.active_jobs'}", "actions": "@:{'templates.generated.compat.configuration.backups.actions'}", diff --git a/src/i18n/generated/no-v2.json b/src/i18n/generated/no-v2.json index f0e3ede2..99f1f5fe 100644 --- a/src/i18n/generated/no-v2.json +++ b/src/i18n/generated/no-v2.json @@ -2654,6 +2654,7 @@ "zip": "@:{'words.generated.postnummer'}" }, "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/generated/sv-v2.json b/src/i18n/generated/sv-v2.json index b96bbd56..5ef4b21e 100644 --- a/src/i18n/generated/sv-v2.json +++ b/src/i18n/generated/sv-v2.json @@ -2704,6 +2704,7 @@ "zip": "Postnummer" }, "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/source/da/phrases/compat/configuration/index.json b/src/i18n/source/da/phrases/compat/configuration/index.json index f7748adb..a3fb628a 100644 --- a/src/i18n/source/da/phrases/compat/configuration/index.json +++ b/src/i18n/source/da/phrases/compat/configuration/index.json @@ -1,6 +1,7 @@ { "compat": { "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/source/de/phrases/compat/configuration/index.json b/src/i18n/source/de/phrases/compat/configuration/index.json index 6d4d699c..0f6ad148 100644 --- a/src/i18n/source/de/phrases/compat/configuration/index.json +++ b/src/i18n/source/de/phrases/compat/configuration/index.json @@ -1,6 +1,7 @@ { "compat": { "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/source/en/phrases/compat/configuration/index.json b/src/i18n/source/en/phrases/compat/configuration/index.json index 863cbeb1..75b617a7 100644 --- a/src/i18n/source/en/phrases/compat/configuration/index.json +++ b/src/i18n/source/en/phrases/compat/configuration/index.json @@ -1,6 +1,7 @@ { "compat": { "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/source/global/shared/configuration/index.json b/src/i18n/source/global/shared/configuration/index.json index 080a7955..4012fa13 100644 --- a/src/i18n/source/global/shared/configuration/index.json +++ b/src/i18n/source/global/shared/configuration/index.json @@ -1,5 +1,6 @@ { "configuration": { + "secret_key_not_set": "@:{'phrases.compat.configuration.secret_key_not_set'}", "backups": { "active_jobs": "@:{'phrases.compat.configuration.backups.active_jobs'}", "actions": "@:{'phrases.compat.configuration.backups.actions'}", diff --git a/src/i18n/source/no/phrases/compat/configuration/index.json b/src/i18n/source/no/phrases/compat/configuration/index.json index 9614a2a3..20ad1e83 100644 --- a/src/i18n/source/no/phrases/compat/configuration/index.json +++ b/src/i18n/source/no/phrases/compat/configuration/index.json @@ -1,6 +1,7 @@ { "compat": { "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/i18n/source/sv/phrases/compat/configuration/index.json b/src/i18n/source/sv/phrases/compat/configuration/index.json index 80a76509..9c88ce7b 100644 --- a/src/i18n/source/sv/phrases/compat/configuration/index.json +++ b/src/i18n/source/sv/phrases/compat/configuration/index.json @@ -1,6 +1,7 @@ { "compat": { "configuration": { + "secret_key_not_set": "The secret key is not set, please set it before enabling the integration.", "backups": { "active_jobs": "Active jobs", "actions": "Actions", diff --git a/src/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue b/src/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue index cf013989..bbf1cb69 100644 --- a/src/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue +++ b/src/views/dashboards/superUserDashboard/configuration/ConfigurationXLVask.vue @@ -85,20 +85,46 @@ const onClickTestConnection = async () => { // --- MiniMax re-authenticate / remove --------------------------------------- const minimaxApiKeyIsSet = ref(false); +const minimaxEnabled = ref(false); const reauthenticatingMiniMax = ref(false); const removingMiniMax = ref(false); +const togglingMiniMaxEnabled = ref(false); -const refreshMiniMaxStatus = async () => { +/** + * The backend returns the get-config response as an array (one entry per + * module variable). Extract the single entry we asked for, then trust the + * explicit `isSet` flag instead of the redacted `value`. + */ +const extractConfigEntry = (response) => { + const payload = response?.data?.data; + if (Array.isArray(payload)) { + return payload[0] ?? null; + } + return payload ?? null; +}; + +const refreshMiniMaxApiKeyStatus = async () => { try { const response = await SessionUser.superUser.modules.minimax.config.keys.api_key.get(); - const value = response?.data?.data?.value ?? response?.data?.data ?? ''; - minimaxApiKeyIsSet.value = typeof value === 'string' && value !== ''; + const entry = extractConfigEntry(response); + minimaxApiKeyIsSet.value = entry?.isSet === true; } catch (error) { // If the endpoint is unreachable or the key isn't set yet, treat as not-set. minimaxApiKeyIsSet.value = false; } }; +const refreshMiniMaxEnabled = async () => { + try { + const response = await SessionUser.superUser.modules.minimax.config.enabled.get(); + const entry = extractConfigEntry(response); + const raw = entry?.value; + minimaxEnabled.value = raw === true || raw === 'true' || raw === '1' || raw === 1; + } catch (error) { + minimaxEnabled.value = false; + } +}; + const onClickReauthenticateMiniMax = async () => { const { value: apiKey } = await Swal.fire({ title: t('configuration.xlvask.minimax_reauth_title'), @@ -121,7 +147,10 @@ const onClickReauthenticateMiniMax = async () => { reauthenticatingMiniMax.value = true; try { await SessionUser.superUser.modules.minimax.config.keys.api_key.set(apiKey); - minimaxApiKeyIsSet.value = true; + // Re-fetch from the backend so the UI matches actual persistence (and so a + // silent failure surfaces as "still not set" instead of a misleading green + // checkmark). + await refreshMiniMaxApiKeyStatus(); Swal.fire({ icon: 'success', title: t('configuration.xlvask.minimax_reauth_success'), @@ -152,7 +181,7 @@ const onClickRemoveMiniMax = async () => { removingMiniMax.value = true; try { await SessionUser.superUser.modules.minimax.config.keys.api_key.set(''); - minimaxApiKeyIsSet.value = false; + await refreshMiniMaxApiKeyStatus(); Swal.fire({ icon: 'success', title: t('configuration.xlvask.minimax_remove_success'), @@ -169,9 +198,37 @@ const onClickRemoveMiniMax = async () => { } }; +/** + * The ConfigurationSecretKey inline-edit flow calls onSave and resolves on + * success. Refresh the parent state from the API so the "Hidden" view replaces + * the warning as soon as the request actually persists. + */ +const onMiniMaxApiKeySaved = async () => { + await refreshMiniMaxApiKeyStatus(); +}; + +/** + * The MiniMax "Enable" toggle calls on-switch with the next boolean value. + * Re-fetch after the save so the UI reflects persisted state (the inline + * `set()` call does not refresh the UI on its own). + */ +const onMiniMaxEnabledSwitch = async (nextValue) => { + togglingMiniMaxEnabled.value = true; + try { + await SessionUser.superUser.modules.minimax.config.enabled.set(nextValue); + await refreshMiniMaxEnabled(); + } catch (error) { + // Roll back the optimistic UI flip on failure. + minimaxEnabled.value = !nextValue; + throw error; + } finally { + togglingMiniMaxEnabled.value = false; + } +}; + const load = async () => { await getModuleConfig(); - await refreshMiniMaxStatus(); + await Promise.all([refreshMiniMaxApiKeyStatus(), refreshMiniMaxEnabled()]); }; load(); @@ -294,8 +351,9 @@ load(); :title="$t('configuration.xlvask.minimax_enable')" :description="$t('configuration.xlvask.minimax_enable_desc')" icon="fas fa-robot" - :value="SessionUser.superUser.modules.minimax.config.enabled.get ? true : false" - :on-switch="SessionUser.superUser.modules.minimax.config.enabled.set" + :value="minimaxEnabled" + :on-switch="onMiniMaxEnabledSwitch" + :disabled="togglingMiniMaxEnabled" />