feat(pleno-vue): MiniMax M3 settings UI in superuser XL Vask module (#269)

Adds the MiniMax (M3) configuration surface inside
`ConfigurationXLVask.vue`.

**What ships**

- `SessionUser.modules.minimax` mirrors the OpenAI pattern
(`config.get_all`, `config.keys.api_key`, `config.enabled`).
- Two new sections inside `ConfigurationXLVask.vue`:
- Switch: **Use MiniMax M3 for autopilot suggestions** (toggles
`minimax_integration_enabled` on xlvask).
  - **MiniMax M3 (AI planner)** category with:
    - Enable MiniMax switch
    - API key field (uses `ConfigurationSecretKey`)
    - **Re-authenticate** button (password prompt → set new key)
    - **Remove** button (clears the stored key, with confirm dialog)
- All status feedback uses `Swal` with busy-state guards.

**i18n**

26 new keys added to `configuration.xlvask.minimax_*` in all 5 locales
(da/de/en/no/sv). English source, to be translated by the language
owners later.

**Backend counterpart**

`api#355` adds `modules/miniMax` config, the `classes/minimax.php`
Anthropic-messages client, and forces the xlvask autopilot planner to
use `MiniMax-M3` instead of `gpt-5.6-sol`.

**Workflow (per jeppe)**

Once this PR + api#355 are merged to master, operator (jeppe) enters the
MiniMax API key in the new XL Vask settings UI; agent then optimizes +
tests + debugs live XL Vask usage logs against the new model.

---------

Co-authored-by: Truck Wash Agent <agent@copenhagentruckwash.local>
This commit is contained in:
Jeppe B
2026-08-09 19:26:05 +02:00
committed by GitHub
co-authored by Truck Wash Agent
parent f63e51c96e
commit 8d646ce770
14 changed files with 479 additions and 10 deletions
@@ -0,0 +1,47 @@
<script>
import {authenticatedRequest} from "@/components/session/authenticatedRequest.vue";
/**
* The MiniMax -> Config object
*/
export const Config = {
get: async ( variable ) => {
return authenticatedRequest(
"/minimax/config?variable=" + variable,
"GET")
},
get_all: async () => {
return authenticatedRequest(
"/minimax/config",
"GET")
},
set: async ( variable, value ) => {
return authenticatedRequest(
"/minimax/config",
"POST",
{
variable: variable,
value: value
})
},
keys: {
api_key: {
get: async () => {
return Config.get("api_key");
},
set: async (value) => {
return Config.set("api_key", value);
},
},
},
enabled: {
get: async () => {
return Config.get("enabled");
},
set: async (enabled) => {
return Config.set("enabled", enabled);
},
},
};
</script>
@@ -0,0 +1,22 @@
<script>
import { Config } from "@/components/session/token/superUser/modules/miniMax/Config.vue";
/**
* The MiniMax object
*/
export const MiniMax = {
meta: {
title: "MiniMax M3",
icon: "fas fa-robot",
description: "MiniMax M3 (Anthropic-messages) integration used by XL Vask autopilot and other AI features.",
endpoint: "/modules/MiniMax",
config_endpoint: "/configuration/MiniMax",
labels: {
single: "MiniMax",
multiple: "MiniMax"
}
},
config: Config,
functions: {}
};
</script>
@@ -23,6 +23,7 @@ import { Entra } from "@/components/session/token/superUser/modules/entra/Entra.
import { Limble } from "@/components/session/token/superUser/modules/limble/Limble.vue"; import { Limble } from "@/components/session/token/superUser/modules/limble/Limble.vue";
import { OcrSpace } from "@/components/session/token/superUser/modules/ocrSpace/OcrSpace.vue"; import { OcrSpace } from "@/components/session/token/superUser/modules/ocrSpace/OcrSpace.vue";
import { OpenAI } from "@/components/session/token/superUser/modules/openAI/OpenAI.vue"; import { OpenAI } from "@/components/session/token/superUser/modules/openAI/OpenAI.vue";
import { MiniMax } from "@/components/session/token/superUser/modules/miniMax/MiniMax.vue";
import { LicensePlateRecognizer } from "@/components/session/token/superUser/modules/licensePlateRecognizer/LicensePlateRecognizer.vue"; import { LicensePlateRecognizer } from "@/components/session/token/superUser/modules/licensePlateRecognizer/LicensePlateRecognizer.vue";
import { VirkData } from "@/components/session/token/superUser/modules/virkdata/VirkData.vue"; import { VirkData } from "@/components/session/token/superUser/modules/virkdata/VirkData.vue";
import { Shelly } from "@/components/session/token/superUser/modules/shelly/Shelly.vue"; import { Shelly } from "@/components/session/token/superUser/modules/shelly/Shelly.vue";
@@ -105,6 +106,9 @@ export const SuperUserObject = {
get openai() { get openai() {
return OpenAI; return OpenAI;
}, },
get minimax() {
return MiniMax;
},
get licenseplaterecognizer() { get licenseplaterecognizer() {
return LicensePlateRecognizer; return LicensePlateRecognizer;
}, },
+27 -1
View File
@@ -2911,7 +2911,33 @@
"password_desc": "@.capitalize:{'words.generated.adgangskoden'} @:{'words.generated.bruges'} @:{'words.generated.til'} @:{'words.generated.at'} @:{'words.generated.autentificere'} @:{'words.generated.api'} @:{'words.generated.forbindelsen'}.", "password_desc": "@.capitalize:{'words.generated.adgangskoden'} @:{'words.generated.bruges'} @:{'words.generated.til'} @:{'words.generated.at'} @:{'words.generated.autentificere'} @:{'words.generated.api'} @:{'words.generated.forbindelsen'}.",
"subtitle": "@.capitalize:{'words.generated.konfiguration'} @:{'words.generated.af'} @:{'words.generated.xlvask'} @:{'words.generated.integrationen'}", "subtitle": "@.capitalize:{'words.generated.konfiguration'} @:{'words.generated.af'} @:{'words.generated.xlvask'} @:{'words.generated.integrationen'}",
"title": "@:{'words.generated.xlvask'} @:{'words.generated.konfiguration'}", "title": "@:{'words.generated.xlvask'} @:{'words.generated.konfiguration'}",
"username_desc": "@.capitalize:{'words.generated.brugernavnet'} @:{'words.generated.bruges'} @:{'words.generated.til'} @:{'words.generated.at'} @:{'words.generated.autentificere'} @:{'words.generated.api'} @:{'words.generated.forbindelsen'}." "username_desc": "@.capitalize:{'words.generated.brugernavnet'} @:{'words.generated.bruges'} @:{'words.generated.til'} @:{'words.generated.at'} @:{'words.generated.autentificere'} @:{'words.generated.api'} @:{'words.generated.forbindelsen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
}, },
"release_manager": { "release_manager": {
"integrations": { "integrations": {
+27 -1
View File
@@ -3021,7 +3021,33 @@
"password_desc": "@.capitalize:{'words.generated.das'} @:{'words.generated.passwort'} @:{'words.generated.wird'} @:{'words.generated.zur'} @:{'words.generated.authentifizierung'} @:{'words.generated.der'} @:{'words.generated.api'}-@:{'words.generated.verbindung'} @:{'words.generated.verwendet'}.", "password_desc": "@.capitalize:{'words.generated.das'} @:{'words.generated.passwort'} @:{'words.generated.wird'} @:{'words.generated.zur'} @:{'words.generated.authentifizierung'} @:{'words.generated.der'} @:{'words.generated.api'}-@:{'words.generated.verbindung'} @:{'words.generated.verwendet'}.",
"subtitle": "@:{'words.generated.konfiguration'} @:{'words.generated.der'} @:{'words.generated.xlvask'}-@.capitalize:{'words.generated.integration'}", "subtitle": "@:{'words.generated.konfiguration'} @:{'words.generated.der'} @:{'words.generated.xlvask'}-@.capitalize:{'words.generated.integration'}",
"title": "@:{'words.generated.xlvask'}-@:{'words.generated.konfiguration'}", "title": "@:{'words.generated.xlvask'}-@:{'words.generated.konfiguration'}",
"username_desc": "@.capitalize:{'words.generated.der'} @:{'words.generated.benutzername'} @:{'words.generated.wird'} @:{'words.generated.zur'} @:{'words.generated.authentifizierung'} @:{'words.generated.der'} @:{'words.generated.api'}-@:{'words.generated.verbindung'} @:{'words.generated.verwendet'}." "username_desc": "@.capitalize:{'words.generated.der'} @:{'words.generated.benutzername'} @:{'words.generated.wird'} @:{'words.generated.zur'} @:{'words.generated.authentifizierung'} @:{'words.generated.der'} @:{'words.generated.api'}-@:{'words.generated.verbindung'} @:{'words.generated.verwendet'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
}, },
"release_manager": { "release_manager": {
"integrations": { "integrations": {
+27 -1
View File
@@ -2742,7 +2742,33 @@
"password_desc": "@.capitalize:{'words.replication.article.host_mention'} @:{'words.generated.password'} @:{'words.generated.is'} @:{'words.generated.used'} @:{'words.generated.to'} @:{'words.generated.authenticate'} @:{'words.replication.article.host_mention'} @:{'words.generated.api'} @:{'words.generated.connection'}.", "password_desc": "@.capitalize:{'words.replication.article.host_mention'} @:{'words.generated.password'} @:{'words.generated.is'} @:{'words.generated.used'} @:{'words.generated.to'} @:{'words.generated.authenticate'} @:{'words.replication.article.host_mention'} @:{'words.generated.api'} @:{'words.generated.connection'}.",
"subtitle": "@.capitalize:{'words.generated.configuration'} @:{'words.generated.of'} @:{'words.replication.article.host_mention'} @:{'words.generated.xlvask'} @:{'words.generated.integration'}", "subtitle": "@.capitalize:{'words.generated.configuration'} @:{'words.generated.of'} @:{'words.replication.article.host_mention'} @:{'words.generated.xlvask'} @:{'words.generated.integration'}",
"title": "@:{'words.generated.xlvask'} @:{'words.generated.configuration'}", "title": "@:{'words.generated.xlvask'} @:{'words.generated.configuration'}",
"username_desc": "@.capitalize:{'words.replication.article.host_mention'} @:{'words.generated.username'} @:{'words.generated.is'} @:{'words.generated.used'} @:{'words.generated.to'} @:{'words.generated.authenticate'} @:{'words.replication.article.host_mention'} @:{'words.generated.api'} @:{'words.generated.connection'}." "username_desc": "@.capitalize:{'words.replication.article.host_mention'} @:{'words.generated.username'} @:{'words.generated.is'} @:{'words.generated.used'} @:{'words.generated.to'} @:{'words.generated.authenticate'} @:{'words.replication.article.host_mention'} @:{'words.generated.api'} @:{'words.generated.connection'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
}, },
"release_manager": { "release_manager": {
"integrations": { "integrations": {
+27 -1
View File
@@ -3024,7 +3024,33 @@
"password_desc": "@.capitalize:{'words.generated.passordet'} @:{'words.generated.brukes'} @:{'words.generated.til'} @:{'words.generated.a'} @:{'words.generated.autentisere'} @:{'words.generated.api'}-@:{'words.generated.tilkoblingen'}.", "password_desc": "@.capitalize:{'words.generated.passordet'} @:{'words.generated.brukes'} @:{'words.generated.til'} @:{'words.generated.a'} @:{'words.generated.autentisere'} @:{'words.generated.api'}-@:{'words.generated.tilkoblingen'}.",
"subtitle": "@.capitalize:{'words.generated.konfigurasjon'} @:{'words.generated.av'} @:{'words.generated.xlvask'}-@:{'words.generated.integrasjonen'}", "subtitle": "@.capitalize:{'words.generated.konfigurasjon'} @:{'words.generated.av'} @:{'words.generated.xlvask'}-@:{'words.generated.integrasjonen'}",
"title": "@:{'words.generated.xlvask'}-@:{'words.generated.konfigurasjon'}", "title": "@:{'words.generated.xlvask'}-@:{'words.generated.konfigurasjon'}",
"username_desc": "@:{'words.generated.brukernavnet'} @:{'words.generated.brukes'} @:{'words.generated.til'} @:{'words.generated.a'} @:{'words.generated.autentisere'} @:{'words.generated.api'}-@:{'words.generated.tilkoblingen'}." "username_desc": "@:{'words.generated.brukernavnet'} @:{'words.generated.brukes'} @:{'words.generated.til'} @:{'words.generated.a'} @:{'words.generated.autentisere'} @:{'words.generated.api'}-@:{'words.generated.tilkoblingen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
}, },
"release_manager": { "release_manager": {
"integrations": { "integrations": {
+27 -1
View File
@@ -3074,7 +3074,33 @@
"password_desc": "@.capitalize:{'words.generated.losenordet'} @:{'words.generated.anvands'} @:{'words.generated.for'} @:{'words.generated.att'} @:{'words.generated.autentisera'} @:{'words.generated.api'}-@:{'words.generated.anslutningen'}.", "password_desc": "@.capitalize:{'words.generated.losenordet'} @:{'words.generated.anvands'} @:{'words.generated.for'} @:{'words.generated.att'} @:{'words.generated.autentisera'} @:{'words.generated.api'}-@:{'words.generated.anslutningen'}.",
"subtitle": "@.capitalize:{'words.generated.konfiguration'} @:{'words.generated.af'} @:{'words.generated.xlvask'} @:{'words.generated.integrationen'}", "subtitle": "@.capitalize:{'words.generated.konfiguration'} @:{'words.generated.af'} @:{'words.generated.xlvask'} @:{'words.generated.integrationen'}",
"title": "@:{'words.generated.xlvask'} @:{'words.generated.konfiguration'}", "title": "@:{'words.generated.xlvask'} @:{'words.generated.konfiguration'}",
"username_desc": "Användarnamnet @:{'words.generated.anvands'} @:{'words.generated.for'} @:{'words.generated.att'} @:{'words.generated.autentisera'} @:{'words.generated.api'}-@:{'words.generated.anslutningen'}." "username_desc": "Användarnamnet @:{'words.generated.anvands'} @:{'words.generated.for'} @:{'words.generated.att'} @:{'words.generated.autentisera'} @:{'words.generated.api'}-@:{'words.generated.anslutningen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
}, },
"release_manager": { "release_manager": {
"integrations": { "integrations": {
@@ -371,7 +371,33 @@
"password_desc": "@.capitalize:{'terms.glossary.adgangskoden'} @:{'terms.glossary.bruges'} @:{'terms.glossary.til'} @:{'terms.glossary.at'} @:{'terms.glossary.autentificere'} @:{'terms.glossary.api'} @:{'terms.glossary.forbindelsen'}.", "password_desc": "@.capitalize:{'terms.glossary.adgangskoden'} @:{'terms.glossary.bruges'} @:{'terms.glossary.til'} @:{'terms.glossary.at'} @:{'terms.glossary.autentificere'} @:{'terms.glossary.api'} @:{'terms.glossary.forbindelsen'}.",
"subtitle": "@.capitalize:{'terms.glossary.konfiguration'} @:{'terms.glossary.af'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integrationen'}", "subtitle": "@.capitalize:{'terms.glossary.konfiguration'} @:{'terms.glossary.af'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integrationen'}",
"title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.konfiguration'}", "title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.konfiguration'}",
"username_desc": "@.capitalize:{'terms.glossary.brugernavnet'} @:{'terms.glossary.bruges'} @:{'terms.glossary.til'} @:{'terms.glossary.at'} @:{'terms.glossary.autentificere'} @:{'terms.glossary.api'} @:{'terms.glossary.forbindelsen'}." "username_desc": "@.capitalize:{'terms.glossary.brugernavnet'} @:{'terms.glossary.bruges'} @:{'terms.glossary.til'} @:{'terms.glossary.at'} @:{'terms.glossary.autentificere'} @:{'terms.glossary.api'} @:{'terms.glossary.forbindelsen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
} }
} }
} }
@@ -371,7 +371,33 @@
"password_desc": "@.capitalize:{'terms.glossary.das'} @:{'terms.glossary.passwort'} @:{'terms.glossary.wird'} @:{'terms.glossary.zur'} @:{'terms.glossary.authentifizierung'} @:{'terms.glossary.der'} @:{'terms.glossary.api'}-@:{'terms.glossary.verbindung'} @:{'terms.glossary.verwendet'}.", "password_desc": "@.capitalize:{'terms.glossary.das'} @:{'terms.glossary.passwort'} @:{'terms.glossary.wird'} @:{'terms.glossary.zur'} @:{'terms.glossary.authentifizierung'} @:{'terms.glossary.der'} @:{'terms.glossary.api'}-@:{'terms.glossary.verbindung'} @:{'terms.glossary.verwendet'}.",
"subtitle": "@:{'terms.glossary.konfiguration'} @:{'terms.glossary.der'} @:{'terms.glossary.xlvask'}-@.capitalize:{'terms.glossary.integration'}", "subtitle": "@:{'terms.glossary.konfiguration'} @:{'terms.glossary.der'} @:{'terms.glossary.xlvask'}-@.capitalize:{'terms.glossary.integration'}",
"title": "@:{'terms.glossary.xlvask'}-@:{'terms.glossary.konfiguration'}", "title": "@:{'terms.glossary.xlvask'}-@:{'terms.glossary.konfiguration'}",
"username_desc": "@.capitalize:{'terms.glossary.der'} @:{'terms.glossary.benutzername'} @:{'terms.glossary.wird'} @:{'terms.glossary.zur'} @:{'terms.glossary.authentifizierung'} @:{'terms.glossary.der'} @:{'terms.glossary.api'}-@:{'terms.glossary.verbindung'} @:{'terms.glossary.verwendet'}." "username_desc": "@.capitalize:{'terms.glossary.der'} @:{'terms.glossary.benutzername'} @:{'terms.glossary.wird'} @:{'terms.glossary.zur'} @:{'terms.glossary.authentifizierung'} @:{'terms.glossary.der'} @:{'terms.glossary.api'}-@:{'terms.glossary.verbindung'} @:{'terms.glossary.verwendet'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
} }
} }
} }
@@ -371,7 +371,33 @@
"password_desc": "@.capitalize:{'terms.replication.article.host_mention'} @:{'terms.glossary.password'} @:{'terms.glossary.is'} @:{'terms.glossary.used'} @:{'terms.glossary.to'} @:{'terms.glossary.authenticate'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.api'} @:{'terms.glossary.connection'}.", "password_desc": "@.capitalize:{'terms.replication.article.host_mention'} @:{'terms.glossary.password'} @:{'terms.glossary.is'} @:{'terms.glossary.used'} @:{'terms.glossary.to'} @:{'terms.glossary.authenticate'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.api'} @:{'terms.glossary.connection'}.",
"subtitle": "@.capitalize:{'terms.glossary.configuration'} @:{'terms.glossary.of'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integration'}", "subtitle": "@.capitalize:{'terms.glossary.configuration'} @:{'terms.glossary.of'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integration'}",
"title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.configuration'}", "title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.configuration'}",
"username_desc": "@.capitalize:{'terms.replication.article.host_mention'} @:{'terms.glossary.username'} @:{'terms.glossary.is'} @:{'terms.glossary.used'} @:{'terms.glossary.to'} @:{'terms.glossary.authenticate'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.api'} @:{'terms.glossary.connection'}." "username_desc": "@.capitalize:{'terms.replication.article.host_mention'} @:{'terms.glossary.username'} @:{'terms.glossary.is'} @:{'terms.glossary.used'} @:{'terms.glossary.to'} @:{'terms.glossary.authenticate'} @:{'terms.replication.article.host_mention'} @:{'terms.glossary.api'} @:{'terms.glossary.connection'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
} }
} }
} }
@@ -371,7 +371,33 @@
"password_desc": "@.capitalize:{'terms.glossary.passordet'} @:{'terms.glossary.brukes'} @:{'terms.glossary.til'} @:{'terms.glossary.a'} @:{'terms.glossary.autentisere'} @:{'terms.glossary.api'}-@:{'terms.glossary.tilkoblingen'}.", "password_desc": "@.capitalize:{'terms.glossary.passordet'} @:{'terms.glossary.brukes'} @:{'terms.glossary.til'} @:{'terms.glossary.a'} @:{'terms.glossary.autentisere'} @:{'terms.glossary.api'}-@:{'terms.glossary.tilkoblingen'}.",
"subtitle": "@.capitalize:{'terms.glossary.konfigurasjon'} @:{'terms.glossary.av'} @:{'terms.glossary.xlvask'}-@:{'terms.glossary.integrasjonen'}", "subtitle": "@.capitalize:{'terms.glossary.konfigurasjon'} @:{'terms.glossary.av'} @:{'terms.glossary.xlvask'}-@:{'terms.glossary.integrasjonen'}",
"title": "@:{'terms.glossary.xlvask'}-@:{'terms.glossary.konfigurasjon'}", "title": "@:{'terms.glossary.xlvask'}-@:{'terms.glossary.konfigurasjon'}",
"username_desc": "@:{'terms.glossary.brukernavnet'} @:{'terms.glossary.brukes'} @:{'terms.glossary.til'} @:{'terms.glossary.a'} @:{'terms.glossary.autentisere'} @:{'terms.glossary.api'}-@:{'terms.glossary.tilkoblingen'}." "username_desc": "@:{'terms.glossary.brukernavnet'} @:{'terms.glossary.brukes'} @:{'terms.glossary.til'} @:{'terms.glossary.a'} @:{'terms.glossary.autentisere'} @:{'terms.glossary.api'}-@:{'terms.glossary.tilkoblingen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
} }
} }
} }
@@ -371,7 +371,33 @@
"password_desc": "@.capitalize:{'terms.glossary.losenordet'} @:{'terms.glossary.anvands'} @:{'terms.glossary.for'} @:{'terms.glossary.att'} @:{'terms.glossary.autentisera'} @:{'terms.glossary.api'}-@:{'terms.glossary.anslutningen'}.", "password_desc": "@.capitalize:{'terms.glossary.losenordet'} @:{'terms.glossary.anvands'} @:{'terms.glossary.for'} @:{'terms.glossary.att'} @:{'terms.glossary.autentisera'} @:{'terms.glossary.api'}-@:{'terms.glossary.anslutningen'}.",
"subtitle": "@.capitalize:{'terms.glossary.konfiguration'} @:{'terms.glossary.af'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integrationen'}", "subtitle": "@.capitalize:{'terms.glossary.konfiguration'} @:{'terms.glossary.af'} @:{'terms.glossary.xlvask'} @:{'terms.glossary.integrationen'}",
"title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.konfiguration'}", "title": "@:{'terms.glossary.xlvask'} @:{'terms.glossary.konfiguration'}",
"username_desc": "Användarnamnet @:{'terms.glossary.anvands'} @:{'terms.glossary.for'} @:{'terms.glossary.att'} @:{'terms.glossary.autentisera'} @:{'terms.glossary.api'}-@:{'terms.glossary.anslutningen'}." "username_desc": "Användarnamnet @:{'terms.glossary.anvands'} @:{'terms.glossary.for'} @:{'terms.glossary.att'} @:{'terms.glossary.autentisera'} @:{'terms.glossary.api'}-@:{'terms.glossary.anslutningen'}.",
"minimax_settings": "MiniMax M3 (AI planner)",
"minimax_settings_desc": "Configure the MiniMax M3 integration that powers the XL Vask autopilot planner.",
"enable_minimax_integration": "Use MiniMax M3 for autopilot suggestions",
"enable_minimax_integration_desc": "Force the XL Vask autopilot to use MiniMax M3 (replaces OpenAI for AI suggestions).",
"minimax_enable": "Enable MiniMax",
"minimax_enable_desc": "Activate the MiniMax integration used by the XL Vask autopilot and other AI features.",
"minimax_api_key": "MiniMax API key",
"minimax_api_key_desc": "The secret key for MiniMax. Obtain it from the MiniMax Portal; rotate or remove it from this page.",
"minimax_api_key_placeholder": "Paste your MiniMax API key",
"minimax_api_key_required": "An API key is required.",
"minimax_reauthenticate": "Re-authenticate",
"minimax_reauth_title": "Re-authenticate MiniMax",
"minimax_reauth_desc": "Paste a new MiniMax API key. This replaces the stored key.",
"minimax_reauth_confirm": "Save key",
"minimax_reauth_in_progress": "Saving…",
"minimax_reauth_success": "MiniMax key saved",
"minimax_reauth_success_desc": "The XL Vask autopilot will use the new key on its next call.",
"minimax_reauth_failed": "Could not save MiniMax key",
"minimax_remove": "Remove",
"minimax_remove_title": "Remove MiniMax key",
"minimax_remove_desc": "Clear the stored MiniMax API key. The autopilot will stop using MiniMax until a new key is provided.",
"minimax_remove_confirm": "Yes, remove",
"minimax_remove_in_progress": "Removing…",
"minimax_remove_success": "MiniMax key removed",
"minimax_remove_success_desc": "The autopilot is now forced off until a new key is configured.",
"minimax_remove_failed": "Could not remove MiniMax key"
} }
} }
} }
@@ -83,8 +83,95 @@ const onClickTestConnection = async () => {
}) })
} }
// --- MiniMax re-authenticate / remove ---------------------------------------
const minimaxApiKeyIsSet = ref(false);
const reauthenticatingMiniMax = ref(false);
const removingMiniMax = ref(false);
const refreshMiniMaxStatus = 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 !== '';
} catch (error) {
// If the endpoint is unreachable or the key isn't set yet, treat as not-set.
minimaxApiKeyIsSet.value = false;
}
};
const onClickReauthenticateMiniMax = async () => {
const { value: apiKey } = await Swal.fire({
title: t('configuration.xlvask.minimax_reauth_title'),
text: t('configuration.xlvask.minimax_reauth_desc'),
input: 'password',
inputAttributes: { autocomplete: 'off', autocapitalize: 'off', spellcheck: 'false' },
inputPlaceholder: t('configuration.xlvask.minimax_api_key_placeholder'),
showCancelButton: true,
confirmButtonText: t('configuration.xlvask.minimax_reauth_confirm'),
cancelButtonText: t('common.cancel'),
preConfirm: (val) => {
if (!val || String(val).trim() === '') {
Swal.showValidationMessage(t('configuration.xlvask.minimax_api_key_required'));
return false;
}
return String(val).trim();
},
});
if (!apiKey) return;
reauthenticatingMiniMax.value = true;
try {
await SessionUser.superUser.modules.minimax.config.keys.api_key.set(apiKey);
minimaxApiKeyIsSet.value = true;
Swal.fire({
icon: 'success',
title: t('configuration.xlvask.minimax_reauth_success'),
text: t('configuration.xlvask.minimax_reauth_success_desc'),
});
} catch (error) {
Swal.fire({
icon: 'error',
title: t('configuration.xlvask.minimax_reauth_failed'),
text: error?.message ?? String(error),
});
} finally {
reauthenticatingMiniMax.value = false;
}
};
const onClickRemoveMiniMax = async () => {
const confirmation = await Swal.fire({
title: t('configuration.xlvask.minimax_remove_title'),
text: t('configuration.xlvask.minimax_remove_desc'),
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
confirmButtonText: t('configuration.xlvask.minimax_remove_confirm'),
cancelButtonText: t('common.cancel'),
});
if (!confirmation.isConfirmed) return;
removingMiniMax.value = true;
try {
await SessionUser.superUser.modules.minimax.config.keys.api_key.set('');
minimaxApiKeyIsSet.value = false;
Swal.fire({
icon: 'success',
title: t('configuration.xlvask.minimax_remove_success'),
text: t('configuration.xlvask.minimax_remove_success_desc'),
});
} catch (error) {
Swal.fire({
icon: 'error',
title: t('configuration.xlvask.minimax_remove_failed'),
text: error?.message ?? String(error),
});
} finally {
removingMiniMax.value = false;
}
};
const load = async () => { const load = async () => {
await getModuleConfig(); await getModuleConfig();
await refreshMiniMaxStatus();
}; };
load(); load();
@@ -184,6 +271,55 @@ load();
:value="getModuleConfigValue('openai_integration_enabled') === true" :value="getModuleConfigValue('openai_integration_enabled') === true"
:on-switch="SessionUser.superUser.modules.xlvask.config.keys.openai_integration_enabled.set" :on-switch="SessionUser.superUser.modules.xlvask.config.keys.openai_integration_enabled.set"
/> />
<ConfigurationSwitch
class="mt-2"
module="XLVask"
:title="$t('configuration.xlvask.enable_minimax_integration')"
:description="$t('configuration.xlvask.enable_minimax_integration_desc')"
icon="fas fa-robot"
:value="getModuleConfigValue('minimax_integration_enabled') === true"
:on-switch="SessionUser.superUser.modules.xlvask.config.keys.minimax_integration_enabled.set"
/>
</ConfigurationCategory>
<ConfigurationCategory
class="mt-2"
module="XLVask"
:title="$t('configuration.xlvask.minimax_settings')"
:description="$t('configuration.xlvask.minimax_settings_desc')"
icon="fas fa-robot"
>
<ConfigurationSwitch
class="mt-2"
module="XLVask"
: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"
/>
<ConfigurationSecretKey
class="mt-2"
module="XLVask"
:title="$t('configuration.xlvask.minimax_api_key')"
:description="$t('configuration.xlvask.minimax_api_key_desc')"
icon="fas fa-key"
:isSet="minimaxApiKeyIsSet"
:on-save="SessionUser.superUser.modules.minimax.config.keys.api_key.set"
/>
<div class="buttons mt-2">
<button class="button is-warning" @click="onClickReauthenticateMiniMax" :disabled="reauthenticatingMiniMax">
<span class="icon">
<i class="fas fa-redo"></i>
</span>
<span>{{ reauthenticatingMiniMax ? $t('configuration.xlvask.minimax_reauth_in_progress') : $t('configuration.xlvask.minimax_reauthenticate') }}</span>
</button>
<button class="button is-danger ml-2" @click="onClickRemoveMiniMax" :disabled="removingMiniMax">
<span class="icon">
<i class="fas fa-trash"></i>
</span>
<span>{{ removingMiniMax ? $t('configuration.xlvask.minimax_remove_in_progress') : $t('configuration.xlvask.minimax_remove') }}</span>
</button>
</div>
</ConfigurationCategory> </ConfigurationCategory>
<div class="buttons"> <div class="buttons">
<button class="button is-dark" @click="onClickTestConnection"> <button class="button is-dark" @click="onClickTestConnection">