@cat-factory/app 0.97.0 → 0.97.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.
@@ -12,6 +12,7 @@ import type {
12
12
  } from '~/types/domain'
13
13
  import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBindingsResolved.vue'
14
14
  import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
15
+ import { apiErrorEnvelope } from '~/composables/api/errors'
15
16
 
16
17
  // Frontend-frame (`type: 'frontend'`) configuration: how to build, serve, and mock this
17
18
  // frontend for a self-contained UI test (+ an optional browsable preview on local/node),
@@ -119,7 +120,9 @@ const showPreview = ref(false)
119
120
  // frame links to its repo the same way a service does (`github_repos.block_id`).
120
121
  const repoLink = computed(() => github.repoForBlock(props.block.id))
121
122
  const detecting = ref(false)
122
- const detectError = ref(false)
123
+ // The detect failure message to show, or null when there's no error. Holds the SERVER's real
124
+ // message (the backend raises an actionable one for an unreadable repo) instead of a fixed line.
125
+ const detectError = ref<string | null>(null)
123
126
  const detectResult = ref<FrontendConfigRecommendation | null>(null)
124
127
 
125
128
  // A detection result is scoped to the inspected block — clear it (and any error) when the
@@ -128,18 +131,20 @@ watch(
128
131
  () => props.block.id,
129
132
  () => {
130
133
  detectResult.value = null
131
- detectError.value = false
134
+ detectError.value = null
132
135
  },
133
136
  )
134
137
 
135
138
  async function detectFromRepo() {
136
139
  const repo = repoLink.value
137
140
  if (!repo) {
138
- detectError.value = true
141
+ // The frame points at a repo that isn't in the connected-repo projection, so we can't resolve
142
+ // its owner/name to ask the backend. A "sync/connect GitHub" problem, not a read failure.
143
+ detectError.value = t('inspector.detectRepoUnresolved')
139
144
  return
140
145
  }
141
146
  detecting.value = true
142
- detectError.value = false
147
+ detectError.value = null
143
148
  detectResult.value = null
144
149
  try {
145
150
  const result = await infra.detectFrontendConfig({
@@ -151,8 +156,13 @@ async function detectFromRepo() {
151
156
  // When nothing was detected the "none" hint tells the user to set the frontend directory —
152
157
  // that field lives in the (collapsed) Build group, so open it so the advice is actionable.
153
158
  if (!result.detected) showBuild.value = true
154
- } catch {
155
- detectError.value = true
159
+ } catch (e) {
160
+ // Surface the server's real message (an actionable "couldn't read the repo — check App access"
161
+ // for a read fault), falling back to the generic line only when none is available.
162
+ detectError.value =
163
+ apiErrorEnvelope(e)?.message ??
164
+ (e instanceof Error ? e.message : null) ??
165
+ t('inspector.frontendConfig.detect.error')
156
166
  } finally {
157
167
  detecting.value = false
158
168
  }
@@ -243,7 +253,7 @@ onUnmounted(() => preview.stopPolling(props.block.id))
243
253
  </p>
244
254
 
245
255
  <p v-if="detectError" class="text-[11px] text-rose-300/80">
246
- {{ t('inspector.frontendConfig.detect.error') }}
256
+ {{ detectError }}
247
257
  </p>
248
258
 
249
259
  <template v-if="detectResult && !detecting">
@@ -18,6 +18,7 @@ import type {
18
18
  } from '@cat-factory/contracts'
19
19
  import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
20
20
  import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
21
+ import { apiErrorEnvelope } from '~/composables/api/errors'
21
22
 
22
23
  // Service-level (frame) configuration: the service-owned PROVISIONING — the provision
23
24
  // TYPE this service produces (`infraless` / `docker-compose` / `kubernetes` / `custom`)
@@ -284,7 +285,10 @@ function applyPicked() {
284
285
  // every field stays editable, and the engine-level URL/namespace suggestions are surfaced
285
286
  // read-only (the workspace handler owns them). Nothing is persisted server-side by detection.
286
287
  const detecting = ref(false)
287
- const detectError = ref(false)
288
+ // The detect failure message to show, or null when there's no error. Holds the SERVER's real
289
+ // message (the backend now raises an actionable one for an unreadable repo) so the user sees why
290
+ // detection failed instead of a fixed, vague line.
291
+ const detectError = ref<string | null>(null)
288
292
  const detectResult = ref<ProvisioningRecommendation | null>(null)
289
293
  // Advisory, LOCAL-ONLY selection: which compose `services:` key the user picked. It is NOT persisted
290
294
  // (the compose backend targets the file, not a single service), so it lives only in component state
@@ -298,7 +302,7 @@ watch(
298
302
  () => props.block.id,
299
303
  () => {
300
304
  detectResult.value = null
301
- detectError.value = false
305
+ detectError.value = null
302
306
  pickedComposeService.value = null
303
307
  },
304
308
  )
@@ -308,11 +312,14 @@ async function detectFromRepo() {
308
312
  if (!ctx) return
309
313
  const repo = github.repoFor(ctx.githubId)
310
314
  if (!repo) {
311
- detectError.value = true
315
+ // The frame points at a repo that isn't in the connected-repo projection, so we can't resolve
316
+ // its owner/name to ask the backend. That's a "sync/connect GitHub" problem, NOT "couldn't read
317
+ // the repo" — say so specifically.
318
+ detectError.value = t('inspector.detectRepoUnresolved')
312
319
  return
313
320
  }
314
321
  detecting.value = true
315
- detectError.value = false
322
+ detectError.value = null
316
323
  try {
317
324
  const rec = await infra.detectProvisioning({
318
325
  owner: repo.owner,
@@ -342,8 +349,13 @@ async function detectFromRepo() {
342
349
  board.updateBlock(props.block.id, { provisioning: rec.provisioning })
343
350
  if (rec.provisioning.type === 'kubernetes') seedKubeSource(rec.provisioning.manifestSource)
344
351
  }
345
- } catch {
346
- detectError.value = true
352
+ } catch (e) {
353
+ // Surface the server's real message (an actionable "couldn't read the repo — check App access"
354
+ // for a read fault), falling back to the generic line only when none is available.
355
+ detectError.value =
356
+ apiErrorEnvelope(e)?.message ??
357
+ (e instanceof Error ? e.message : null) ??
358
+ t('inspector.testConfig.detect.error')
347
359
  } finally {
348
360
  detecting.value = false
349
361
  }
@@ -452,7 +464,7 @@ function setSize(value: InstanceSize) {
452
464
  </p>
453
465
 
454
466
  <p v-if="detectError" class="text-[11px] text-rose-300/80">
455
- {{ t('inspector.testConfig.detect.error') }}
467
+ {{ detectError }}
456
468
  </p>
457
469
 
458
470
  <template v-if="detectResult && !detecting">
@@ -504,6 +504,7 @@
504
504
  }
505
505
  },
506
506
  "inspector": {
507
+ "detectRepoUnresolved": "This block's repository isn't among the connected GitHub repos, so it can't be read. Connect or sync GitHub for it, then retry.",
507
508
  "container": {
508
509
  "title": "Contents",
509
510
  "hint": "The modules and tasks inside this block. Click an entry to select it on the board.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "El repositorio de este bloque no está entre los repositorios de GitHub conectados, por lo que no se puede leer. Conecta o sincroniza GitHub para él y vuelve a intentarlo.",
464
465
  "container": {
465
466
  "title": "Contenido",
466
467
  "hint": "Los módulos y tareas dentro de este bloque. Haz clic en una entrada para seleccionarla en el tablero.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "Le dépôt de ce bloc ne figure pas parmi les dépôts GitHub connectés et ne peut donc pas être lu. Connectez ou synchronisez GitHub pour ce dépôt, puis réessayez.",
464
465
  "container": {
465
466
  "title": "Contenu",
466
467
  "hint": "Les modules et les tâches contenus dans ce bloc. Cliquez sur une entrée pour la sélectionner sur le tableau.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "מאגר הקוד של בלוק זה אינו נמצא בין מאגרי GitHub המחוברים, ולכן לא ניתן לקרוא אותו. חבר או סנכרן את GitHub עבורו ונסה שוב.",
464
465
  "container": {
465
466
  "title": "תוכן",
466
467
  "hint": "המודולים והמשימות בתוך בלוק זה. לחץ על פריט כדי לבחור אותו בלוח.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "このブロックのリポジトリは接続済みの GitHub リポジトリに含まれていないため、読み取れません。GitHub を接続または同期してから、もう一度お試しください。",
464
465
  "container": {
465
466
  "title": "内容",
466
467
  "hint": "このブロック内のモジュールとタスク。エントリをクリックするとボード上で選択されます。",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "Repozytorium tego bloku nie znajduje się wśród połączonych repozytoriów GitHub, więc nie można go odczytać. Połącz lub zsynchronizuj GitHub dla tego repozytorium, a następnie spróbuj ponownie.",
464
465
  "container": {
465
466
  "title": "Zawartość",
466
467
  "hint": "Moduły i zadania wewnątrz tego bloku. Kliknij pozycję, aby zaznaczyć ją na tablicy.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "Bu bloğun deposu bağlı GitHub depoları arasında değil, bu yüzden okunamıyor. Bunun için GitHub'ı bağlayın veya eşitleyin, ardından yeniden deneyin.",
464
465
  "container": {
465
466
  "title": "İçerik",
466
467
  "hint": "Bu bloğun içindeki modüller ve görevler. Bir öğeye tıklayarak panoda seçin.",
@@ -461,6 +461,7 @@
461
461
  }
462
462
  },
463
463
  "inspector": {
464
+ "detectRepoUnresolved": "Репозиторій цього блоку відсутній серед підключених репозиторіїв GitHub, тому його не вдається прочитати. Підключіть або синхронізуйте GitHub для нього та повторіть спробу.",
464
465
  "container": {
465
466
  "title": "Вміст",
466
467
  "hint": "Модулі та завдання всередині цього блока. Клацніть запис, щоб вибрати його на дошці.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.97.0",
3
+ "version": "0.97.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",