@cat-factory/app 0.167.0 → 0.167.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/settings/ConnectionWarnings.vue +38 -0
- package/app/components/settings/KubernetesEnvironmentForm.vue +5 -1
- package/app/components/settings/ProviderConnectionTab.vue +5 -1
- package/app/components/settings/ProviderManifestEditor.vue +5 -1
- package/app/utils/connectionWarnings.ts +17 -0
- package/i18n/locales/de.json +6 -1
- package/i18n/locales/en.json +6 -1
- package/i18n/locales/es.json +6 -1
- package/i18n/locales/fr.json +6 -1
- package/i18n/locales/he.json +6 -1
- package/i18n/locales/it.json +6 -1
- package/i18n/locales/ja.json +6 -1
- package/i18n/locales/pl.json +6 -1
- package/i18n/locales/tr.json +6 -1
- package/i18n/locales/uk.json +6 -1
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// The non-fatal GAPS a connection test reports about the config it just probed: it connects,
|
|
3
|
+
// but something it never declared costs a recovery or cleanup path that only shows itself
|
|
4
|
+
// during an incident (a runner-pool manifest with no `release` template leaks a runner on
|
|
5
|
+
// every cancelled run).
|
|
6
|
+
//
|
|
7
|
+
// Rendered beside the pass/fail verdict rather than as part of it, because the two are
|
|
8
|
+
// independent — a green test with a gap is the common case, and folding the gap into the
|
|
9
|
+
// failure line would make a working connection look broken.
|
|
10
|
+
//
|
|
11
|
+
// The backend sends machine-readable codes (it does not localize prose); the copy lives in the
|
|
12
|
+
// catalog behind `CONNECTION_WARNING_KEYS`. A code this SPA build predates falls back to the
|
|
13
|
+
// backend's own English `message` — untranslated, but never a blank row.
|
|
14
|
+
import type { ConnectionWarning } from '@cat-factory/contracts'
|
|
15
|
+
import { CONNECTION_WARNING_KEYS } from '~/utils/connectionWarnings'
|
|
16
|
+
|
|
17
|
+
defineProps<{ warnings?: ConnectionWarning[] }>()
|
|
18
|
+
|
|
19
|
+
const { t, te } = useI18n()
|
|
20
|
+
|
|
21
|
+
const copy = (warning: ConnectionWarning): string => {
|
|
22
|
+
const key = CONNECTION_WARNING_KEYS[warning.code]
|
|
23
|
+
return key && te(key) ? t(key) : warning.message
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div
|
|
29
|
+
v-if="warnings?.length"
|
|
30
|
+
class="rounded-md border border-amber-500/40 bg-amber-950/40 px-3 py-2 text-xs text-amber-200"
|
|
31
|
+
data-testid="connection-warnings"
|
|
32
|
+
>
|
|
33
|
+
<p class="font-semibold">{{ t('settings.providerConnection.test.warningsTitle') }}</p>
|
|
34
|
+
<ul class="mt-1 list-disc space-y-1 pl-4">
|
|
35
|
+
<li v-for="warning in warnings" :key="warning.code">{{ copy(warning) }}</li>
|
|
36
|
+
</ul>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
// driven (see docs/initiatives/descriptor-driven-infra-forms.md).
|
|
11
11
|
import { computed, reactive, ref, watch } from 'vue'
|
|
12
12
|
import { KUBERNETES_ENV_TOKEN_SECRET_KEY } from '@cat-factory/contracts'
|
|
13
|
+
import type { ConnectionTestResult } from '@cat-factory/contracts'
|
|
14
|
+
import ConnectionWarnings from '~/components/settings/ConnectionWarnings.vue'
|
|
13
15
|
import SecretInput from '~/components/common/SecretInput.vue'
|
|
14
16
|
import type { ProviderConnection } from '~/types/providerConnections'
|
|
15
17
|
|
|
@@ -18,7 +20,7 @@ const props = defineProps<{
|
|
|
18
20
|
supportsTest: boolean
|
|
19
21
|
testing: boolean
|
|
20
22
|
busy: boolean
|
|
21
|
-
testResult:
|
|
23
|
+
testResult: ConnectionTestResult | null
|
|
22
24
|
}>()
|
|
23
25
|
|
|
24
26
|
const emit = defineEmits<{
|
|
@@ -409,6 +411,8 @@ function optional(label: string): string {
|
|
|
409
411
|
</span>
|
|
410
412
|
</div>
|
|
411
413
|
|
|
414
|
+
<ConnectionWarnings :warnings="testResult?.warnings" />
|
|
415
|
+
|
|
412
416
|
<div class="flex items-center justify-end gap-3">
|
|
413
417
|
<p v-if="connectBlockedReason" class="flex-1 text-left text-xs text-rose-400">
|
|
414
418
|
{{ connectBlockedReason }}
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
// - a MANIFEST-driven provider (no template) → the full JSON manifest editor
|
|
13
13
|
// (ProviderManifestEditor), which replaces the old "use the API" disclaimer.
|
|
14
14
|
import { computed, ref, toRaw, watch } from 'vue'
|
|
15
|
+
import type { ConnectionTestResult } from '@cat-factory/contracts'
|
|
15
16
|
import type { ProviderConfigField, ProviderConnectionKind } from '~/types/providerConnections'
|
|
17
|
+
import ConnectionWarnings from '~/components/settings/ConnectionWarnings.vue'
|
|
16
18
|
import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
|
|
17
19
|
import ProviderManifestEditor from '~/components/settings/ProviderManifestEditor.vue'
|
|
18
20
|
import KubernetesEnvironmentForm from '~/components/settings/KubernetesEnvironmentForm.vue'
|
|
@@ -56,7 +58,7 @@ const showLogs = ref(false)
|
|
|
56
58
|
|
|
57
59
|
// --- Shared state -------------------------------------------------------------------
|
|
58
60
|
const values = ref<Record<string, string>>({})
|
|
59
|
-
const testResult = ref<
|
|
61
|
+
const testResult = ref<ConnectionTestResult | null>(null)
|
|
60
62
|
const testing = ref(false)
|
|
61
63
|
const busy = ref(false)
|
|
62
64
|
|
|
@@ -515,6 +517,8 @@ function fieldHelp(key: string): string | undefined {
|
|
|
515
517
|
</span>
|
|
516
518
|
</div>
|
|
517
519
|
|
|
520
|
+
<ConnectionWarnings :warnings="testResult?.warnings" />
|
|
521
|
+
|
|
518
522
|
<div class="flex justify-end">
|
|
519
523
|
<UButton
|
|
520
524
|
color="primary"
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
import { computed, ref, watch } from 'vue'
|
|
18
18
|
import * as v from 'valibot'
|
|
19
19
|
import { environmentManifestSchema, runnerPoolManifestSchema } from '@cat-factory/contracts'
|
|
20
|
+
import type { ConnectionTestResult } from '@cat-factory/contracts'
|
|
20
21
|
import type { ProviderConnectionKind } from '~/types/providerConnections'
|
|
22
|
+
import ConnectionWarnings from '~/components/settings/ConnectionWarnings.vue'
|
|
21
23
|
import SecretInput from '~/components/common/SecretInput.vue'
|
|
22
24
|
|
|
23
25
|
const props = defineProps<{
|
|
@@ -34,7 +36,7 @@ const props = defineProps<{
|
|
|
34
36
|
/** Bubbled-up busy state from the tab's store calls (so the editor shows loading). */
|
|
35
37
|
testing: boolean
|
|
36
38
|
busy: boolean
|
|
37
|
-
testResult:
|
|
39
|
+
testResult: ConnectionTestResult | null
|
|
38
40
|
}>()
|
|
39
41
|
|
|
40
42
|
const emit = defineEmits<{
|
|
@@ -286,6 +288,8 @@ function onSave() {
|
|
|
286
288
|
</span>
|
|
287
289
|
</div>
|
|
288
290
|
|
|
291
|
+
<ConnectionWarnings :warnings="testResult?.warnings" />
|
|
292
|
+
|
|
289
293
|
<div class="flex justify-end">
|
|
290
294
|
<UButton
|
|
291
295
|
color="primary"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ConnectionWarningCode } from '@cat-factory/contracts'
|
|
2
|
+
|
|
3
|
+
// A connection test can report non-fatal GAPS in the config beside its pass/fail verdict: the
|
|
4
|
+
// backend states them as machine-readable codes (it does not localize prose), and the copy the
|
|
5
|
+
// operator reads lives here.
|
|
6
|
+
//
|
|
7
|
+
// The exhaustive `Record<ConnectionWarningCode, …>` is the tier-2 drift guard: a backend that
|
|
8
|
+
// adds a warning code fails this typecheck until the SPA has copy for it, which the typed-key
|
|
9
|
+
// check alone cannot catch for a runtime-assembled key.
|
|
10
|
+
|
|
11
|
+
/** Config-gap warning code → i18n key. Leaf keys mirror the code verbatim. */
|
|
12
|
+
export const CONNECTION_WARNING_KEYS: Record<ConnectionWarningCode, string> = {
|
|
13
|
+
runner_manifest_no_release:
|
|
14
|
+
'settings.providerConnection.test.warnings.runner_manifest_no_release',
|
|
15
|
+
runner_manifest_no_status_path:
|
|
16
|
+
'settings.providerConnection.test.warnings.runner_manifest_no_status_path',
|
|
17
|
+
}
|
package/i18n/locales/de.json
CHANGED
|
@@ -298,7 +298,12 @@
|
|
|
298
298
|
"test": {
|
|
299
299
|
"button": "Verbindung testen",
|
|
300
300
|
"ok": "Verbindung OK",
|
|
301
|
-
"failed": "Verbindung fehlgeschlagen"
|
|
301
|
+
"failed": "Verbindung fehlgeschlagen",
|
|
302
|
+
"warningsTitle": "Lücken in dieser Konfiguration",
|
|
303
|
+
"warnings": {
|
|
304
|
+
"runner_manifest_no_release": "Kein Release-Template: Beim Abbrechen eines Laufs kann dem Pool nicht mitgeteilt werden, dass er seinen Job stoppen soll. Ein verwaister Job belegt seinen Runner, bis der Pool ihn von selbst zurücknimmt.",
|
|
305
|
+
"runner_manifest_no_status_path": "Kein Statuspfad: Jede Abfrage wird als weiterhin laufend gelesen. Ein Job kann daher nur enden, wenn das Abfragebudget des Laufs aufgebraucht ist."
|
|
306
|
+
}
|
|
302
307
|
},
|
|
303
308
|
"toast": {
|
|
304
309
|
"saved": "{title} gespeichert",
|
package/i18n/locales/en.json
CHANGED
|
@@ -2467,7 +2467,12 @@
|
|
|
2467
2467
|
"test": {
|
|
2468
2468
|
"button": "Test connection",
|
|
2469
2469
|
"ok": "Connection OK",
|
|
2470
|
-
"failed": "Connection failed"
|
|
2470
|
+
"failed": "Connection failed",
|
|
2471
|
+
"warningsTitle": "Gaps in this configuration",
|
|
2472
|
+
"warnings": {
|
|
2473
|
+
"runner_manifest_no_release": "No release template: cancelling a run cannot tell the pool to stop its job, so an orphaned job keeps its runner until the pool reclaims it on its own.",
|
|
2474
|
+
"runner_manifest_no_status_path": "No status path: every poll reads as still running, so a job can only end by exhausting the run's poll budget."
|
|
2475
|
+
}
|
|
2471
2476
|
},
|
|
2472
2477
|
"toast": {
|
|
2473
2478
|
"saved": "{title} saved",
|
package/i18n/locales/es.json
CHANGED
|
@@ -2202,7 +2202,12 @@
|
|
|
2202
2202
|
"test": {
|
|
2203
2203
|
"button": "Probar conexión",
|
|
2204
2204
|
"ok": "Conexión correcta",
|
|
2205
|
-
"failed": "Falló la conexión"
|
|
2205
|
+
"failed": "Falló la conexión",
|
|
2206
|
+
"warningsTitle": "Carencias en esta configuración",
|
|
2207
|
+
"warnings": {
|
|
2208
|
+
"runner_manifest_no_release": "Sin plantilla de release: al cancelar una ejecución no se puede indicar al pool que detenga su trabajo, así que un trabajo huérfano ocupa su runner hasta que el pool lo recupere por su cuenta.",
|
|
2209
|
+
"runner_manifest_no_status_path": "Sin ruta de estado: cada sondeo se interpreta como todavía en ejecución, así que un trabajo solo puede terminar agotando el presupuesto de sondeo de la ejecución."
|
|
2210
|
+
}
|
|
2206
2211
|
},
|
|
2207
2212
|
"toast": {
|
|
2208
2213
|
"saved": "{title} guardado",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -2202,7 +2202,12 @@
|
|
|
2202
2202
|
"test": {
|
|
2203
2203
|
"button": "Tester la connexion",
|
|
2204
2204
|
"ok": "Connexion réussie",
|
|
2205
|
-
"failed": "Échec de la connexion"
|
|
2205
|
+
"failed": "Échec de la connexion",
|
|
2206
|
+
"warningsTitle": "Lacunes dans cette configuration",
|
|
2207
|
+
"warnings": {
|
|
2208
|
+
"runner_manifest_no_release": "Aucun modèle de release : annuler une exécution ne permet pas de demander au pool d'arrêter son job, donc un job orphelin occupe son runner jusqu'à ce que le pool le récupère de lui-même.",
|
|
2209
|
+
"runner_manifest_no_status_path": "Aucun chemin de statut : chaque interrogation est lue comme toujours en cours, donc un job ne peut se terminer qu'en épuisant le budget d'interrogation de l'exécution."
|
|
2210
|
+
}
|
|
2206
2211
|
},
|
|
2207
2212
|
"toast": {
|
|
2208
2213
|
"saved": "{title} enregistré",
|
package/i18n/locales/he.json
CHANGED
|
@@ -2397,7 +2397,12 @@
|
|
|
2397
2397
|
"test": {
|
|
2398
2398
|
"button": "בדוק חיבור",
|
|
2399
2399
|
"ok": "החיבור תקין",
|
|
2400
|
-
"failed": "החיבור נכשל"
|
|
2400
|
+
"failed": "החיבור נכשל",
|
|
2401
|
+
"warningsTitle": "פערים בתצורה הזו",
|
|
2402
|
+
"warnings": {
|
|
2403
|
+
"runner_manifest_no_release": "אין תבנית שחרור: ביטול הרצה לא יכול להודיע למאגר להפסיק את המשימה שלו, ולכן משימה יתומה תופסת את הראנר שלה עד שהמאגר משחרר אותה בעצמו.",
|
|
2404
|
+
"runner_manifest_no_status_path": "אין נתיב סטטוס: כל תשאול נקרא כאילו המשימה עדיין רצה, ולכן משימה יכולה להסתיים רק לאחר ניצול כל תקציב התשאול של ההרצה."
|
|
2405
|
+
}
|
|
2401
2406
|
},
|
|
2402
2407
|
"toast": {
|
|
2403
2408
|
"saved": "{title} נשמר",
|
package/i18n/locales/it.json
CHANGED
|
@@ -298,7 +298,12 @@
|
|
|
298
298
|
"test": {
|
|
299
299
|
"button": "Testa la connessione",
|
|
300
300
|
"ok": "Connessione OK",
|
|
301
|
-
"failed": "Connessione fallita"
|
|
301
|
+
"failed": "Connessione fallita",
|
|
302
|
+
"warningsTitle": "Lacune in questa configurazione",
|
|
303
|
+
"warnings": {
|
|
304
|
+
"runner_manifest_no_release": "Nessun template di release: annullare un'esecuzione non può dire al pool di fermare il suo job, quindi un job orfano tiene occupato il suo runner finché il pool non lo recupera da solo.",
|
|
305
|
+
"runner_manifest_no_status_path": "Nessun percorso di stato: ogni polling viene letto come ancora in corso, quindi un job può terminare solo esaurendo il budget di polling dell'esecuzione."
|
|
306
|
+
}
|
|
302
307
|
},
|
|
303
308
|
"toast": {
|
|
304
309
|
"saved": "{title} salvato",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -2398,7 +2398,12 @@
|
|
|
2398
2398
|
"test": {
|
|
2399
2399
|
"button": "接続をテスト",
|
|
2400
2400
|
"ok": "接続 OK",
|
|
2401
|
-
"failed": "接続に失敗しました"
|
|
2401
|
+
"failed": "接続に失敗しました",
|
|
2402
|
+
"warningsTitle": "この設定の不足点",
|
|
2403
|
+
"warnings": {
|
|
2404
|
+
"runner_manifest_no_release": "release テンプレートがありません。実行をキャンセルしてもプールにジョブの停止を伝えられないため、取り残されたジョブはプールが自分で回収するまでランナーを占有し続けます。",
|
|
2405
|
+
"runner_manifest_no_status_path": "ステータスパスがありません。ポーリングは常に実行中と解釈されるため、ジョブは実行のポーリング上限を使い切ることでしか終了できません。"
|
|
2406
|
+
}
|
|
2402
2407
|
},
|
|
2403
2408
|
"toast": {
|
|
2404
2409
|
"saved": "{title} を保存しました",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -2202,7 +2202,12 @@
|
|
|
2202
2202
|
"test": {
|
|
2203
2203
|
"button": "Przetestuj połączenie",
|
|
2204
2204
|
"ok": "Połączenie poprawne",
|
|
2205
|
-
"failed": "Połączenie nieudane"
|
|
2205
|
+
"failed": "Połączenie nieudane",
|
|
2206
|
+
"warningsTitle": "Braki w tej konfiguracji",
|
|
2207
|
+
"warnings": {
|
|
2208
|
+
"runner_manifest_no_release": "Brak szablonu release: anulowanie przebiegu nie może przekazać puli, że ma zatrzymać zadanie, więc osierocone zadanie zajmuje swojego runnera, dopóki pula sama go nie odzyska.",
|
|
2209
|
+
"runner_manifest_no_status_path": "Brak ścieżki statusu: każde odpytanie jest odczytywane jako wciąż trwające, więc zadanie może zakończyć się tylko po wyczerpaniu budżetu odpytań przebiegu."
|
|
2210
|
+
}
|
|
2206
2211
|
},
|
|
2207
2212
|
"toast": {
|
|
2208
2213
|
"saved": "Zapisano: {title}",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -2398,7 +2398,12 @@
|
|
|
2398
2398
|
"test": {
|
|
2399
2399
|
"button": "Bağlantıyı test et",
|
|
2400
2400
|
"ok": "Bağlantı tamam",
|
|
2401
|
-
"failed": "Bağlantı başarısız"
|
|
2401
|
+
"failed": "Bağlantı başarısız",
|
|
2402
|
+
"warningsTitle": "Bu yapılandırmadaki eksikler",
|
|
2403
|
+
"warnings": {
|
|
2404
|
+
"runner_manifest_no_release": "Release şablonu yok: bir çalıştırma iptal edildiğinde havuza işi durdurması söylenemez, bu yüzden sahipsiz kalan iş, havuz onu kendi kendine geri alana kadar runner'ını meşgul tutar.",
|
|
2405
|
+
"runner_manifest_no_status_path": "Durum yolu yok: her yoklama hâlâ çalışıyor olarak okunur, bu yüzden bir iş ancak çalıştırmanın yoklama bütçesi tükendiğinde sona erebilir."
|
|
2406
|
+
}
|
|
2402
2407
|
},
|
|
2403
2408
|
"toast": {
|
|
2404
2409
|
"saved": "{title} kaydedildi",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -2202,7 +2202,12 @@
|
|
|
2202
2202
|
"test": {
|
|
2203
2203
|
"button": "Перевірити підключення",
|
|
2204
2204
|
"ok": "Підключення в порядку",
|
|
2205
|
-
"failed": "Не вдалося підключитися"
|
|
2205
|
+
"failed": "Не вдалося підключитися",
|
|
2206
|
+
"warningsTitle": "Прогалини в цій конфігурації",
|
|
2207
|
+
"warnings": {
|
|
2208
|
+
"runner_manifest_no_release": "Немає шаблону release: скасування запуску не може повідомити пулу, що завдання треба зупинити, тож осиротіле завдання займає свій раннер, доки пул не забере його сам.",
|
|
2209
|
+
"runner_manifest_no_status_path": "Немає шляху до статусу: кожне опитування читається як таке, що ще триває, тож завдання може завершитися лише після вичерпання бюджету опитувань запуску."
|
|
2210
|
+
}
|
|
2206
2211
|
},
|
|
2207
2212
|
"toast": {
|
|
2208
2213
|
"saved": "{title} збережено",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.167.
|
|
3
|
+
"version": "0.167.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.40",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.180.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|