@cat-factory/app 0.250.0 → 0.252.0

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.
@@ -1,7 +1,11 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { documentFreshnessChangeSchema, documentFreshnessGapSchema } from '@cat-factory/contracts'
2
+ import {
3
+ documentFreshnessChangeSchema,
4
+ documentFreshnessGapSchema,
5
+ documentRenderStatusSchema,
6
+ } from '@cat-factory/contracts'
3
7
  import { missingI18nKeys } from '../../../test/i18nKeys'
4
- import { CHANGE_KEYS, GAP_KEYS } from './DocumentSyncState.logic'
8
+ import { CHANGE_KEYS, GAP_KEYS, RENDER_STATUS_KEYS } from './DocumentSyncState.logic'
5
9
 
6
10
  /**
7
11
  * The half of these tables' correctness that no guard can see.
@@ -24,10 +28,20 @@ describe('DocumentSyncState freshness tables', () => {
24
28
  expect(missingI18nKeys(Object.values(CHANGE_KEYS))).toEqual([])
25
29
  })
26
30
 
31
+ it('names a key the base catalog holds for every render status that states one', () => {
32
+ // The `null` half is deliberate (see the table): only the statuses that name a FIX render.
33
+ expect(missingI18nKeys(Object.values(RENDER_STATUS_KEYS).filter((k) => k !== null))).toEqual([])
34
+ })
35
+
27
36
  it('covers exactly the contracts vocabularies, with no entry for a member that is gone', () => {
28
37
  expect(Object.keys(GAP_KEYS).sort()).toEqual([...documentFreshnessGapSchema.options].sort())
29
38
  expect(Object.keys(CHANGE_KEYS).sort()).toEqual(
30
39
  [...documentFreshnessChangeSchema.options].sort(),
31
40
  )
41
+ // A new render status has to be CLASSIFIED (a key or an explicit null), never omitted into
42
+ // silence: an unclassified one would render nothing and read as "the images are fine".
43
+ expect(Object.keys(RENDER_STATUS_KEYS).sort()).toEqual(
44
+ [...documentRenderStatusSchema.options].sort(),
45
+ )
32
46
  })
33
47
  })
@@ -1,4 +1,8 @@
1
- import type { DocumentFreshnessChange, DocumentFreshnessGap } from '~/types/domain'
1
+ import type {
2
+ DocumentFreshnessChange,
3
+ DocumentFreshnessGap,
4
+ DocumentRenderStatus,
5
+ } from '~/types/domain'
2
6
 
3
7
  /**
4
8
  * The i18n keys `DocumentSyncState` renders a freshness verdict through, in their own module so a
@@ -36,3 +40,25 @@ export const CHANGE_KEYS = {
36
40
  reimported: 'documents.freshness.change.reimported',
37
41
  revision_only: 'documents.freshness.change.revision_only',
38
42
  } as const satisfies Record<DocumentFreshnessChange, string>
43
+
44
+ /**
45
+ * What became of a design document's rendered images, for the three statuses that ask something of
46
+ * a person, and `null` for the two that do not.
47
+ *
48
+ * A design import retains its frames as reference images, and every way of failing to renders as
49
+ * the same absence: no picture. `stored` and `none` are the states nothing can be done about
50
+ * ("they are there" and "the design had none"), so they say nothing on an eleven-pixel line already
51
+ * carrying a stamp, a verdict and a button. The other three each name a DIFFERENT fix, which is
52
+ * exactly why they are worth the room: configure image storage, or retry a source that would not
53
+ * render.
54
+ *
55
+ * `null` here rather than an omitted key so the `satisfies` still spans the whole vocabulary: a new
56
+ * status has to be classified rather than falling silently into the unremarkable half.
57
+ */
58
+ export const RENDER_STATUS_KEYS = {
59
+ stored: null,
60
+ none: null,
61
+ partial: 'documents.renders.partial',
62
+ failed: 'documents.renders.failed',
63
+ storage_unavailable: 'documents.renders.storage_unavailable',
64
+ } as const satisfies Record<DocumentRenderStatus, string | null>
@@ -1,7 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import { isConnectableSource } from '@cat-factory/contracts'
3
3
  import type { SourceDocument } from '~/types/domain'
4
- import { CHANGE_KEYS, GAP_KEYS } from '~/components/documents/DocumentSyncState.logic'
4
+ import {
5
+ CHANGE_KEYS,
6
+ GAP_KEYS,
7
+ RENDER_STATUS_KEYS,
8
+ } from '~/components/documents/DocumentSyncState.logic'
5
9
 
6
10
  // When a stored document was last written, and a way to ask its source whether that is still the
7
11
  // current revision.
@@ -129,6 +133,20 @@ const detail = computed(() =>
129
133
  .join(' · '),
130
134
  )
131
135
 
136
+ /**
137
+ * What became of the design's rendered images, when that is something a person can act on.
138
+ *
139
+ * A THIRD fact beside the two above, and separate for the same reason they are separate from each
140
+ * other: it is about the pictures rather than the text, it is written by the import rather than by
141
+ * a click, and folding it into either would make an absent image read as a stale body. It renders
142
+ * only for the statuses that name a fix, so the common case adds nothing to the line.
143
+ */
144
+ const renders = computed(() => {
145
+ const status = props.doc.renderStatus
146
+ const key = status ? RENDER_STATUS_KEYS[status] : null
147
+ return key ? t(key) : ''
148
+ })
149
+
132
150
  const TONE_CLASS: Record<Stated['tone'], string> = {
133
151
  ok: 'text-emerald-400',
134
152
  warn: 'text-amber-400',
@@ -165,6 +183,10 @@ async function refresh() {
165
183
  <UIcon :name="stated.icon" class="h-3 w-3 shrink-0" />
166
184
  <span class="truncate">{{ stated.text }}</span>
167
185
  </span>
186
+ <span v-if="renders" class="flex min-w-0 items-center gap-1 text-slate-500" :title="renders">
187
+ <UIcon name="i-lucide-image-off" class="h-3 w-3 shrink-0" />
188
+ <span class="truncate">{{ renders }}</span>
189
+ </span>
168
190
  <UButton
169
191
  v-if="askable"
170
192
  color="neutral"
@@ -16,6 +16,13 @@ const props = defineProps<{
16
16
  referenceId: string | null | undefined
17
17
  blobs: ArtifactBlobs
18
18
  busy?: boolean
19
+ /**
20
+ * Where the reference came from, when the caller knows. A frame rendered from a linked design
21
+ * and a mock a person attached are different claims about what "the reference" is, so the
22
+ * caption says which; absent leaves the plain label, which is what an unattributed reference
23
+ * honestly is.
24
+ */
25
+ referenceOrigin?: 'upload' | 'design' | null
19
26
  }>()
20
27
 
21
28
  const emit = defineEmits<{
@@ -196,6 +203,9 @@ function onRefInput(e: Event) {
196
203
  <figure class="space-y-1">
197
204
  <figcaption class="text-[10px] uppercase tracking-wide text-slate-500">
198
205
  {{ t('media.compare.reference') }}
206
+ <span v-if="referenceOrigin === 'design'" class="text-amber-300/80">
207
+ {{ t('media.compare.fromLinkedDesign') }}
208
+ </span>
199
209
  </figcaption>
200
210
  <button
201
211
  v-if="refUrl"
@@ -8,7 +8,7 @@
8
8
  // (per-view notes + a freeform box, composed into the Tester's fixer findings), or recapture.
9
9
  // References can be dropped straight onto a pair, or uploaded for any view below.
10
10
  import { computed, onUnmounted, reactive, ref, watch } from 'vue'
11
- import type { VisualConfirmStepState } from '~/types/execution'
11
+ import type { VisualConfirmDesignGapReason, VisualConfirmStepState } from '~/types/execution'
12
12
  import { useArtifactBlobs } from '~/composables/useArtifactBlobs'
13
13
  import ImageCompare from '~/components/media/ImageCompare.vue'
14
14
  import ArtifactLightbox from '~/components/media/ArtifactLightbox.vue'
@@ -63,6 +63,23 @@ const OUTCOME_LABELS = computed<Record<'completed' | 'failed', string>>(() => ({
63
63
  failed: t('visualConfirm.outcome.failed'),
64
64
  }))
65
65
 
66
+ // What the task's LINKED DESIGNS contributed. Present whenever a design is linked, including
67
+ // when everything worked: a reviewer comparing a screen against a Figma frame needs to know the
68
+ // frame is the design's own, and one seeing no design frames needs to know whether a design is
69
+ // linked at all. Absent ⇒ the task links none, which this panel must not invent a line about.
70
+ const design = computed(() => vc.value?.designReferences ?? null)
71
+
72
+ // Exhaustive map of the gap vocabulary → copy, literal-keyed for the same drift-guard reason as
73
+ // the outcome labels above. Each names a DIFFERENT fix, which is why the backend keeps them apart
74
+ // instead of collapsing them into one "no images" absence.
75
+ const DESIGN_GAP_LABELS = computed<Record<VisualConfirmDesignGapReason, string>>(() => ({
76
+ partial: t('visualConfirm.design.gap.partial'),
77
+ failed: t('visualConfirm.design.gap.failed'),
78
+ none: t('visualConfirm.design.gap.none'),
79
+ storage_unavailable: t('visualConfirm.design.gap.storage_unavailable'),
80
+ not_retained: t('visualConfirm.design.gap.not_retained'),
81
+ }))
82
+
66
83
  // Resolve every pair's artifacts (the gallery + the lightbox share this one cache).
67
84
  watch(
68
85
  pairs,
@@ -212,6 +229,35 @@ async function onFilePicked(e: Event) {
212
229
  {{ vc.degradedReason }}
213
230
  </p>
214
231
 
232
+ <!-- What the linked designs contributed. Rendered even when nothing is missing, so a
233
+ reference the reviewer is judging against is never anonymous. -->
234
+ <section
235
+ v-if="design"
236
+ class="rounded-lg border border-slate-800 bg-slate-900/60 px-3 py-2 text-[12px] text-slate-300"
237
+ >
238
+ <p class="flex items-center gap-1.5">
239
+ <UIcon name="i-lucide-figma" class="h-3.5 w-3.5 shrink-0 text-amber-300" />
240
+ <span>{{
241
+ t('visualConfirm.design.summary', { count: design.images }, design.images)
242
+ }}</span>
243
+ <span v-if="design.dropped" class="text-slate-500">
244
+ {{ t('visualConfirm.design.dropped', { count: design.dropped }, design.dropped) }}
245
+ </span>
246
+ </p>
247
+ <!-- One line per short design, carrying both ways it can fall short: what its source
248
+ kept, and what this gallery's shared ceiling cut from it. A design the ceiling shut
249
+ out entirely reads as one with no frames unless it is named here. -->
250
+ <ul v-if="design.gaps?.length" class="mt-1.5 space-y-1 text-[11px] text-amber-300/90">
251
+ <li v-for="gap in design.gaps" :key="`${gap.title}-${gap.reason ?? 'capped'}`">
252
+ {{ t('visualConfirm.design.gapLine', { title: gap.title }) }}
253
+ <template v-if="gap.reason">{{ DESIGN_GAP_LABELS[gap.reason] }}</template>
254
+ <template v-if="gap.dropped">{{
255
+ t('visualConfirm.design.gapDropped', { count: gap.dropped }, gap.dropped)
256
+ }}</template>
257
+ </li>
258
+ </ul>
259
+ </section>
260
+
215
261
  <p
216
262
  v-if="working"
217
263
  class="flex items-center gap-2 rounded-lg border border-slate-800 bg-slate-950/40 px-3 py-2 text-[12px] text-slate-300"
@@ -228,6 +274,7 @@ async function onFilePicked(e: Event) {
228
274
  :view="p.view"
229
275
  :actual-id="p.actualArtifactId"
230
276
  :reference-id="p.referenceArtifactId"
277
+ :reference-origin="p.referenceOrigin"
231
278
  :blobs="blobs"
232
279
  :busy="busy"
233
280
  @expand="expand"
@@ -24,6 +24,7 @@ function doc(over: Partial<SourceDocument> = {}): SourceDocument {
24
24
  role: null,
25
25
  docKind: null,
26
26
  syncedAt: 1_000,
27
+ renderStatus: null,
27
28
  ...over,
28
29
  }
29
30
  }
@@ -18,6 +18,7 @@ export type {
18
18
  DocumentFreshness,
19
19
  DocumentFreshnessChange,
20
20
  DocumentFreshnessGap,
21
+ DocumentRenderStatus,
21
22
  RefreshedDocumentView,
22
23
  SourceDocument,
23
24
  DocumentSearchResult,
@@ -104,6 +104,10 @@ export type {
104
104
  HumanTestStepState,
105
105
  VisualConfirmStepState,
106
106
  VisualConfirmPair,
107
+ VisualConfirmReferenceOrigin,
108
+ VisualConfirmDesignGap,
109
+ VisualConfirmDesignGapReason,
110
+ VisualConfirmDesignReferences,
107
111
  VisualConfirmRound,
108
112
  ExecutionInstance,
109
113
  // The historical frontend name for a per-block review comment is the contract's
@@ -3925,6 +3925,11 @@
3925
3925
  },
3926
3926
  "refreshFailed": "Prüfung auf Änderungen fehlgeschlagen"
3927
3927
  },
3928
+ "renders": {
3929
+ "partial": "Einige Design-Frames konnten nicht als Bilder gespeichert werden.",
3930
+ "failed": "Die Design-Bilder konnten nicht von der Quelle abgerufen werden.",
3931
+ "storage_unavailable": "Design-Bilder wurden nicht gespeichert: für diese Installation ist kein Bildspeicher konfiguriert."
3932
+ },
3928
3933
  "connect": {
3929
3934
  "title": "Quelle verbinden",
3930
3935
  "sourceFallback": "Quelle",
@@ -6148,6 +6153,19 @@
6148
6153
  "history": {
6149
6154
  "heading": "Verlauf (keine Runden) | Verlauf ({count} Runde) | Verlauf ({count} Runden)",
6150
6155
  "fixRequested": "Korrektur angefordert"
6156
+ },
6157
+ "design": {
6158
+ "summary": "Keine Frames stammen aus dem verknüpften Design. | 1 Frame aus dem verknüpften Design. | {count} Frames aus dem verknüpften Design.",
6159
+ "dropped": "Es sind keine weiteren ausgeblendet. | 1 weiterer wird hier nicht angezeigt. | {count} weitere werden hier nicht angezeigt.",
6160
+ "gapDropped": "Keiner seiner Frames ist ausgeblendet. | 1 seiner Frames wird hier nicht angezeigt. | {count} seiner Frames werden hier nicht angezeigt.",
6161
+ "gapLine": "{title}:",
6162
+ "gap": {
6163
+ "partial": "nur ein Teil seiner Frames wurde gespeichert; aktualisiere das Dokument, um es erneut zu versuchen.",
6164
+ "failed": "seine Frames konnten beim letzten Import nicht geladen werden; aktualisiere das Dokument, um es erneut zu versuchen.",
6165
+ "none": "es enthält keine Frames zum Anzeigen.",
6166
+ "storage_unavailable": "beim Import war kein Bildspeicher konfiguriert, daher wurde nichts heruntergeladen.",
6167
+ "not_retained": "es sind keine Bilder dazu gespeichert. Die Quelle rendert möglicherweise keine Frames, oder das Dokument wurde importiert, bevor Frames aufbewahrt wurden; ein erneuter Import zeigt, was zutrifft."
6168
+ }
6151
6169
  }
6152
6170
  },
6153
6171
  "outcome": {
@@ -6394,6 +6412,7 @@
6394
6412
  },
6395
6413
  "actual": "Tatsächlich",
6396
6414
  "reference": "Referenz",
6415
+ "fromLinkedDesign": "· aus dem verknüpften Design",
6397
6416
  "actualAlt": "{view} (tatsächlich)",
6398
6417
  "referenceAlt": "{view} (Referenz)",
6399
6418
  "replace": "Ersetzen",
@@ -4448,6 +4448,11 @@
4448
4448
  },
4449
4449
  "refreshFailed": "Could not check for changes"
4450
4450
  },
4451
+ "renders": {
4452
+ "partial": "Some design frames could not be saved as images.",
4453
+ "failed": "The design images could not be retrieved from the source.",
4454
+ "storage_unavailable": "Design images were not saved: this deployment has no image storage configured."
4455
+ },
4451
4456
  "connect": {
4452
4457
  "title": "Connect source",
4453
4458
  "sourceFallback": "Source",
@@ -5861,6 +5866,19 @@
5861
5866
  "history": {
5862
5867
  "heading": "History (no rounds) | History ({count} round) | History ({count} rounds)",
5863
5868
  "fixRequested": "Fix requested"
5869
+ },
5870
+ "design": {
5871
+ "summary": "No frames came from the linked design. | 1 frame from the linked design. | {count} frames from the linked design.",
5872
+ "dropped": "No others are hidden. | 1 more is not shown here. | {count} more are not shown here.",
5873
+ "gapDropped": "None of its frames are hidden. | 1 of its frames is not shown here. | {count} of its frames are not shown here.",
5874
+ "gapLine": "{title}:",
5875
+ "gap": {
5876
+ "partial": "only part of its frames were retained; refresh the document to try again.",
5877
+ "failed": "its frames could not be downloaded at the last import; refresh the document to retry.",
5878
+ "none": "it has no frames to show.",
5879
+ "storage_unavailable": "no image storage was configured when it was imported, so nothing was downloaded.",
5880
+ "not_retained": "no images are held for it. Its source may not render frames, or it was imported before frames were kept; re-importing tells the two apart."
5881
+ }
5864
5882
  }
5865
5883
  },
5866
5884
  "outcome": {
@@ -6113,6 +6131,7 @@
6113
6131
  },
6114
6132
  "actual": "Actual",
6115
6133
  "reference": "Reference",
6134
+ "fromLinkedDesign": "· from the linked design",
6116
6135
  "actualAlt": "{view} (actual)",
6117
6136
  "referenceAlt": "{view} (reference)",
6118
6137
  "replace": "Replace",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "No se han podido buscar cambios"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "Algunos marcos del diseño no se pudieron guardar como imágenes.",
4316
+ "failed": "No se pudieron obtener las imágenes del diseño desde el origen.",
4317
+ "storage_unavailable": "Las imágenes del diseño no se guardaron: esta instalación no tiene almacenamiento de imágenes configurado."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "Conectar fuente",
4316
4321
  "sourceFallback": "Fuente",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "Historial (sin rondas) | Historial ({count} ronda) | Historial ({count} rondas)",
5594
5599
  "fixRequested": "Corrección solicitada"
5600
+ },
5601
+ "design": {
5602
+ "summary": "Ningún marco procede del diseño vinculado. | 1 marco del diseño vinculado. | {count} marcos del diseño vinculado.",
5603
+ "dropped": "No hay otros ocultos. | 1 más no se muestra aquí. | {count} más no se muestran aquí.",
5604
+ "gapDropped": "Ninguno de sus marcos está oculto. | 1 de sus marcos no se muestra aquí. | {count} de sus marcos no se muestran aquí.",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "solo se conservó parte de sus marcos; actualiza el documento para volver a intentarlo.",
5608
+ "failed": "no se pudieron descargar sus marcos en la última importación; actualiza el documento para reintentarlo.",
5609
+ "none": "no tiene marcos que mostrar.",
5610
+ "storage_unavailable": "no había almacenamiento de imágenes configurado cuando se importó, así que no se descargó nada.",
5611
+ "not_retained": "no hay imágenes guardadas para él. Puede que su origen no genere marcos, o que se importara antes de que se conservaran; volver a importarlo lo aclara."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "Real",
5840
5858
  "reference": "Referencia",
5859
+ "fromLinkedDesign": "· del diseño vinculado",
5841
5860
  "actualAlt": "{view} (real)",
5842
5861
  "referenceAlt": "{view} (referencia)",
5843
5862
  "replace": "Reemplazar",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "Impossible de vérifier les changements"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "Certains cadres de la maquette n'ont pas pu être enregistrés en images.",
4316
+ "failed": "Les images de la maquette n'ont pas pu être récupérées depuis la source.",
4317
+ "storage_unavailable": "Les images de la maquette n'ont pas été enregistrées : aucun stockage d'images n'est configuré pour ce déploiement."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "Connecter une source",
4316
4321
  "sourceFallback": "Source",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "Historique (aucun tour) | Historique ({count} tour) | Historique ({count} tours)",
5594
5599
  "fixRequested": "Correction demandée"
5600
+ },
5601
+ "design": {
5602
+ "summary": "Aucun cadre ne provient de la maquette liée. | 1 cadre issu de la maquette liée. | {count} cadres issus de la maquette liée.",
5603
+ "dropped": "Aucun autre n'est masqué. | 1 de plus n'est pas affiché ici. | {count} de plus ne sont pas affichés ici.",
5604
+ "gapDropped": "Aucun de ses cadres n'est masqué. | 1 de ses cadres n'est pas affiché ici. | {count} de ses cadres ne sont pas affichés ici.",
5605
+ "gapLine": "{title} :",
5606
+ "gap": {
5607
+ "partial": "seule une partie de ses cadres a été conservée ; actualisez le document pour réessayer.",
5608
+ "failed": "ses cadres n'ont pas pu être téléchargés lors du dernier import ; actualisez le document pour réessayer.",
5609
+ "none": "elle n'a aucun cadre à afficher.",
5610
+ "storage_unavailable": "aucun stockage d'images n'était configuré lors de l'import, donc rien n'a été téléchargé.",
5611
+ "not_retained": "aucune image n'est conservée pour elle. Sa source ne produit peut-être pas de cadres, ou elle a été importée avant leur conservation ; un nouvel import permet de trancher."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "Réel",
5840
5858
  "reference": "Référence",
5859
+ "fromLinkedDesign": "· issu de la maquette liée",
5841
5860
  "actualAlt": "{view} (réel)",
5842
5861
  "referenceAlt": "{view} (référence)",
5843
5862
  "replace": "Remplacer",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "לא ניתן היה לבדוק שינויים"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "חלק ממסגרות העיצוב לא נשמרו כתמונות.",
4316
+ "failed": "לא ניתן היה לאחזר את תמונות העיצוב מהמקור.",
4317
+ "storage_unavailable": "תמונות העיצוב לא נשמרו: לפריסה הזו לא מוגדר אחסון תמונות."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "חבר מקור",
4316
4321
  "sourceFallback": "מקור",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "היסטוריה (אין סבבים) | היסטוריה (סבב אחד) | היסטוריה (שני סבבים) | היסטוריה ({count} סבבים)",
5594
5599
  "fixRequested": "התבקש תיקון"
5600
+ },
5601
+ "design": {
5602
+ "summary": "לא התקבלו מסגרות מהעיצוב המקושר. | מסגרת אחת מהעיצוב המקושר. | שתי מסגרות מהעיצוב המקושר. | {count} מסגרות מהעיצוב המקושר.",
5603
+ "dropped": "אין נוספות שאינן מוצגות. | עוד אחת אינה מוצגת כאן. | עוד שתיים אינן מוצגות כאן. | עוד {count} אינן מוצגות כאן.",
5604
+ "gapDropped": "אף אחת מהמסגרות שלו אינה מוסתרת. | מסגרת אחת שלו אינה מוצגת כאן. | שתי מסגרות שלו אינן מוצגות כאן. | {count} מסגרות שלו אינן מוצגות כאן.",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "רק חלק מהמסגרות שלו נשמרו; רענן את המסמך כדי לנסות שוב.",
5608
+ "failed": "לא ניתן היה להוריד את המסגרות שלו בייבוא האחרון; רענן את המסמך כדי לנסות שוב.",
5609
+ "none": "אין בו מסגרות להצגה.",
5610
+ "storage_unavailable": "בעת הייבוא לא הוגדר אחסון תמונות, ולכן לא הורד דבר.",
5611
+ "not_retained": "לא נשמרו עבורו תמונות. ייתכן שהמקור אינו מייצר מסגרות, או שהמסמך יובא לפני שמסגרות נשמרו; ייבוא מחדש יבהיר מה מהשניים."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "בפועל",
5840
5858
  "reference": "ייחוס",
5859
+ "fromLinkedDesign": "· מהעיצוב המקושר",
5841
5860
  "actualAlt": "{view} (בפועל)",
5842
5861
  "referenceAlt": "{view} (ייחוס)",
5843
5862
  "replace": "החלף",
@@ -3925,6 +3925,11 @@
3925
3925
  },
3926
3926
  "refreshFailed": "Impossibile verificare le modifiche"
3927
3927
  },
3928
+ "renders": {
3929
+ "partial": "Alcuni frame del design non è stato possibile salvarli come immagini.",
3930
+ "failed": "Non è stato possibile recuperare le immagini del design dalla sorgente.",
3931
+ "storage_unavailable": "Le immagini del design non sono state salvate: questa installazione non ha uno spazio di archiviazione per le immagini configurato."
3932
+ },
3928
3933
  "connect": {
3929
3934
  "title": "Collega sorgente",
3930
3935
  "sourceFallback": "Sorgente",
@@ -6148,6 +6153,19 @@
6148
6153
  "history": {
6149
6154
  "heading": "Cronologia (nessun round) | Cronologia ({count} round) | Cronologia ({count} round)",
6150
6155
  "fixRequested": "Correzione richiesta"
6156
+ },
6157
+ "design": {
6158
+ "summary": "Nessun frame proviene dal design collegato. | 1 frame dal design collegato. | {count} frame dal design collegato.",
6159
+ "dropped": "Non ce ne sono altri nascosti. | 1 altro non è mostrato qui. | Altri {count} non sono mostrati qui.",
6160
+ "gapDropped": "Nessuno dei suoi frame è nascosto. | 1 dei suoi frame non è mostrato qui. | {count} dei suoi frame non sono mostrati qui.",
6161
+ "gapLine": "{title}:",
6162
+ "gap": {
6163
+ "partial": "solo una parte dei suoi frame è stata conservata; aggiorna il documento per riprovare.",
6164
+ "failed": "non è stato possibile scaricare i suoi frame nell'ultimo import; aggiorna il documento per riprovare.",
6165
+ "none": "non ha frame da mostrare.",
6166
+ "storage_unavailable": "quando è stato importato non era configurato alcuno spazio per le immagini, quindi non è stato scaricato nulla.",
6167
+ "not_retained": "non ci sono immagini conservate per esso. La sua origine potrebbe non generare frame, oppure è stato importato prima che i frame venissero conservati; un nuovo import chiarisce quale dei due."
6168
+ }
6151
6169
  }
6152
6170
  },
6153
6171
  "outcome": {
@@ -6394,6 +6412,7 @@
6394
6412
  },
6395
6413
  "actual": "Effettivo",
6396
6414
  "reference": "Riferimento",
6415
+ "fromLinkedDesign": "· dal design collegato",
6397
6416
  "actualAlt": "{view} (effettivo)",
6398
6417
  "referenceAlt": "{view} (riferimento)",
6399
6418
  "replace": "Sostituisci",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "変更を確認できませんでした"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "一部のデザインフレームを画像として保存できませんでした。",
4316
+ "failed": "ソースからデザイン画像を取得できませんでした。",
4317
+ "storage_unavailable": "デザイン画像は保存されていません。このデプロイには画像ストレージが設定されていません。"
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "ソースを接続",
4316
4321
  "sourceFallback": "ソース",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "履歴(ラウンドなし) | 履歴({count} ラウンド) | 履歴({count} ラウンド)",
5594
5599
  "fixRequested": "修正をリクエスト済み"
5600
+ },
5601
+ "design": {
5602
+ "summary": "リンクされたデザインからのフレームはありません。 | リンクされたデザインから {count} 件のフレーム。 | リンクされたデザインから {count} 件のフレーム。",
5603
+ "dropped": "非表示のものはありません。 | 他に {count} 件はここに表示されていません。 | 他に {count} 件はここに表示されていません。",
5604
+ "gapDropped": "非表示のフレームはありません。 | このデザインのフレーム {count} 件はここに表示されていません。 | このデザインのフレーム {count} 件はここに表示されていません。",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "フレームの一部のみが保持されました。ドキュメントを更新して再試行してください。",
5608
+ "failed": "前回のインポートでフレームをダウンロードできませんでした。ドキュメントを更新して再試行してください。",
5609
+ "none": "表示できるフレームがありません。",
5610
+ "storage_unavailable": "インポート時に画像ストレージが設定されていなかったため、何もダウンロードされていません。",
5611
+ "not_retained": "画像は保持されていません。ソースがフレームを生成しないか、フレームの保持が始まる前にインポートされた可能性があります。再インポートすると判別できます。"
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "実際",
5840
5858
  "reference": "リファレンス",
5859
+ "fromLinkedDesign": "· リンクされたデザインから",
5841
5860
  "actualAlt": "{view}(実際)",
5842
5861
  "referenceAlt": "{view}(リファレンス)",
5843
5862
  "replace": "置き換え",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "Nie udało się sprawdzić zmian"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "Niektórych ramek projektu nie udało się zapisać jako obrazy.",
4316
+ "failed": "Nie udało się pobrać obrazów projektu ze źródła.",
4317
+ "storage_unavailable": "Obrazy projektu nie zostały zapisane: to wdrożenie nie ma skonfigurowanego magazynu obrazów."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "Połącz źródło",
4316
4321
  "sourceFallback": "Źródło",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "Historia ({count} runda) | Historia ({count} rundy) | Historia ({count} rund)",
5594
5599
  "fixRequested": "Poproszono o poprawkę"
5600
+ },
5601
+ "design": {
5602
+ "summary": "1 klatka z połączonego projektu. | {count} klatki z połączonego projektu. | Klatek z połączonego projektu: {count}.",
5603
+ "dropped": "Jeszcze 1 nie jest tu pokazana. | Jeszcze {count} nie są tu pokazane. | Nie pokazano tu jeszcze {count}.",
5604
+ "gapDropped": "1 jej klatka nie jest tu pokazana. | {count} jej klatki nie są tu pokazane. | Nie pokazano tu {count} jej klatek.",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "zachowano tylko część jego klatek; odśwież dokument, aby spróbować ponownie.",
5608
+ "failed": "przy ostatnim imporcie nie udało się pobrać jego klatek; odśwież dokument, aby spróbować ponownie.",
5609
+ "none": "nie ma klatek do pokazania.",
5610
+ "storage_unavailable": "podczas importu nie skonfigurowano magazynu obrazów, więc nic nie pobrano.",
5611
+ "not_retained": "nie ma dla niego zapisanych obrazów. Jego źródło może nie generować klatek albo został zaimportowany, zanim klatki były zachowywane; ponowny import to rozstrzygnie."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "Rzeczywiste",
5840
5858
  "reference": "Wzorzec",
5859
+ "fromLinkedDesign": "· z połączonego projektu",
5841
5860
  "actualAlt": "{view} (rzeczywiste)",
5842
5861
  "referenceAlt": "{view} (wzorzec)",
5843
5862
  "replace": "Zamień",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "Değişiklikler denetlenemedi"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "Bazı tasarım çerçeveleri görsel olarak kaydedilemedi.",
4316
+ "failed": "Tasarım görselleri kaynaktan alınamadı.",
4317
+ "storage_unavailable": "Tasarım görselleri kaydedilmedi: bu kurulumda yapılandırılmış bir görsel deposu yok."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "Kaynak bağla",
4316
4321
  "sourceFallback": "Kaynak",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "Geçmiş (tur yok) | Geçmiş ({count} tur) | Geçmiş ({count} tur)",
5594
5599
  "fixRequested": "Düzeltme istendi"
5600
+ },
5601
+ "design": {
5602
+ "summary": "Bağlantılı tasarımdan hiç çerçeve gelmedi. | Bağlantılı tasarımdan {count} çerçeve. | Bağlantılı tasarımdan {count} çerçeve.",
5603
+ "dropped": "Gizlenen başka çerçeve yok. | {count} çerçeve daha burada gösterilmiyor. | {count} çerçeve daha burada gösterilmiyor.",
5604
+ "gapDropped": "Gizlenen çerçevesi yok. | Bu tasarımın {count} çerçevesi burada gösterilmiyor. | Bu tasarımın {count} çerçevesi burada gösterilmiyor.",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "çerçevelerinin yalnızca bir kısmı saklandı; yeniden denemek için belgeyi yenileyin.",
5608
+ "failed": "son içe aktarmada çerçeveleri indirilemedi; yeniden denemek için belgeyi yenileyin.",
5609
+ "none": "gösterilecek çerçevesi yok.",
5610
+ "storage_unavailable": "içe aktarıldığında görsel depolama yapılandırılmamıştı, bu yüzden hiçbir şey indirilmedi.",
5611
+ "not_retained": "bunun için saklanan görsel yok. Kaynağı çerçeve üretmiyor olabilir ya da çerçeveler saklanmaya başlamadan önce içe aktarılmış olabilir; yeniden içe aktarmak hangisi olduğunu gösterir."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "Gerçek",
5840
5858
  "reference": "Referans",
5859
+ "fromLinkedDesign": "· bağlantılı tasarımdan",
5841
5860
  "actualAlt": "{view} (gerçek)",
5842
5861
  "referenceAlt": "{view} (referans)",
5843
5862
  "replace": "Değiştir",
@@ -4311,6 +4311,11 @@
4311
4311
  },
4312
4312
  "refreshFailed": "Не вдалося перевірити зміни"
4313
4313
  },
4314
+ "renders": {
4315
+ "partial": "Деякі кадри дизайну не вдалося зберегти як зображення.",
4316
+ "failed": "Не вдалося отримати зображення дизайну з джерела.",
4317
+ "storage_unavailable": "Зображення дизайну не збережено: у цьому розгортанні не налаштовано сховище зображень."
4318
+ },
4314
4319
  "connect": {
4315
4320
  "title": "Підключити джерело",
4316
4321
  "sourceFallback": "Джерело",
@@ -5592,6 +5597,19 @@
5592
5597
  "history": {
5593
5598
  "heading": "Історія ({count} раунд) | Історія ({count} раунди) | Історія ({count} раундів)",
5594
5599
  "fixRequested": "Запитано виправлення"
5600
+ },
5601
+ "design": {
5602
+ "summary": "{count} кадр із пов'язаного дизайну. | {count} кадри із пов'язаного дизайну. | Кадрів із пов'язаного дизайну: {count}.",
5603
+ "dropped": "Ще {count} кадр не показано тут. | Ще {count} кадри не показано тут. | Ще {count} кадрів не показано тут.",
5604
+ "gapDropped": "{count} його кадр не показано тут. | {count} його кадри не показано тут. | {count} його кадрів не показано тут.",
5605
+ "gapLine": "{title}:",
5606
+ "gap": {
5607
+ "partial": "збережено лише частину його кадрів; оновіть документ, щоб спробувати ще раз.",
5608
+ "failed": "під час останнього імпорту не вдалося завантажити його кадри; оновіть документ, щоб повторити.",
5609
+ "none": "у ньому немає кадрів для показу.",
5610
+ "storage_unavailable": "під час імпорту сховище зображень не було налаштоване, тому нічого не завантажено.",
5611
+ "not_retained": "для нього не збережено зображень. Його джерело може не створювати кадрів, або він імпортований до того, як кадри почали зберігати; повторний імпорт це покаже."
5612
+ }
5595
5613
  }
5596
5614
  },
5597
5615
  "outcome": {
@@ -5838,6 +5856,7 @@
5838
5856
  },
5839
5857
  "actual": "Фактичне",
5840
5858
  "reference": "Еталон",
5859
+ "fromLinkedDesign": "· із пов'язаного дизайну",
5841
5860
  "actualAlt": "{view} (фактичне)",
5842
5861
  "referenceAlt": "{view} (еталон)",
5843
5862
  "replace": "Замінити",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.250.0",
3
+ "version": "0.252.0",
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.272.0"
43
+ "@cat-factory/contracts": "0.274.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",