From c66fdaeb0423ef884e93cc34d656379e4b1f9cf4 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 22:55:35 +0000
Subject: [PATCH 1/2] feat(web/dashboard): improve gateway configuration form
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Mask pairing code input with type="password"
- Normalize baseUrl in payload to match gatewayBaseUrl (trim trailing slash)
- Reset save status banner with a 3s timeout after successful save
- Hide save status banner when any form field is edited
- Conditionally include secrets in request body only if they are not empty
- Add a 10s timeout to the POST request using AbortController
- Ensure timeouts are cleared on component unmount
- Fix typo "Requisitos minimos" to "Requisitos mínimos" in README.md
- Add "test" and "test:dashboard" scripts to web monorepo root
- Update README.md with the new test commands
Co-authored-by: yacosta738 <33158051+yacosta738@users.noreply.github.com>
---
clients/web/README.md | 4 +-
clients/web/apps/dashboard/src/App.vue | 57 +++++++++++++++++++++-----
clients/web/package.json | 4 +-
3 files changed, 53 insertions(+), 12 deletions(-)
diff --git a/clients/web/README.md b/clients/web/README.md
index 422de9e38..1fc826513 100644
--- a/clients/web/README.md
+++ b/clients/web/README.md
@@ -36,7 +36,7 @@ clients/web/
## 🛠️ Comandos
-Requisitos minimos:
+Requisitos mínimos:
- Node.js 20.19+ (recomendado 22+)
- pnpm 10.30+
@@ -67,6 +67,8 @@ pnpm dev:landing
# Quality
pnpm format
pnpm check
+pnpm test
+pnpm test:dashboard
```
## 📦 Añadir más proyectos web
diff --git a/clients/web/apps/dashboard/src/App.vue b/clients/web/apps/dashboard/src/App.vue
index 6c1ae9c56..2f7c6abd8 100644
--- a/clients/web/apps/dashboard/src/App.vue
+++ b/clients/web/apps/dashboard/src/App.vue
@@ -1,5 +1,5 @@
@@ -160,13 +196,14 @@ async function sendMessage(): Promise {
>
diff --git a/clients/web/package.json b/clients/web/package.json
index 1d126380e..de7175bdd 100644
--- a/clients/web/package.json
+++ b/clients/web/package.json
@@ -16,7 +16,9 @@
"dev:dashboard": "pnpm --filter @corvus/dashboard run dev",
"format": "pnpm -r run format",
"check": "pnpm -r run check",
- "clean": "pnpm -r run clean"
+ "clean": "pnpm -r run clean",
+ "test": "pnpm -r run test",
+ "test:dashboard": "pnpm --filter @corvus/dashboard run test"
},
"devDependencies": {
"@biomejs/biome": "^2.4.2",
From 72d8e9b648b4e3e45db862e58c7816ccb41296e6 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Wed, 18 Feb 2026 06:03:38 +0000
Subject: [PATCH 2/2] fix(web/dashboard): refine gateway configuration form
logic
- Add guard to resetSaveStatus to prevent resetting state during in-flight requests
- Change timeout variables from reactive refs to plain mutable variables for efficiency
- Add "timeoutError" localization to Spanish locale
- Improve error message fallback logic in saveGatewayConfig
- Ensure error message keys are checked correctly with i18n
- Clean up unused reactive refs for timeouts
Co-authored-by: yacosta738 <33158051+yacosta738@users.noreply.github.com>
---
clients/web/apps/dashboard/src/App.vue | 29 +++++++++++--------
.../web/apps/dashboard/src/locales/es.json | 3 +-
2 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/clients/web/apps/dashboard/src/App.vue b/clients/web/apps/dashboard/src/App.vue
index 2f7c6abd8..11f133062 100644
--- a/clients/web/apps/dashboard/src/App.vue
+++ b/clients/web/apps/dashboard/src/App.vue
@@ -31,8 +31,9 @@ const chatContainer = ref(null);
const secretInputNonce = ref(0);
const saveStatus = ref<"idle" | "saving" | "success" | "error">("idle");
const saveErrorMessage = ref("");
-const saveStatusTimeoutId = ref | null>(null);
-const requestTimeoutId = ref | null>(null);
+
+let saveStatusTimeoutId: ReturnType | null = null;
+let requestTimeoutId: ReturnType | null = null;
let messageIdCounter = 1;
let pairingCodeInput = "";
@@ -57,9 +58,13 @@ function nextMessageId(): number {
}
function resetSaveStatus(): void {
- if (saveStatusTimeoutId.value) {
- clearTimeout(saveStatusTimeoutId.value);
- saveStatusTimeoutId.value = null;
+ if (saveStatus.value === "saving") {
+ return;
+ }
+
+ if (saveStatusTimeoutId) {
+ clearTimeout(saveStatusTimeoutId);
+ saveStatusTimeoutId = null;
}
saveStatus.value = "idle";
}
@@ -86,7 +91,7 @@ async function saveGatewayConfig(): Promise {
const gatewayBaseUrl = baseUrl.value.replace(/\/$/, "");
const controller = new AbortController();
- requestTimeoutId.value = setTimeout(() => controller.abort(), 10000);
+ requestTimeoutId = setTimeout(() => controller.abort(), 10000);
try {
const payload: Record = {
@@ -117,7 +122,7 @@ async function saveGatewayConfig(): Promise {
secretInputNonce.value += 1;
saveStatus.value = "success";
- saveStatusTimeoutId.value = setTimeout(() => {
+ saveStatusTimeoutId = setTimeout(() => {
saveStatus.value = "idle";
}, 3000);
} catch (error) {
@@ -129,9 +134,9 @@ async function saveGatewayConfig(): Promise {
}
console.error("Error saving gateway config", error);
} finally {
- if (requestTimeoutId.value) {
- clearTimeout(requestTimeoutId.value);
- requestTimeoutId.value = null;
+ if (requestTimeoutId) {
+ clearTimeout(requestTimeoutId);
+ requestTimeoutId = null;
}
}
}
@@ -169,8 +174,8 @@ async function sendMessage(): Promise {
}
onUnmounted(() => {
- if (saveStatusTimeoutId.value) clearTimeout(saveStatusTimeoutId.value);
- if (requestTimeoutId.value) clearTimeout(requestTimeoutId.value);
+ if (saveStatusTimeoutId) clearTimeout(saveStatusTimeoutId);
+ if (requestTimeoutId) clearTimeout(requestTimeoutId);
});
diff --git a/clients/web/apps/dashboard/src/locales/es.json b/clients/web/apps/dashboard/src/locales/es.json
index 4c5e214b0..620770ed7 100644
--- a/clients/web/apps/dashboard/src/locales/es.json
+++ b/clients/web/apps/dashboard/src/locales/es.json
@@ -16,7 +16,8 @@
"webhookSecretPlaceholder": "Secreto del webhook",
"save": "Guardar configuración",
"saveSuccess": "Configuración guardada correctamente",
- "saveError": "No se pudo guardar la configuración"
+ "saveError": "No se pudo guardar la configuración",
+ "timeoutError": "Tiempo de espera agotado"
},
"chat": {
"welcome": "Hola, soy {modelName}. ¿En qué puedo ayudarte?",