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