@cat-factory/app 0.53.0 → 0.54.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/bootstrap/BootstrapModal.vue +81 -69
- package/app/components/environments/EnvironmentStatusPanel.vue +37 -14
- package/app/components/fragments/FragmentLibraryManager.vue +104 -69
- package/app/components/fragments/FragmentLibraryPanel.vue +2 -1
- package/app/components/kaizen/KaizenPanel.vue +36 -25
- package/app/components/kaizen/KaizenStepStatus.vue +13 -10
- package/app/components/media/ArtifactLightbox.vue +20 -14
- package/app/components/media/ImageCompare.vue +35 -22
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +27 -14
- package/app/components/recurring/RecurrenceEditor.vue +22 -15
- package/app/components/sandbox/SandboxPanel.vue +126 -59
- package/app/components/settings/InfrastructureBackendPicker.vue +304 -0
- package/app/components/settings/InfrastructureWindow.vue +6 -10
- package/app/components/settings/KubernetesRunnerForm.vue +30 -0
- package/app/components/settings/ProviderConnectionTab.vue +46 -85
- package/app/components/settings/ProviderManifestEditor.vue +19 -3
- package/i18n/locales/en.json +425 -13
- package/i18n/locales/es.json +403 -11
- package/i18n/locales/fr.json +403 -11
- package/i18n/locales/pl.json +403 -11
- package/i18n/locales/uk.json +403 -11
- package/package.json +2 -2
- package/app/components/settings/ExecutionBackendSelector.vue +0 -171
|
@@ -6,11 +6,39 @@
|
|
|
6
6
|
// and Fixtures (the graded inputs each run is scored against). Loaded on demand when the
|
|
7
7
|
// window opens; 503 (the deployment hasn't provisioned the Sandbox DB) shows a notice.
|
|
8
8
|
import { computed, ref, watch } from 'vue'
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
SandboxExperimentStatus,
|
|
11
|
+
SandboxFixtureKind,
|
|
12
|
+
SandboxGrade,
|
|
13
|
+
SandboxPromptVersion,
|
|
14
|
+
SandboxRun,
|
|
15
|
+
} from '~/types/sandbox'
|
|
10
16
|
|
|
11
17
|
const ui = useUiStore()
|
|
12
18
|
const store = useSandboxStore()
|
|
13
19
|
const toast = useToast()
|
|
20
|
+
const { t } = useI18n()
|
|
21
|
+
|
|
22
|
+
// Exhaustive enum→label maps of literal `t(...)` keys (keeps the typed-key drift guard
|
|
23
|
+
// live for these runtime-indexed status/kind/origin lookups).
|
|
24
|
+
const EXPERIMENT_STATUS_LABEL = computed<Record<SandboxExperimentStatus, string>>(() => ({
|
|
25
|
+
draft: t('sandbox.experimentStatus.draft'),
|
|
26
|
+
running: t('sandbox.experimentStatus.running'),
|
|
27
|
+
done: t('sandbox.experimentStatus.done'),
|
|
28
|
+
failed: t('sandbox.experimentStatus.failed'),
|
|
29
|
+
}))
|
|
30
|
+
const FIXTURE_KIND_LABEL = computed<Record<SandboxFixtureKind, string>>(() => ({
|
|
31
|
+
requirements: t('sandbox.fixtureKind.requirements'),
|
|
32
|
+
clarity: t('sandbox.fixtureKind.clarity'),
|
|
33
|
+
architecture: t('sandbox.fixtureKind.architecture'),
|
|
34
|
+
'code-review': t('sandbox.fixtureKind.code-review'),
|
|
35
|
+
'repo-feature': t('sandbox.fixtureKind.repo-feature'),
|
|
36
|
+
'repo-bug': t('sandbox.fixtureKind.repo-bug'),
|
|
37
|
+
}))
|
|
38
|
+
const FIXTURE_ORIGIN_LABEL = computed<Record<'builtin' | 'custom', string>>(() => ({
|
|
39
|
+
builtin: t('sandbox.fixtureOrigin.builtin'),
|
|
40
|
+
custom: t('sandbox.fixtureOrigin.custom'),
|
|
41
|
+
}))
|
|
14
42
|
|
|
15
43
|
const open = computed({
|
|
16
44
|
get: () => ui.sandboxOpen,
|
|
@@ -39,7 +67,7 @@ const selectedFixtureIds = ref<string[]>([])
|
|
|
39
67
|
const selectedJudgeModel = ref<string>('')
|
|
40
68
|
|
|
41
69
|
const judgeModelItems = computed(() => [
|
|
42
|
-
{ label: '
|
|
70
|
+
{ label: t('sandbox.deploymentDefault'), value: '' },
|
|
43
71
|
...store.selectableModels.map((m) => ({ label: m.label, value: m.id })),
|
|
44
72
|
])
|
|
45
73
|
|
|
@@ -82,7 +110,7 @@ async function createAndRun() {
|
|
|
82
110
|
if (!canRun.value) return
|
|
83
111
|
try {
|
|
84
112
|
const created = await store.createExperiment({
|
|
85
|
-
name: name.value.trim() ||
|
|
113
|
+
name: name.value.trim() || t('sandbox.defaultRunName', { kind: agentKind.value }),
|
|
86
114
|
agentKind: agentKind.value,
|
|
87
115
|
judgeModel: selectedJudgeModel.value || undefined,
|
|
88
116
|
matrix: {
|
|
@@ -92,12 +120,12 @@ async function createAndRun() {
|
|
|
92
120
|
},
|
|
93
121
|
})
|
|
94
122
|
name.value = ''
|
|
95
|
-
toast.add({ title: '
|
|
123
|
+
toast.add({ title: t('sandbox.toast.running'), icon: 'i-lucide-flask-conical', color: 'info' })
|
|
96
124
|
await store.launch(created.id)
|
|
97
|
-
toast.add({ title: '
|
|
125
|
+
toast.add({ title: t('sandbox.toast.complete'), icon: 'i-lucide-check', color: 'success' })
|
|
98
126
|
} catch (e) {
|
|
99
127
|
toast.add({
|
|
100
|
-
title: '
|
|
128
|
+
title: t('sandbox.toast.runFailed'),
|
|
101
129
|
description: e instanceof Error ? e.message : String(e),
|
|
102
130
|
icon: 'i-lucide-triangle-alert',
|
|
103
131
|
color: 'error',
|
|
@@ -149,11 +177,11 @@ async function saveVersion() {
|
|
|
149
177
|
savingPrompt.value = true
|
|
150
178
|
try {
|
|
151
179
|
await store.saveVersion(editing.value.id, editText.value)
|
|
152
|
-
toast.add({ title: '
|
|
180
|
+
toast.add({ title: t('sandbox.toast.versionSaved'), icon: 'i-lucide-check', color: 'success' })
|
|
153
181
|
editing.value = null
|
|
154
182
|
} catch (e) {
|
|
155
183
|
toast.add({
|
|
156
|
-
title: '
|
|
184
|
+
title: t('sandbox.toast.saveFailed'),
|
|
157
185
|
description: e instanceof Error ? e.message : String(e),
|
|
158
186
|
icon: 'i-lucide-triangle-alert',
|
|
159
187
|
color: 'error',
|
|
@@ -169,7 +197,7 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
169
197
|
if (editing.value?.id === prompt.id) editing.value = null
|
|
170
198
|
} catch (e) {
|
|
171
199
|
toast.add({
|
|
172
|
-
title: '
|
|
200
|
+
title: t('sandbox.toast.archiveFailed'),
|
|
173
201
|
description: e instanceof Error ? e.message : String(e),
|
|
174
202
|
icon: 'i-lucide-triangle-alert',
|
|
175
203
|
color: 'error',
|
|
@@ -181,8 +209,8 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
181
209
|
<template>
|
|
182
210
|
<UModal
|
|
183
211
|
v-model:open="open"
|
|
184
|
-
title="
|
|
185
|
-
description="
|
|
212
|
+
:title="t('sandbox.title')"
|
|
213
|
+
:description="t('sandbox.description')"
|
|
186
214
|
:ui="{ content: 'max-w-5xl' }"
|
|
187
215
|
>
|
|
188
216
|
<template #body>
|
|
@@ -194,21 +222,21 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
194
222
|
v-else-if="!store.available"
|
|
195
223
|
class="rounded-lg border border-slate-700 bg-slate-900/50 p-6 text-sm text-slate-300"
|
|
196
224
|
>
|
|
197
|
-
<p class="font-medium text-slate-200">
|
|
198
|
-
<p class="mt-1 text-slate-400">
|
|
199
|
-
|
|
200
|
-
<code>sandbox</code>
|
|
201
|
-
</
|
|
225
|
+
<p class="font-medium text-slate-200">{{ t('sandbox.unavailable.title') }}</p>
|
|
226
|
+
<i18n-t keypath="sandbox.unavailable.body" tag="p" class="mt-1 text-slate-400">
|
|
227
|
+
<template #db><code>SANDBOX_DB</code></template>
|
|
228
|
+
<template #schema><code>sandbox</code></template>
|
|
229
|
+
</i18n-t>
|
|
202
230
|
</div>
|
|
203
231
|
|
|
204
232
|
<div
|
|
205
233
|
v-else-if="store.error"
|
|
206
234
|
class="rounded-lg border border-rose-800 bg-rose-950/40 p-6 text-sm text-rose-200"
|
|
207
235
|
>
|
|
208
|
-
<p class="font-medium text-rose-100">
|
|
236
|
+
<p class="font-medium text-rose-100">{{ t('sandbox.error.title') }}</p>
|
|
209
237
|
<p class="mt-1 text-rose-300">{{ store.error }}</p>
|
|
210
238
|
<UButton class="mt-3" size="xs" color="neutral" variant="subtle" @click="store.load()">
|
|
211
|
-
|
|
239
|
+
{{ t('common.retry') }}
|
|
212
240
|
</UButton>
|
|
213
241
|
</div>
|
|
214
242
|
|
|
@@ -216,9 +244,17 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
216
244
|
<UTabs
|
|
217
245
|
v-model="tab"
|
|
218
246
|
:items="[
|
|
219
|
-
{
|
|
220
|
-
|
|
221
|
-
|
|
247
|
+
{
|
|
248
|
+
label: t('sandbox.tab.experiments'),
|
|
249
|
+
value: 'experiments',
|
|
250
|
+
icon: 'i-lucide-flask-conical',
|
|
251
|
+
},
|
|
252
|
+
{ label: t('sandbox.tab.prompts'), value: 'prompts', icon: 'i-lucide-file-text' },
|
|
253
|
+
{
|
|
254
|
+
label: t('sandbox.tab.fixtures'),
|
|
255
|
+
value: 'fixtures',
|
|
256
|
+
icon: 'i-lucide-clipboard-list',
|
|
257
|
+
},
|
|
222
258
|
]"
|
|
223
259
|
/>
|
|
224
260
|
|
|
@@ -227,10 +263,10 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
227
263
|
<!-- builder -->
|
|
228
264
|
<div class="space-y-3 rounded-lg border border-slate-700 bg-slate-900/40 p-3">
|
|
229
265
|
<p class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
230
|
-
|
|
266
|
+
{{ t('sandbox.builder.title') }}
|
|
231
267
|
</p>
|
|
232
268
|
|
|
233
|
-
<UFormField label="
|
|
269
|
+
<UFormField :label="t('sandbox.builder.agent')">
|
|
234
270
|
<USelect
|
|
235
271
|
v-model="agentKind"
|
|
236
272
|
:items="store.agentKinds.map((k) => ({ label: k.label, value: k.agentKind }))"
|
|
@@ -241,7 +277,7 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
241
277
|
|
|
242
278
|
<div>
|
|
243
279
|
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
244
|
-
|
|
280
|
+
{{ t('sandbox.builder.promptVersions') }}
|
|
245
281
|
</span>
|
|
246
282
|
<div class="max-h-28 space-y-1 overflow-auto pr-1">
|
|
247
283
|
<label
|
|
@@ -261,7 +297,11 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
261
297
|
variant="soft"
|
|
262
298
|
size="xs"
|
|
263
299
|
>
|
|
264
|
-
{{
|
|
300
|
+
{{
|
|
301
|
+
p.origin === 'baseline'
|
|
302
|
+
? t('sandbox.baseline')
|
|
303
|
+
: t('sandbox.versionLabel', { version: p.version })
|
|
304
|
+
}}
|
|
265
305
|
</UBadge>
|
|
266
306
|
</label>
|
|
267
307
|
</div>
|
|
@@ -269,7 +309,7 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
269
309
|
|
|
270
310
|
<div>
|
|
271
311
|
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
272
|
-
|
|
312
|
+
{{ t('sandbox.builder.models') }}
|
|
273
313
|
</span>
|
|
274
314
|
<div class="max-h-28 space-y-1 overflow-auto pr-1">
|
|
275
315
|
<label
|
|
@@ -286,14 +326,14 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
286
326
|
<span class="truncate">{{ m.label }}</span>
|
|
287
327
|
</label>
|
|
288
328
|
<p v-if="!store.selectableModels.length" class="text-xs text-slate-500">
|
|
289
|
-
|
|
329
|
+
{{ t('sandbox.builder.noModels') }}
|
|
290
330
|
</p>
|
|
291
331
|
</div>
|
|
292
332
|
</div>
|
|
293
333
|
|
|
294
334
|
<div>
|
|
295
335
|
<span class="mb-1 block text-[10px] uppercase tracking-wide text-slate-500">
|
|
296
|
-
|
|
336
|
+
{{ t('sandbox.builder.fixtures') }}
|
|
297
337
|
</span>
|
|
298
338
|
<div class="max-h-28 space-y-1 overflow-auto pr-1">
|
|
299
339
|
<label
|
|
@@ -310,24 +350,30 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
310
350
|
<span class="truncate">{{ f.name }}</span>
|
|
311
351
|
</label>
|
|
312
352
|
<p v-if="!kindFixtures.length" class="text-xs text-slate-500">
|
|
313
|
-
|
|
353
|
+
{{ t('sandbox.builder.noFixtures') }}
|
|
314
354
|
</p>
|
|
315
355
|
</div>
|
|
316
356
|
</div>
|
|
317
357
|
|
|
318
|
-
<UFormField
|
|
358
|
+
<UFormField
|
|
359
|
+
:label="t('sandbox.builder.judgeModel')"
|
|
360
|
+
:hint="t('sandbox.builder.judgeModelHint')"
|
|
361
|
+
>
|
|
319
362
|
<USelect v-model="selectedJudgeModel" :items="judgeModelItems" />
|
|
320
363
|
</UFormField>
|
|
321
364
|
|
|
322
|
-
<UFormField label="
|
|
323
|
-
<UInput
|
|
365
|
+
<UFormField :label="t('sandbox.builder.nameLabel')">
|
|
366
|
+
<UInput
|
|
367
|
+
v-model="name"
|
|
368
|
+
:placeholder="t('sandbox.defaultRunName', { kind: agentKind })"
|
|
369
|
+
/>
|
|
324
370
|
</UFormField>
|
|
325
371
|
|
|
326
372
|
<div class="flex items-center justify-between">
|
|
327
373
|
<span class="text-xs text-slate-500">
|
|
328
|
-
{{ cellCount
|
|
374
|
+
{{ t('sandbox.builder.cellCount', { count: cellCount }, cellCount) }}
|
|
329
375
|
<span v-if="cellCount > store.maxCells" class="text-rose-400">
|
|
330
|
-
(
|
|
376
|
+
{{ t('sandbox.builder.maxCells', { max: store.maxCells }) }}
|
|
331
377
|
</span>
|
|
332
378
|
</span>
|
|
333
379
|
<UButton
|
|
@@ -338,7 +384,7 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
338
384
|
:disabled="!canRun"
|
|
339
385
|
@click="createAndRun()"
|
|
340
386
|
>
|
|
341
|
-
|
|
387
|
+
{{ t('sandbox.builder.run') }}
|
|
342
388
|
</UButton>
|
|
343
389
|
</div>
|
|
344
390
|
</div>
|
|
@@ -350,17 +396,19 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
350
396
|
<p class="text-sm font-medium text-slate-200">
|
|
351
397
|
{{ store.detail.experiment.name }}
|
|
352
398
|
</p>
|
|
353
|
-
<UBadge variant="soft" size="xs">{{
|
|
399
|
+
<UBadge variant="soft" size="xs">{{
|
|
400
|
+
EXPERIMENT_STATUS_LABEL[store.detail.experiment.status]
|
|
401
|
+
}}</UBadge>
|
|
354
402
|
</div>
|
|
355
403
|
<div class="overflow-auto">
|
|
356
404
|
<table class="w-full text-left text-xs">
|
|
357
405
|
<thead class="text-slate-500">
|
|
358
406
|
<tr>
|
|
359
|
-
<th class="py-1 pr-2 font-medium">
|
|
360
|
-
<th class="py-1 pr-2 font-medium">
|
|
361
|
-
<th class="py-1 pr-2 font-medium">
|
|
362
|
-
<th class="py-1 pr-2 font-medium">
|
|
363
|
-
<th class="py-1 font-medium">
|
|
407
|
+
<th class="py-1 pr-2 font-medium">{{ t('sandbox.results.col.prompt') }}</th>
|
|
408
|
+
<th class="py-1 pr-2 font-medium">{{ t('sandbox.results.col.model') }}</th>
|
|
409
|
+
<th class="py-1 pr-2 font-medium">{{ t('sandbox.results.col.fixture') }}</th>
|
|
410
|
+
<th class="py-1 pr-2 font-medium">{{ t('sandbox.results.col.score') }}</th>
|
|
411
|
+
<th class="py-1 font-medium">{{ t('sandbox.results.col.objective') }}</th>
|
|
364
412
|
</tr>
|
|
365
413
|
</thead>
|
|
366
414
|
<tbody>
|
|
@@ -383,9 +431,9 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
383
431
|
>
|
|
384
432
|
{{ grade.weightedTotal.toFixed(2) }}
|
|
385
433
|
</span>
|
|
386
|
-
<span v-else-if="run.status === 'failed'" class="text-rose-400"
|
|
387
|
-
|
|
388
|
-
>
|
|
434
|
+
<span v-else-if="run.status === 'failed'" class="text-rose-400">{{
|
|
435
|
+
t('sandbox.results.failed')
|
|
436
|
+
}}</span>
|
|
389
437
|
<span v-else class="text-slate-600">—</span>
|
|
390
438
|
</td>
|
|
391
439
|
<td class="py-1">
|
|
@@ -429,7 +477,9 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
429
477
|
</div>
|
|
430
478
|
</div>
|
|
431
479
|
|
|
432
|
-
<p class="text-[11px] uppercase tracking-wide text-slate-500">
|
|
480
|
+
<p class="text-[11px] uppercase tracking-wide text-slate-500">
|
|
481
|
+
{{ t('sandbox.results.past') }}
|
|
482
|
+
</p>
|
|
433
483
|
<div class="max-h-56 space-y-1 overflow-auto">
|
|
434
484
|
<button
|
|
435
485
|
v-for="x in store.experiments"
|
|
@@ -438,10 +488,10 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
438
488
|
@click="store.openExperiment(x.id)"
|
|
439
489
|
>
|
|
440
490
|
<span class="truncate text-slate-300">{{ x.name }}</span>
|
|
441
|
-
<UBadge variant="soft" size="xs">{{ x.status }}</UBadge>
|
|
491
|
+
<UBadge variant="soft" size="xs">{{ EXPERIMENT_STATUS_LABEL[x.status] }}</UBadge>
|
|
442
492
|
</button>
|
|
443
493
|
<p v-if="!store.experiments.length" class="text-xs text-slate-500">
|
|
444
|
-
|
|
494
|
+
{{ t('sandbox.results.empty') }}
|
|
445
495
|
</p>
|
|
446
496
|
</div>
|
|
447
497
|
</div>
|
|
@@ -463,7 +513,11 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
463
513
|
variant="soft"
|
|
464
514
|
size="xs"
|
|
465
515
|
>
|
|
466
|
-
{{
|
|
516
|
+
{{
|
|
517
|
+
p.origin === 'baseline'
|
|
518
|
+
? t('sandbox.baseline')
|
|
519
|
+
: t('sandbox.versionLabel', { version: p.version })
|
|
520
|
+
}}
|
|
467
521
|
</UBadge>
|
|
468
522
|
</div>
|
|
469
523
|
<span class="text-[11px] text-slate-500">{{ p.agentKind }}</span>
|
|
@@ -474,7 +528,11 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
474
528
|
color="neutral"
|
|
475
529
|
variant="ghost"
|
|
476
530
|
size="xs"
|
|
477
|
-
:title="
|
|
531
|
+
:title="
|
|
532
|
+
p.origin === 'baseline'
|
|
533
|
+
? t('sandbox.prompts.forkTitle')
|
|
534
|
+
: t('sandbox.prompts.editTitle')
|
|
535
|
+
"
|
|
478
536
|
@click="edit(p)"
|
|
479
537
|
/>
|
|
480
538
|
<UButton
|
|
@@ -494,12 +552,16 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
494
552
|
class="space-y-2 rounded-lg border border-slate-700 bg-slate-900/40 p-3"
|
|
495
553
|
>
|
|
496
554
|
<p class="text-[11px] uppercase tracking-wide text-slate-500">
|
|
497
|
-
{{
|
|
555
|
+
{{
|
|
556
|
+
editing.origin === 'baseline'
|
|
557
|
+
? t('sandbox.prompts.forkOf', { name: editing.name })
|
|
558
|
+
: t('sandbox.prompts.newVersionOf', { name: editing.name })
|
|
559
|
+
}}
|
|
498
560
|
</p>
|
|
499
561
|
<UTextarea v-model="editText" :rows="16" class="w-full font-mono text-xs" autoresize />
|
|
500
562
|
<div class="flex justify-end gap-2">
|
|
501
563
|
<UButton color="neutral" variant="ghost" size="sm" @click="editing = null">
|
|
502
|
-
|
|
564
|
+
{{ t('common.cancel') }}
|
|
503
565
|
</UButton>
|
|
504
566
|
<UButton
|
|
505
567
|
color="primary"
|
|
@@ -509,13 +571,12 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
509
571
|
:disabled="!editText.trim()"
|
|
510
572
|
@click="saveVersion()"
|
|
511
573
|
>
|
|
512
|
-
|
|
574
|
+
{{ t('sandbox.prompts.saveVersion') }}
|
|
513
575
|
</UButton>
|
|
514
576
|
</div>
|
|
515
577
|
</div>
|
|
516
578
|
<p v-else class="self-start text-xs text-slate-500">
|
|
517
|
-
|
|
518
|
-
immutable version you can put under test.
|
|
579
|
+
{{ t('sandbox.prompts.hint') }}
|
|
519
580
|
</p>
|
|
520
581
|
</div>
|
|
521
582
|
|
|
@@ -529,23 +590,29 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
529
590
|
<div class="flex items-center justify-between">
|
|
530
591
|
<span class="text-slate-200">{{ f.name }}</span>
|
|
531
592
|
<div class="flex items-center gap-1.5">
|
|
532
|
-
<UBadge variant="soft" size="xs">{{ f.kind }}</UBadge>
|
|
593
|
+
<UBadge variant="soft" size="xs">{{ FIXTURE_KIND_LABEL[f.kind] }}</UBadge>
|
|
533
594
|
<UBadge
|
|
534
595
|
:color="f.origin === 'builtin' ? 'neutral' : 'primary'"
|
|
535
596
|
variant="soft"
|
|
536
597
|
size="xs"
|
|
537
598
|
>
|
|
538
|
-
{{ f.origin }}
|
|
599
|
+
{{ FIXTURE_ORIGIN_LABEL[f.origin] }}
|
|
539
600
|
</UBadge>
|
|
540
601
|
</div>
|
|
541
602
|
</div>
|
|
542
603
|
<p v-if="f.objective?.kind === 'findings'" class="mt-0.5 text-[11px] text-slate-500">
|
|
543
|
-
{{
|
|
544
|
-
|
|
604
|
+
{{
|
|
605
|
+
t(
|
|
606
|
+
'sandbox.fixtures.expectations',
|
|
607
|
+
{ count: f.objective.expectations.length },
|
|
608
|
+
f.objective.expectations.length,
|
|
609
|
+
)
|
|
545
610
|
}}
|
|
546
611
|
</p>
|
|
547
612
|
</div>
|
|
548
|
-
<p v-if="!store.fixtures.length" class="text-xs text-slate-500">
|
|
613
|
+
<p v-if="!store.fixtures.length" class="text-xs text-slate-500">
|
|
614
|
+
{{ t('sandbox.fixtures.empty') }}
|
|
615
|
+
</p>
|
|
549
616
|
</div>
|
|
550
617
|
</div>
|
|
551
618
|
</template>
|