@cat-factory/app 0.47.8 → 0.47.10
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/brainstorm/BrainstormWindow.vue +97 -59
- package/app/components/clarity/ClarityReviewWindow.vue +85 -59
- package/app/components/consensus/ConsensusSessionWindow.vue +72 -34
- package/app/components/focus/BlockFocusView.vue +14 -10
- package/app/components/followUp/FollowUpWindow.vue +51 -26
- package/app/components/humanTest/HumanTestWindow.vue +70 -35
- package/app/components/panels/AgentStepDetail.vue +1 -0
- package/app/components/panels/InspectorPanel.vue +1 -0
- package/app/components/requirements/RequirementsReviewWindow.vue +131 -82
- package/app/components/spec/ServiceSpecWindow.vue +54 -28
- package/app/components/testing/TestReportWindow.vue +82 -39
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +49 -32
- package/app/pages/index.vue +1 -0
- package/i18n/locales/en.json +580 -0
- package/i18n/locales/es.json +547 -0
- package/i18n/locales/fr.json +547 -0
- package/i18n/locales/pl.json +547 -0
- package/i18n/locales/uk.json +547 -0
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// agent step and the spec-writer consume.
|
|
10
10
|
import { parseOutputOutline } from '~/utils/agentOutput'
|
|
11
11
|
import StepRestartControl from '~/components/panels/StepRestartControl.vue'
|
|
12
|
+
import IterationCapPrompt from '~/components/pipeline/IterationCapPrompt.vue'
|
|
12
13
|
import type {
|
|
13
14
|
RequirementRecommendation,
|
|
14
15
|
RequirementReview,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
const board = useBoardStore()
|
|
22
23
|
const requirements = useRequirementsStore()
|
|
23
24
|
const toast = useToast()
|
|
25
|
+
const { t } = useI18n()
|
|
24
26
|
|
|
25
27
|
// Draft replies, keyed by item id, so editing one item doesn't disturb others.
|
|
26
28
|
const drafts = ref<Record<string, string>>({})
|
|
@@ -125,6 +127,28 @@ const STATUS_COLOR = {
|
|
|
125
127
|
recommend_requested: 'primary',
|
|
126
128
|
} as const satisfies Record<ReviewItemStatus, string>
|
|
127
129
|
|
|
130
|
+
// Exhaustive enum→label maps of literal keys, so the typed-key drift guard sees each key
|
|
131
|
+
// (vs a runtime-built `requirements.severity.${value}`).
|
|
132
|
+
const SEVERITY_LABELS = computed<Record<ReviewItemSeverity, string>>(() => ({
|
|
133
|
+
high: t('requirements.severity.high'),
|
|
134
|
+
medium: t('requirements.severity.medium'),
|
|
135
|
+
low: t('requirements.severity.low'),
|
|
136
|
+
}))
|
|
137
|
+
const CATEGORY_LABELS = computed<Record<ReviewItemCategory, string>>(() => ({
|
|
138
|
+
gap: t('requirements.category.gap'),
|
|
139
|
+
clarification: t('requirements.category.clarification'),
|
|
140
|
+
assumption: t('requirements.category.assumption'),
|
|
141
|
+
risk: t('requirements.category.risk'),
|
|
142
|
+
question: t('requirements.category.question'),
|
|
143
|
+
}))
|
|
144
|
+
const STATUS_LABELS = computed<Record<ReviewItemStatus, string>>(() => ({
|
|
145
|
+
open: t('requirements.itemStatus.open'),
|
|
146
|
+
answered: t('requirements.itemStatus.answered'),
|
|
147
|
+
resolved: t('requirements.itemStatus.resolved'),
|
|
148
|
+
dismissed: t('requirements.itemStatus.dismissed'),
|
|
149
|
+
recommend_requested: t('requirements.itemStatus.recommend_requested'),
|
|
150
|
+
}))
|
|
151
|
+
|
|
128
152
|
function notifyError(title: string, e: unknown) {
|
|
129
153
|
toast.add({
|
|
130
154
|
title,
|
|
@@ -145,7 +169,7 @@ async function persistDraft(item: RequirementReviewItem) {
|
|
|
145
169
|
try {
|
|
146
170
|
await requirements.reply(review.value, item.id, text)
|
|
147
171
|
} catch (e) {
|
|
148
|
-
notifyError('
|
|
172
|
+
notifyError(t('requirements.errors.saveAnswer'), e)
|
|
149
173
|
}
|
|
150
174
|
}
|
|
151
175
|
|
|
@@ -206,7 +230,7 @@ async function setStatus(item: RequirementReviewItem, itemStatus: ReviewItemStat
|
|
|
206
230
|
try {
|
|
207
231
|
await requirements.setItemStatus(review.value, item.id, itemStatus)
|
|
208
232
|
} catch (e) {
|
|
209
|
-
notifyError('
|
|
233
|
+
notifyError(t('requirements.errors.updateFinding'), e)
|
|
210
234
|
}
|
|
211
235
|
}
|
|
212
236
|
|
|
@@ -254,7 +278,6 @@ async function requestRecommendations() {
|
|
|
254
278
|
const updated = await requirements.requestRecommendations(blockId.value, ids)
|
|
255
279
|
markedForRecommend.value = new Set()
|
|
256
280
|
const n = ids.length
|
|
257
|
-
const plural = n === 1 ? '' : 's'
|
|
258
281
|
// On a parked run the request returns at once with `pending` placeholders the durable driver
|
|
259
282
|
// fills in the background; off-path (no active pipeline) there is no driver, so the Writer
|
|
260
283
|
// ran inline and the recommendations are already settled. Tell the human which actually
|
|
@@ -263,18 +286,17 @@ async function requestRecommendations() {
|
|
|
263
286
|
toast.add(
|
|
264
287
|
stillGenerating
|
|
265
288
|
? {
|
|
266
|
-
title:
|
|
267
|
-
description:
|
|
268
|
-
"Your answers are saved — close this if you like; we'll notify you when they're ready.",
|
|
289
|
+
title: t('requirements.toast.preparingRecommendations', { count: n }, n),
|
|
290
|
+
description: t('requirements.toast.preparingRecommendationsDescription'),
|
|
269
291
|
icon: 'i-lucide-sparkles',
|
|
270
292
|
}
|
|
271
293
|
: {
|
|
272
|
-
title:
|
|
294
|
+
title: t('requirements.toast.recommendationsReady', { count: n }, n),
|
|
273
295
|
icon: 'i-lucide-sparkles',
|
|
274
296
|
},
|
|
275
297
|
)
|
|
276
298
|
} catch (e) {
|
|
277
|
-
notifyError('
|
|
299
|
+
notifyError(t('requirements.errors.requestRecommendations'), e)
|
|
278
300
|
}
|
|
279
301
|
}
|
|
280
302
|
|
|
@@ -283,7 +305,7 @@ async function acceptRecommendation(rec: RequirementRecommendation) {
|
|
|
283
305
|
try {
|
|
284
306
|
await requirements.acceptRecommendation(review.value, rec.id)
|
|
285
307
|
} catch (e) {
|
|
286
|
-
notifyError('
|
|
308
|
+
notifyError(t('requirements.errors.acceptRecommendation'), e)
|
|
287
309
|
}
|
|
288
310
|
}
|
|
289
311
|
|
|
@@ -292,7 +314,7 @@ async function rejectRecommendation(rec: RequirementRecommendation) {
|
|
|
292
314
|
try {
|
|
293
315
|
await requirements.rejectRecommendation(review.value, rec.id)
|
|
294
316
|
} catch (e) {
|
|
295
|
-
notifyError('
|
|
317
|
+
notifyError(t('requirements.errors.rejectRecommendation'), e)
|
|
296
318
|
}
|
|
297
319
|
}
|
|
298
320
|
|
|
@@ -304,7 +326,7 @@ async function reRequestRecommendation(rec: RequirementRecommendation) {
|
|
|
304
326
|
await requirements.reRequestRecommendation(review.value, rec.id, note)
|
|
305
327
|
reRequestNotes.value = { ...reRequestNotes.value, [rec.id]: '' }
|
|
306
328
|
} catch (e) {
|
|
307
|
-
notifyError('
|
|
329
|
+
notifyError(t('requirements.errors.reRequestRecommendation'), e)
|
|
308
330
|
}
|
|
309
331
|
}
|
|
310
332
|
|
|
@@ -314,7 +336,7 @@ async function incorporate(feedback?: string) {
|
|
|
314
336
|
await flushDrafts()
|
|
315
337
|
await requirements.incorporate(review.value, feedback)
|
|
316
338
|
} catch (e) {
|
|
317
|
-
notifyError('
|
|
339
|
+
notifyError(t('requirements.errors.incorporate'), e)
|
|
318
340
|
return
|
|
319
341
|
}
|
|
320
342
|
redoComment.value = ''
|
|
@@ -322,8 +344,8 @@ async function incorporate(feedback?: string) {
|
|
|
322
344
|
// The fold + re-review now run in the durable driver. Hand the user back to the board;
|
|
323
345
|
// a notification calls them back only if the re-review needs more input.
|
|
324
346
|
toast.add({
|
|
325
|
-
title: '
|
|
326
|
-
description:
|
|
347
|
+
title: t('requirements.toast.incorporating'),
|
|
348
|
+
description: t('requirements.toast.incorporatingDescription'),
|
|
327
349
|
icon: 'i-lucide-wand-sparkles',
|
|
328
350
|
})
|
|
329
351
|
close()
|
|
@@ -333,17 +355,18 @@ async function reReview() {
|
|
|
333
355
|
if (!blockId.value) return
|
|
334
356
|
try {
|
|
335
357
|
const updated = await requirements.reReview(blockId.value)
|
|
358
|
+
const newFindings = requirements.openCount(updated)
|
|
336
359
|
toast.add({
|
|
337
360
|
title:
|
|
338
361
|
updated.status === 'incorporated'
|
|
339
|
-
? '
|
|
362
|
+
? t('requirements.toast.reviewerSatisfied')
|
|
340
363
|
: updated.status === 'exceeded'
|
|
341
|
-
? '
|
|
342
|
-
:
|
|
364
|
+
? t('requirements.toast.iterationLimitReached')
|
|
365
|
+
: t('requirements.toast.newFindings', { count: newFindings }, newFindings),
|
|
343
366
|
icon: 'i-lucide-sparkles',
|
|
344
367
|
})
|
|
345
368
|
} catch (e) {
|
|
346
|
-
notifyError('
|
|
369
|
+
notifyError(t('requirements.errors.reReview'), e)
|
|
347
370
|
}
|
|
348
371
|
}
|
|
349
372
|
|
|
@@ -353,9 +376,9 @@ async function proceed() {
|
|
|
353
376
|
try {
|
|
354
377
|
await flushDrafts()
|
|
355
378
|
await requirements.proceed(blockId.value)
|
|
356
|
-
toast.add({ title: '
|
|
379
|
+
toast.add({ title: t('requirements.toast.proceeding'), icon: 'i-lucide-arrow-right' })
|
|
357
380
|
} catch (e) {
|
|
358
|
-
notifyError('
|
|
381
|
+
notifyError(t('requirements.errors.proceed'), e)
|
|
359
382
|
} finally {
|
|
360
383
|
acting.value = false
|
|
361
384
|
}
|
|
@@ -367,15 +390,15 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
367
390
|
try {
|
|
368
391
|
await requirements.resolveExceeded(blockId.value, choice)
|
|
369
392
|
if (choice === 'stop-reset') {
|
|
370
|
-
toast.add({ title: '
|
|
393
|
+
toast.add({ title: t('requirements.toast.taskReset'), icon: 'i-lucide-undo' })
|
|
371
394
|
close()
|
|
372
395
|
} else if (choice === 'proceed') {
|
|
373
|
-
toast.add({ title: '
|
|
396
|
+
toast.add({ title: t('requirements.toast.proceeding'), icon: 'i-lucide-arrow-right' })
|
|
374
397
|
} else {
|
|
375
|
-
toast.add({ title: '
|
|
398
|
+
toast.add({ title: t('requirements.toast.extraRoundGranted'), icon: 'i-lucide-rotate-cw' })
|
|
376
399
|
}
|
|
377
400
|
} catch (e) {
|
|
378
|
-
notifyError('
|
|
401
|
+
notifyError(t('requirements.errors.resolveReview'), e)
|
|
379
402
|
} finally {
|
|
380
403
|
acting.value = false
|
|
381
404
|
}
|
|
@@ -400,12 +423,14 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
400
423
|
<UIcon name="i-lucide-clipboard-check" class="h-5 w-5 text-indigo-300" />
|
|
401
424
|
</div>
|
|
402
425
|
<div class="min-w-0">
|
|
403
|
-
<h1 class="truncate text-base font-semibold text-white">
|
|
426
|
+
<h1 class="truncate text-base font-semibold text-white">
|
|
427
|
+
{{ t('requirements.title') }}
|
|
428
|
+
</h1>
|
|
404
429
|
<p v-if="block" class="truncate text-xs text-slate-500">{{ block.title }}</p>
|
|
405
430
|
</div>
|
|
406
431
|
<div class="ml-auto flex items-center gap-1.5">
|
|
407
432
|
<UBadge v-if="review" color="neutral" variant="subtle" size="sm">
|
|
408
|
-
|
|
433
|
+
{{ t('requirements.iteration', { current: iteration, max: maxIterations }) }}
|
|
409
434
|
</UBadge>
|
|
410
435
|
<StepRestartControl
|
|
411
436
|
:instance-id="instanceId"
|
|
@@ -419,13 +444,20 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
419
444
|
<div class="flex min-h-0 flex-1">
|
|
420
445
|
<!-- main column -->
|
|
421
446
|
<div class="min-w-0 flex-1 overflow-y-auto px-6 py-5">
|
|
422
|
-
<
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
447
|
+
<i18n-t
|
|
448
|
+
keypath="requirements.intro"
|
|
449
|
+
tag="p"
|
|
450
|
+
class="mb-4 text-sm text-slate-400"
|
|
451
|
+
scope="global"
|
|
452
|
+
>
|
|
453
|
+
<template #level>{{ block?.level ?? t('requirements.levelFallback') }}</template>
|
|
454
|
+
<template #answer
|
|
455
|
+
><span class="text-slate-300">{{ t('requirements.answerVerb') }}</span></template
|
|
456
|
+
>
|
|
457
|
+
<template #dismiss
|
|
458
|
+
><span class="text-slate-300">{{ t('requirements.dismissVerb') }}</span></template
|
|
459
|
+
>
|
|
460
|
+
</i18n-t>
|
|
429
461
|
|
|
430
462
|
<!-- empty state — the reviewer runs automatically as the first pipeline
|
|
431
463
|
gate step, so there's nothing to do here until then -->
|
|
@@ -433,8 +465,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
433
465
|
v-if="!review && !busy && !loading"
|
|
434
466
|
class="rounded-lg border border-dashed border-slate-700 p-8 text-center text-sm text-slate-500"
|
|
435
467
|
>
|
|
436
|
-
|
|
437
|
-
pipeline starts.
|
|
468
|
+
{{ t('requirements.empty') }}
|
|
438
469
|
</div>
|
|
439
470
|
|
|
440
471
|
<!-- working state (initial fetch on open, or a reviewer pass running) -->
|
|
@@ -443,7 +474,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
443
474
|
class="flex items-center justify-center gap-2 p-8 text-sm text-slate-400"
|
|
444
475
|
>
|
|
445
476
|
<UIcon name="i-lucide-loader-circle" class="h-4 w-4 animate-spin" />
|
|
446
|
-
{{ loading && !busy ? '
|
|
477
|
+
{{ loading && !busy ? t('requirements.loadingReview') : t('requirements.reviewing') }}
|
|
447
478
|
</div>
|
|
448
479
|
|
|
449
480
|
<template v-else-if="review">
|
|
@@ -453,16 +484,15 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
453
484
|
class="mb-4 flex items-center gap-2 rounded-lg border border-emerald-900/60 bg-emerald-950/30 p-4 text-sm text-emerald-300"
|
|
454
485
|
>
|
|
455
486
|
<UIcon name="i-lucide-circle-check" class="h-5 w-5 shrink-0" />
|
|
456
|
-
|
|
457
|
-
uses.
|
|
487
|
+
{{ t('requirements.settled') }}
|
|
458
488
|
</div>
|
|
459
489
|
|
|
460
490
|
<!-- iteration cap hit -->
|
|
461
491
|
<IterationCapPrompt
|
|
462
492
|
v-else-if="exceeded"
|
|
463
493
|
class="mb-4"
|
|
464
|
-
:heading="
|
|
465
|
-
detail="
|
|
494
|
+
:heading="t('requirements.exceeded.heading', { max: maxIterations })"
|
|
495
|
+
:detail="t('requirements.exceeded.detail')"
|
|
466
496
|
:loading="acting"
|
|
467
497
|
@resolve="resolveExceeded"
|
|
468
498
|
/>
|
|
@@ -475,12 +505,10 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
475
505
|
>
|
|
476
506
|
<UIcon name="i-lucide-loader-circle" class="h-5 w-5 shrink-0 animate-spin" />
|
|
477
507
|
<span v-if="incorporating">
|
|
478
|
-
|
|
479
|
-
we’ll notify you only if more input is needed.
|
|
508
|
+
{{ t('requirements.working.incorporating') }}
|
|
480
509
|
</span>
|
|
481
510
|
<span v-else>
|
|
482
|
-
|
|
483
|
-
if more input is needed.
|
|
511
|
+
{{ t('requirements.working.reReviewing') }}
|
|
484
512
|
</span>
|
|
485
513
|
</div>
|
|
486
514
|
|
|
@@ -501,10 +529,10 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
501
529
|
<div class="flex flex-wrap items-center gap-1.5">
|
|
502
530
|
<span class="text-sm font-medium text-white">{{ item.title }}</span>
|
|
503
531
|
<UBadge size="xs" variant="subtle" :color="SEVERITY_COLOR[item.severity]">
|
|
504
|
-
{{ item.severity }}
|
|
532
|
+
{{ SEVERITY_LABELS[item.severity] }}
|
|
505
533
|
</UBadge>
|
|
506
534
|
<UBadge size="xs" variant="outline" color="neutral">
|
|
507
|
-
{{ item.category }}
|
|
535
|
+
{{ CATEGORY_LABELS[item.category] }}
|
|
508
536
|
</UBadge>
|
|
509
537
|
<UBadge
|
|
510
538
|
size="xs"
|
|
@@ -512,7 +540,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
512
540
|
:color="STATUS_COLOR[item.status]"
|
|
513
541
|
class="ml-auto"
|
|
514
542
|
>
|
|
515
|
-
{{ item.status }}
|
|
543
|
+
{{ STATUS_LABELS[item.status] }}
|
|
516
544
|
</UBadge>
|
|
517
545
|
</div>
|
|
518
546
|
<p class="mt-1 whitespace-pre-line text-sm text-slate-400">
|
|
@@ -526,7 +554,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
526
554
|
class="mt-2 rounded-md border-l-2 border-slate-700 bg-slate-950/40 px-3 py-1.5 text-sm text-slate-300"
|
|
527
555
|
>
|
|
528
556
|
<span class="text-[10px] uppercase tracking-wide text-slate-500">
|
|
529
|
-
|
|
557
|
+
{{ t('requirements.answerLabel') }}
|
|
530
558
|
</span>
|
|
531
559
|
<p class="whitespace-pre-line">{{ item.reply }}</p>
|
|
532
560
|
</div>
|
|
@@ -541,7 +569,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
541
569
|
autoresize
|
|
542
570
|
size="sm"
|
|
543
571
|
class="mt-2 w-full"
|
|
544
|
-
placeholder="
|
|
572
|
+
:placeholder="t('requirements.answerPlaceholder')"
|
|
545
573
|
:disabled="frozen"
|
|
546
574
|
@blur="persistDraft(item)"
|
|
547
575
|
/>
|
|
@@ -554,7 +582,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
554
582
|
:disabled="frozen"
|
|
555
583
|
@click="setStatus(item, 'dismissed')"
|
|
556
584
|
>
|
|
557
|
-
|
|
585
|
+
{{ t('requirements.dismissIrrelevant') }}
|
|
558
586
|
</UButton>
|
|
559
587
|
<UButton
|
|
560
588
|
:color="isMarkedForRecommend(item) ? 'primary' : 'neutral'"
|
|
@@ -566,8 +594,8 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
566
594
|
>
|
|
567
595
|
{{
|
|
568
596
|
isMarkedForRecommend(item)
|
|
569
|
-
? '
|
|
570
|
-
: '
|
|
597
|
+
? t('requirements.markedForRecommendation')
|
|
598
|
+
: t('requirements.recommendSomething')
|
|
571
599
|
}}
|
|
572
600
|
</UButton>
|
|
573
601
|
</div>
|
|
@@ -579,7 +607,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
579
607
|
class="mt-2 flex items-center gap-1.5 text-xs text-indigo-300"
|
|
580
608
|
>
|
|
581
609
|
<UIcon name="i-lucide-wand-2" class="h-3.5 w-3.5" />
|
|
582
|
-
|
|
610
|
+
{{ t('requirements.recommendationRequested') }}
|
|
583
611
|
</div>
|
|
584
612
|
|
|
585
613
|
<!-- reopen a dismissed finding -->
|
|
@@ -592,7 +620,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
592
620
|
:disabled="frozen"
|
|
593
621
|
@click="setStatus(item, 'open')"
|
|
594
622
|
>
|
|
595
|
-
|
|
623
|
+
{{ t('requirements.reopen') }}
|
|
596
624
|
</UButton>
|
|
597
625
|
</div>
|
|
598
626
|
</div>
|
|
@@ -608,13 +636,20 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
608
636
|
>
|
|
609
637
|
<div class="mb-3 flex items-center gap-2 text-[11px] text-indigo-300">
|
|
610
638
|
<UIcon name="i-lucide-wand-2" class="h-3.5 w-3.5" />
|
|
611
|
-
<span class="font-semibold uppercase tracking-wide">
|
|
639
|
+
<span class="font-semibold uppercase tracking-wide">{{
|
|
640
|
+
t('requirements.recommendedAnswers')
|
|
641
|
+
}}</span>
|
|
612
642
|
<span
|
|
613
643
|
v-if="recommendationProgress"
|
|
614
644
|
class="ml-auto flex items-center gap-1.5 normal-case text-indigo-300/80"
|
|
615
645
|
>
|
|
616
646
|
<UIcon name="i-lucide-loader-circle" class="h-3.5 w-3.5 animate-spin" />
|
|
617
|
-
{{
|
|
647
|
+
{{
|
|
648
|
+
t('requirements.recommendationProgress', {
|
|
649
|
+
ready: recommendationProgress.ready,
|
|
650
|
+
total: recommendationProgress.total,
|
|
651
|
+
})
|
|
652
|
+
}}
|
|
618
653
|
</span>
|
|
619
654
|
</div>
|
|
620
655
|
|
|
@@ -633,7 +668,9 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
633
668
|
<span class="text-sm font-medium text-white">{{
|
|
634
669
|
rec.sourceFinding.title
|
|
635
670
|
}}</span>
|
|
636
|
-
<p class="text-xs text-indigo-300/70">
|
|
671
|
+
<p class="text-xs text-indigo-300/70">
|
|
672
|
+
{{ t('requirements.generatingSuggestion') }}
|
|
673
|
+
</p>
|
|
637
674
|
</div>
|
|
638
675
|
</div>
|
|
639
676
|
</div>
|
|
@@ -655,7 +692,9 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
655
692
|
color="success"
|
|
656
693
|
icon="i-lucide-badge-check"
|
|
657
694
|
>
|
|
658
|
-
|
|
695
|
+
{{
|
|
696
|
+
t('requirements.currentStandard', { title: rec.groundedInFragment.title })
|
|
697
|
+
}}
|
|
659
698
|
</UBadge>
|
|
660
699
|
</div>
|
|
661
700
|
<p class="mt-2 whitespace-pre-line text-sm text-slate-300">
|
|
@@ -670,7 +709,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
670
709
|
:disabled="frozen"
|
|
671
710
|
@click="acceptRecommendation(rec)"
|
|
672
711
|
>
|
|
673
|
-
|
|
712
|
+
{{ t('requirements.accept') }}
|
|
674
713
|
</UButton>
|
|
675
714
|
<UButton
|
|
676
715
|
color="neutral"
|
|
@@ -680,7 +719,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
680
719
|
:disabled="frozen"
|
|
681
720
|
@click="rejectRecommendation(rec)"
|
|
682
721
|
>
|
|
683
|
-
|
|
722
|
+
{{ t('requirements.reject') }}
|
|
684
723
|
</UButton>
|
|
685
724
|
</div>
|
|
686
725
|
<!-- re-request with a note (an alternative to rejecting outright) -->
|
|
@@ -691,7 +730,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
691
730
|
autoresize
|
|
692
731
|
size="sm"
|
|
693
732
|
class="flex-1"
|
|
694
|
-
placeholder="
|
|
733
|
+
:placeholder="t('requirements.reRequestPlaceholder')"
|
|
695
734
|
:disabled="frozen || recommending"
|
|
696
735
|
/>
|
|
697
736
|
<UButton
|
|
@@ -703,7 +742,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
703
742
|
:disabled="!(reRequestNotes[rec.id] ?? '').trim() || frozen"
|
|
704
743
|
@click="reRequestRecommendation(rec)"
|
|
705
744
|
>
|
|
706
|
-
|
|
745
|
+
{{ t('requirements.reRequest') }}
|
|
707
746
|
</UButton>
|
|
708
747
|
</div>
|
|
709
748
|
</div>
|
|
@@ -715,7 +754,11 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
715
754
|
<div class="mb-3 flex items-center gap-1.5 text-[11px] text-emerald-400">
|
|
716
755
|
<UIcon name="i-lucide-file-check-2" class="h-3.5 w-3.5" />
|
|
717
756
|
<span class="font-semibold uppercase tracking-wide">
|
|
718
|
-
{{
|
|
757
|
+
{{
|
|
758
|
+
incorporated
|
|
759
|
+
? t('requirements.finalRequirements')
|
|
760
|
+
: t('requirements.incorporatedDraft')
|
|
761
|
+
}}
|
|
719
762
|
</span>
|
|
720
763
|
</div>
|
|
721
764
|
<div v-for="s in outline.sections" :key="s.id" class="mb-2">
|
|
@@ -750,19 +793,19 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
750
793
|
<div class="flex flex-col gap-4 px-4 py-5">
|
|
751
794
|
<div v-if="review" class="space-y-2 text-xs text-slate-400">
|
|
752
795
|
<div class="flex items-center justify-between">
|
|
753
|
-
<span>
|
|
796
|
+
<span>{{ t('requirements.stats.findings') }}</span>
|
|
754
797
|
<span class="text-slate-300">{{ review.items.length }}</span>
|
|
755
798
|
</div>
|
|
756
799
|
<div class="flex items-center justify-between">
|
|
757
|
-
<span>
|
|
800
|
+
<span>{{ t('requirements.stats.open') }}</span>
|
|
758
801
|
<span class="text-slate-300">{{ openCount }}</span>
|
|
759
802
|
</div>
|
|
760
803
|
<div class="flex items-center justify-between">
|
|
761
|
-
<span>
|
|
804
|
+
<span>{{ t('requirements.stats.answered') }}</span>
|
|
762
805
|
<span class="text-slate-300">{{ answeredCount }}</span>
|
|
763
806
|
</div>
|
|
764
807
|
<div v-if="review.model" class="flex items-center justify-between">
|
|
765
|
-
<span>
|
|
808
|
+
<span>{{ t('requirements.stats.model') }}</span>
|
|
766
809
|
<span class="truncate pl-2 text-slate-500">{{ review.model }}</span>
|
|
767
810
|
</div>
|
|
768
811
|
</div>
|
|
@@ -781,7 +824,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
781
824
|
:loading="acting"
|
|
782
825
|
@click="proceed"
|
|
783
826
|
>
|
|
784
|
-
|
|
827
|
+
{{ t('requirements.actions.proceedNothing') }}
|
|
785
828
|
</UButton>
|
|
786
829
|
<UButton
|
|
787
830
|
v-else
|
|
@@ -793,7 +836,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
793
836
|
:disabled="!canIncorporate"
|
|
794
837
|
@click="incorporate()"
|
|
795
838
|
>
|
|
796
|
-
|
|
839
|
+
{{ t('requirements.actions.incorporateAnswers') }}
|
|
797
840
|
</UButton>
|
|
798
841
|
<UButton
|
|
799
842
|
v-if="markedForRecommend.size > 0"
|
|
@@ -805,19 +848,22 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
805
848
|
:loading="recommending"
|
|
806
849
|
@click="requestRecommendations"
|
|
807
850
|
>
|
|
808
|
-
|
|
809
|
-
|
|
851
|
+
{{
|
|
852
|
+
t(
|
|
853
|
+
'requirements.actions.requestRecommendations',
|
|
854
|
+
{ count: markedForRecommend.size },
|
|
855
|
+
markedForRecommend.size,
|
|
856
|
+
)
|
|
810
857
|
}}
|
|
811
858
|
</UButton>
|
|
812
859
|
<p class="text-[11px] leading-relaxed text-slate-500">
|
|
813
860
|
<template v-if="canProceed">
|
|
814
|
-
|
|
861
|
+
{{ t('requirements.help.canProceed') }}
|
|
815
862
|
</template>
|
|
816
863
|
<template v-else-if="canIncorporate">
|
|
817
|
-
|
|
818
|
-
automatically.
|
|
864
|
+
{{ t('requirements.help.canIncorporate') }}
|
|
819
865
|
</template>
|
|
820
|
-
<template v-else>
|
|
866
|
+
<template v-else> {{ t('requirements.help.answerAll') }} </template>
|
|
821
867
|
</p>
|
|
822
868
|
</div>
|
|
823
869
|
|
|
@@ -831,7 +877,11 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
831
877
|
:loading="busy"
|
|
832
878
|
@click="reReview"
|
|
833
879
|
>
|
|
834
|
-
{{
|
|
880
|
+
{{
|
|
881
|
+
busy
|
|
882
|
+
? t('requirements.actions.reReviewing')
|
|
883
|
+
: t('requirements.actions.reReview')
|
|
884
|
+
}}
|
|
835
885
|
</UButton>
|
|
836
886
|
<UButton
|
|
837
887
|
color="neutral"
|
|
@@ -841,7 +891,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
841
891
|
icon="i-lucide-pencil"
|
|
842
892
|
@click="showRedo = !showRedo"
|
|
843
893
|
>
|
|
844
|
-
|
|
894
|
+
{{ t('requirements.actions.redoIncorporation') }}
|
|
845
895
|
</UButton>
|
|
846
896
|
<div v-if="showRedo" class="space-y-2">
|
|
847
897
|
<UTextarea
|
|
@@ -850,7 +900,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
850
900
|
autoresize
|
|
851
901
|
size="sm"
|
|
852
902
|
class="w-full"
|
|
853
|
-
placeholder="
|
|
903
|
+
:placeholder="t('requirements.redoPlaceholder')"
|
|
854
904
|
/>
|
|
855
905
|
<UButton
|
|
856
906
|
color="primary"
|
|
@@ -862,12 +912,11 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
862
912
|
:disabled="!redoComment.trim()"
|
|
863
913
|
@click="incorporate(redoComment.trim())"
|
|
864
914
|
>
|
|
865
|
-
|
|
915
|
+
{{ t('requirements.actions.redoWithDirection') }}
|
|
866
916
|
</UButton>
|
|
867
917
|
</div>
|
|
868
918
|
<p class="text-[11px] leading-relaxed text-slate-500">
|
|
869
|
-
|
|
870
|
-
was merged, redo it with a comment instead.
|
|
919
|
+
{{ t('requirements.help.merged') }}
|
|
871
920
|
</p>
|
|
872
921
|
</div>
|
|
873
922
|
|
|
@@ -875,7 +924,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
875
924
|
v-if="review && incorporated"
|
|
876
925
|
class="border-t border-slate-800 pt-4 text-[11px] leading-relaxed text-slate-500"
|
|
877
926
|
>
|
|
878
|
-
|
|
927
|
+
{{ t('requirements.settledFooter') }}
|
|
879
928
|
</div>
|
|
880
929
|
</div>
|
|
881
930
|
</aside>
|