@cat-factory/app 0.92.2 → 0.93.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.
- package/app/components/auth/LoginScreen.vue +5 -1
- package/app/components/board/AddTaskModal.vue +25 -5
- package/app/components/board/CreateInitiativeModal.vue +9 -1
- package/app/components/board/RecurringPipelineModal.vue +20 -4
- package/app/components/bootstrap/BootstrapModal.vue +9 -1
- package/app/components/brainstorm/BrainstormWindow.vue +5 -1
- package/app/components/clarity/ClarityReviewWindow.vue +5 -1
- package/app/components/docs/DocInterviewWindow.vue +209 -0
- package/app/components/documents/DocumentTemplatesModal.vue +5 -1
- package/app/components/fragments/FragmentLibraryManager.vue +10 -2
- package/app/components/github/GitHubPanel.vue +25 -4
- package/app/components/layout/BoardSwitcher.vue +10 -1
- package/app/components/layout/BoardToolbar.vue +15 -3
- package/app/components/layout/GitHubPatBanner.vue +5 -1
- package/app/components/layout/ProviderConfigBanner.vue +5 -1
- package/app/components/panels/AgentStepDetail.vue +5 -1
- package/app/components/panels/InspectorPanel.vue +5 -1
- package/app/components/panels/StepRestartControl.vue +10 -2
- package/app/components/panels/StepResultViewHost.vue +4 -0
- package/app/components/panels/inspector/FrontendConfig.vue +10 -1
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +11 -3
- package/app/components/pipeline/PipelineBuilder.vue +15 -2
- package/app/components/pipeline/PipelineProgress.vue +10 -2
- package/app/components/providers/AiPresetMismatchDialog.vue +10 -1
- package/app/components/providers/PersonalCredentialModal.vue +18 -2
- package/app/components/requirements/RequirementsReviewWindow.vue +5 -1
- package/app/components/sandbox/SandboxPanel.vue +10 -1
- package/app/components/settings/InfraHandlersConfigurator.vue +5 -1
- package/app/components/settings/IssueTrackerPanel.vue +20 -4
- package/app/components/settings/LocalModelEndpointsPanel.vue +5 -1
- package/app/components/settings/ModelConfigurationPanel.vue +20 -3
- package/app/components/settings/ProviderConnectionTab.vue +5 -1
- package/app/components/spec/ServiceSpecWindow.vue +15 -3
- package/app/components/testing/TestReportWindow.vue +10 -2
- package/app/composables/api/docInterview.ts +36 -0
- package/app/composables/useApi.ts +2 -0
- package/app/composables/useWorkspaceStream.ts +5 -0
- package/app/stores/docInterview.ts +89 -0
- package/app/stores/workspace.ts +1 -0
- package/app/types/doc-interview.ts +9 -0
- package/app/types/domain.ts +1 -0
- package/i18n/locales/en.json +16 -0
- package/i18n/locales/es.json +16 -0
- package/i18n/locales/fr.json +16 -0
- package/i18n/locales/he.json +16 -0
- package/i18n/locales/ja.json +16 -0
- package/i18n/locales/pl.json +16 -0
- package/i18n/locales/tr.json +16 -0
- package/i18n/locales/uk.json +16 -0
- package/package.json +5 -5
|
@@ -386,7 +386,11 @@ const noSignInMethod = computed(
|
|
|
386
386
|
:variant="p === remotePatProvider ? 'solid' : 'subtle'"
|
|
387
387
|
:icon="PROVIDER_ICONS[p]"
|
|
388
388
|
size="sm"
|
|
389
|
-
@click="
|
|
389
|
+
@click="
|
|
390
|
+
() => {
|
|
391
|
+
remotePatProvider = p
|
|
392
|
+
}
|
|
393
|
+
"
|
|
390
394
|
>
|
|
391
395
|
{{ PROVIDER_LABELS[p] }}
|
|
392
396
|
</UButton>
|
|
@@ -489,7 +489,11 @@ async function add() {
|
|
|
489
489
|
:variant="taskType === ty.value ? 'soft' : 'ghost'"
|
|
490
490
|
:icon="ty.icon"
|
|
491
491
|
size="xs"
|
|
492
|
-
@click="
|
|
492
|
+
@click="
|
|
493
|
+
() => {
|
|
494
|
+
taskType = ty.value
|
|
495
|
+
}
|
|
496
|
+
"
|
|
493
497
|
>
|
|
494
498
|
{{ ty.label }}
|
|
495
499
|
</UButton>
|
|
@@ -584,7 +588,11 @@ async function add() {
|
|
|
584
588
|
:variant="severity === s ? 'soft' : 'ghost'"
|
|
585
589
|
size="xs"
|
|
586
590
|
class="capitalize"
|
|
587
|
-
@click="
|
|
591
|
+
@click="
|
|
592
|
+
() => {
|
|
593
|
+
severity = severity === s ? '' : s
|
|
594
|
+
}
|
|
595
|
+
"
|
|
588
596
|
>
|
|
589
597
|
{{ s }}
|
|
590
598
|
</UButton>
|
|
@@ -621,7 +629,11 @@ async function add() {
|
|
|
621
629
|
:variant="docKind === k ? 'soft' : 'ghost'"
|
|
622
630
|
size="xs"
|
|
623
631
|
class="uppercase"
|
|
624
|
-
@click="
|
|
632
|
+
@click="
|
|
633
|
+
() => {
|
|
634
|
+
docKind = docKind === k ? '' : k
|
|
635
|
+
}
|
|
636
|
+
"
|
|
625
637
|
>
|
|
626
638
|
{{ k }}
|
|
627
639
|
</UButton>
|
|
@@ -761,7 +773,11 @@ async function add() {
|
|
|
761
773
|
variant="soft"
|
|
762
774
|
size="xs"
|
|
763
775
|
:icon="showDocPicker ? 'i-lucide-x' : 'i-lucide-plus'"
|
|
764
|
-
@click="
|
|
776
|
+
@click="
|
|
777
|
+
() => {
|
|
778
|
+
showDocPicker = !showDocPicker
|
|
779
|
+
}
|
|
780
|
+
"
|
|
765
781
|
>
|
|
766
782
|
{{ showDocPicker ? t('board.addTask.done') : t('board.addTask.attach') }}
|
|
767
783
|
</UButton>
|
|
@@ -832,7 +848,11 @@ async function add() {
|
|
|
832
848
|
variant="soft"
|
|
833
849
|
size="xs"
|
|
834
850
|
:icon="showIssuePicker ? 'i-lucide-x' : 'i-lucide-plus'"
|
|
835
|
-
@click="
|
|
851
|
+
@click="
|
|
852
|
+
() => {
|
|
853
|
+
showIssuePicker = !showIssuePicker
|
|
854
|
+
}
|
|
855
|
+
"
|
|
836
856
|
>
|
|
837
857
|
{{ showIssuePicker ? t('board.addTask.done') : t('board.addTask.attach') }}
|
|
838
858
|
</UButton>
|
|
@@ -95,7 +95,15 @@ async function create() {
|
|
|
95
95
|
</template>
|
|
96
96
|
<template #footer>
|
|
97
97
|
<div class="flex w-full justify-end gap-2">
|
|
98
|
-
<UButton
|
|
98
|
+
<UButton
|
|
99
|
+
color="neutral"
|
|
100
|
+
variant="ghost"
|
|
101
|
+
@click="
|
|
102
|
+
() => {
|
|
103
|
+
open = false
|
|
104
|
+
}
|
|
105
|
+
"
|
|
106
|
+
>
|
|
99
107
|
{{ t('common.cancel') }}
|
|
100
108
|
</UButton>
|
|
101
109
|
<UButton
|
|
@@ -284,7 +284,11 @@ async function add() {
|
|
|
284
284
|
:color="trackerKind === 'github' ? 'primary' : 'neutral'"
|
|
285
285
|
:variant="trackerKind === 'github' ? 'solid' : 'subtle'"
|
|
286
286
|
icon="i-lucide-github"
|
|
287
|
-
@click="
|
|
287
|
+
@click="
|
|
288
|
+
() => {
|
|
289
|
+
trackerKind = 'github'
|
|
290
|
+
}
|
|
291
|
+
"
|
|
288
292
|
>
|
|
289
293
|
{{ t('board.recurring.githubIssues') }}
|
|
290
294
|
</UButton>
|
|
@@ -293,7 +297,11 @@ async function add() {
|
|
|
293
297
|
:color="trackerKind === 'jira' ? 'primary' : 'neutral'"
|
|
294
298
|
:variant="trackerKind === 'jira' ? 'solid' : 'subtle'"
|
|
295
299
|
icon="i-lucide-square-check"
|
|
296
|
-
@click="
|
|
300
|
+
@click="
|
|
301
|
+
() => {
|
|
302
|
+
trackerKind = 'jira'
|
|
303
|
+
}
|
|
304
|
+
"
|
|
297
305
|
>
|
|
298
306
|
{{ t('board.recurring.jira') }}
|
|
299
307
|
</UButton>
|
|
@@ -302,7 +310,11 @@ async function add() {
|
|
|
302
310
|
:color="trackerKind === 'linear' ? 'primary' : 'neutral'"
|
|
303
311
|
:variant="trackerKind === 'linear' ? 'solid' : 'subtle'"
|
|
304
312
|
icon="i-lucide-square-kanban"
|
|
305
|
-
@click="
|
|
313
|
+
@click="
|
|
314
|
+
() => {
|
|
315
|
+
trackerKind = 'linear'
|
|
316
|
+
}
|
|
317
|
+
"
|
|
306
318
|
>
|
|
307
319
|
{{ t('board.recurring.linear') }}
|
|
308
320
|
</UButton>
|
|
@@ -337,7 +349,11 @@ async function add() {
|
|
|
337
349
|
:color="intakeSource === s.source ? 'primary' : 'neutral'"
|
|
338
350
|
:variant="intakeSource === s.source ? 'solid' : 'subtle'"
|
|
339
351
|
:icon="s.icon"
|
|
340
|
-
@click="
|
|
352
|
+
@click="
|
|
353
|
+
() => {
|
|
354
|
+
intakeSource = s.source
|
|
355
|
+
}
|
|
356
|
+
"
|
|
341
357
|
>
|
|
342
358
|
{{ s.label }}
|
|
343
359
|
</UButton>
|
|
@@ -713,7 +713,15 @@ const statusLabel = computed<Record<BootstrapStatus, string>>(() => ({
|
|
|
713
713
|
/>
|
|
714
714
|
</UFormField>
|
|
715
715
|
<div class="flex justify-end gap-2">
|
|
716
|
-
<UButton
|
|
716
|
+
<UButton
|
|
717
|
+
color="neutral"
|
|
718
|
+
variant="ghost"
|
|
719
|
+
@click="
|
|
720
|
+
() => {
|
|
721
|
+
showArchForm = false
|
|
722
|
+
}
|
|
723
|
+
"
|
|
724
|
+
>
|
|
717
725
|
{{ t('common.cancel') }}
|
|
718
726
|
</UButton>
|
|
719
727
|
<UButton
|
|
@@ -570,7 +570,11 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
570
570
|
size="sm"
|
|
571
571
|
block
|
|
572
572
|
icon="i-lucide-pencil"
|
|
573
|
-
@click="
|
|
573
|
+
@click="
|
|
574
|
+
() => {
|
|
575
|
+
showRedo = !showRedo
|
|
576
|
+
}
|
|
577
|
+
"
|
|
574
578
|
>
|
|
575
579
|
{{ t('brainstorm.redoIncorporation') }}
|
|
576
580
|
</UButton>
|
|
@@ -558,7 +558,11 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
558
558
|
size="sm"
|
|
559
559
|
block
|
|
560
560
|
icon="i-lucide-pencil"
|
|
561
|
-
@click="
|
|
561
|
+
@click="
|
|
562
|
+
() => {
|
|
563
|
+
showRedo = !showRedo
|
|
564
|
+
}
|
|
565
|
+
"
|
|
562
566
|
>
|
|
563
567
|
{{ t('clarity.redoIncorporation') }}
|
|
564
568
|
</UButton>
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// The interactive document-interview window (WS5) — the dedicated view of the doc-authoring
|
|
3
|
+
// INTERVIEWER gate. While the document run is parked between the outline and the draft, the
|
|
4
|
+
// interviewer's clarifying questions (pending `qa` entries with an empty answer) are shown here;
|
|
5
|
+
// the human answers them, then either CONTINUES (the interviewer re-runs and may ask follow-ups)
|
|
6
|
+
// or PROCEEDS (skip remaining questions — the interviewer converges into an authoring brief and
|
|
7
|
+
// the run advances to the writer). Opened via the universal result-view host as the
|
|
8
|
+
// `doc-interviewer` step's result view. Live `docInterview` stream events patch the store, so an
|
|
9
|
+
// open window follows the interview as it progresses. Mirrors InitiativePlanningWindow.vue.
|
|
10
|
+
import { computed, reactive, watch } from 'vue'
|
|
11
|
+
|
|
12
|
+
const board = useBoardStore()
|
|
13
|
+
const docInterview = useDocInterviewStore()
|
|
14
|
+
const { t } = useI18n()
|
|
15
|
+
|
|
16
|
+
const { open, blockId, close } = useResultView('doc-interview', {
|
|
17
|
+
onOpen: (id) => void docInterview.load(id),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const block = computed(() => (blockId.value ? board.getBlock(blockId.value) : undefined))
|
|
21
|
+
const session = computed(() => (blockId.value ? docInterview.forBlock(blockId.value) : null))
|
|
22
|
+
|
|
23
|
+
/** Every interview exchange, with a stable key for the list + draft map. */
|
|
24
|
+
const questions = computed(() =>
|
|
25
|
+
(session.value?.qa ?? []).map((q, i) => ({ ...q, key: q.id ?? `q-${i}` })),
|
|
26
|
+
)
|
|
27
|
+
const pending = computed(() => questions.value.filter((q) => !(q.answer ?? '').trim()))
|
|
28
|
+
/** The interview converged (or never started with a model): nothing left to answer. */
|
|
29
|
+
const converged = computed(() => session.value?.status === 'done')
|
|
30
|
+
|
|
31
|
+
// Per-question answer drafts, seeded from the entity and refreshed as new rounds arrive without
|
|
32
|
+
// clobbering an answer the human is mid-edit on.
|
|
33
|
+
const drafts = reactive<Record<string, string>>({})
|
|
34
|
+
watch(
|
|
35
|
+
questions,
|
|
36
|
+
(list) => {
|
|
37
|
+
for (const q of list) {
|
|
38
|
+
if (!(q.key in drafts)) drafts[q.key] = q.answer ?? ''
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{ immediate: true },
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const resuming = computed(() => docInterview.resuming)
|
|
45
|
+
/** Continue is meaningful once every pending question has a drafted answer. */
|
|
46
|
+
const allAnswered = computed(() => pending.value.every((q) => drafts[q.key]?.trim()))
|
|
47
|
+
|
|
48
|
+
/** Persist one answer if its draft differs from what's recorded. */
|
|
49
|
+
async function persist(q: { id?: string; key: string; answer?: string }) {
|
|
50
|
+
const id = q.id
|
|
51
|
+
if (!id || !blockId.value) return
|
|
52
|
+
const next = (drafts[q.key] ?? '').trim()
|
|
53
|
+
if (!next || next === (q.answer ?? '').trim()) return
|
|
54
|
+
await docInterview.answerQuestion(blockId.value, id, next)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Flush all dirty drafts, then run a window action (continue / proceed). */
|
|
58
|
+
async function flushThen(action: (id: string) => Promise<unknown>) {
|
|
59
|
+
if (!blockId.value) return
|
|
60
|
+
for (const q of questions.value) await persist(q)
|
|
61
|
+
await action(blockId.value)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const onContinue = () => flushThen((id) => docInterview.continueInterview(id))
|
|
65
|
+
const onProceed = () => flushThen((id) => docInterview.proceedInterview(id))
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<Teleport to="body">
|
|
70
|
+
<div
|
|
71
|
+
v-if="open"
|
|
72
|
+
class="fixed inset-0 z-50 flex max-h-[100dvh] items-stretch justify-center bg-slate-950/70 backdrop-blur-sm"
|
|
73
|
+
@click.self="close"
|
|
74
|
+
>
|
|
75
|
+
<div
|
|
76
|
+
class="m-4 flex w-full max-w-3xl flex-col overflow-hidden rounded-2xl border border-slate-800 bg-slate-900 shadow-2xl"
|
|
77
|
+
role="dialog"
|
|
78
|
+
aria-modal="true"
|
|
79
|
+
data-testid="doc-interview-window"
|
|
80
|
+
>
|
|
81
|
+
<!-- Header -->
|
|
82
|
+
<header class="flex items-center gap-3 border-b border-slate-800 px-5 py-3">
|
|
83
|
+
<span
|
|
84
|
+
class="flex h-8 w-8 items-center justify-center rounded-lg bg-indigo-500/15 text-indigo-300"
|
|
85
|
+
>
|
|
86
|
+
<UIcon name="i-lucide-messages-square" class="h-4 w-4" />
|
|
87
|
+
</span>
|
|
88
|
+
<div class="min-w-0 flex-1">
|
|
89
|
+
<h2 class="truncate text-sm font-semibold text-slate-100">
|
|
90
|
+
{{ block?.title ?? t('docInterview.title') }}
|
|
91
|
+
</h2>
|
|
92
|
+
<p class="truncate text-[11px] text-slate-400">
|
|
93
|
+
{{ t('docInterview.subtitle') }}
|
|
94
|
+
</p>
|
|
95
|
+
</div>
|
|
96
|
+
<UBadge
|
|
97
|
+
v-if="session"
|
|
98
|
+
:color="converged ? 'success' : 'primary'"
|
|
99
|
+
variant="subtle"
|
|
100
|
+
size="sm"
|
|
101
|
+
>
|
|
102
|
+
{{ t(converged ? 'docInterview.status.done' : 'docInterview.status.awaiting') }}
|
|
103
|
+
</UBadge>
|
|
104
|
+
<button
|
|
105
|
+
class="rounded-md p-1.5 text-slate-400 hover:bg-slate-800 hover:text-slate-200"
|
|
106
|
+
@click="close"
|
|
107
|
+
>
|
|
108
|
+
<UIcon name="i-lucide-x" class="h-4 w-4" />
|
|
109
|
+
</button>
|
|
110
|
+
</header>
|
|
111
|
+
|
|
112
|
+
<div class="min-h-0 flex-1 overflow-y-auto px-5 py-4">
|
|
113
|
+
<!-- No session yet -->
|
|
114
|
+
<div
|
|
115
|
+
v-if="!session"
|
|
116
|
+
class="flex h-full flex-col items-center justify-center gap-2 text-center text-slate-400"
|
|
117
|
+
>
|
|
118
|
+
<UIcon name="i-lucide-messages-square" class="h-8 w-8 opacity-40" />
|
|
119
|
+
<p class="text-sm">{{ t('docInterview.empty') }}</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<template v-else>
|
|
123
|
+
<p class="mb-4 text-[13px] leading-relaxed text-slate-300">
|
|
124
|
+
{{ t('docInterview.intro') }}
|
|
125
|
+
</p>
|
|
126
|
+
|
|
127
|
+
<!-- Converged: show the synthesized authoring brief -->
|
|
128
|
+
<div
|
|
129
|
+
v-if="converged"
|
|
130
|
+
class="rounded-lg border border-slate-800 bg-slate-950/40 p-4"
|
|
131
|
+
data-testid="doc-interview-converged"
|
|
132
|
+
>
|
|
133
|
+
<p class="mb-2 text-[11px] font-medium uppercase tracking-wide text-slate-500">
|
|
134
|
+
{{ t('docInterview.brief') }}
|
|
135
|
+
</p>
|
|
136
|
+
<pre
|
|
137
|
+
v-if="session.brief"
|
|
138
|
+
class="whitespace-pre-wrap break-words text-[13px] leading-relaxed text-slate-300"
|
|
139
|
+
>{{ session.brief }}</pre
|
|
140
|
+
>
|
|
141
|
+
<p v-else class="text-[13px] text-slate-400">{{ t('docInterview.converged') }}</p>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<!-- No pending questions but not yet converged -->
|
|
145
|
+
<div
|
|
146
|
+
v-else-if="questions.length === 0"
|
|
147
|
+
class="rounded-lg border border-slate-800 bg-slate-950/40 p-4 text-center text-[13px] text-slate-400"
|
|
148
|
+
>
|
|
149
|
+
{{ t('docInterview.converged') }}
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- Interview questions -->
|
|
153
|
+
<ul v-else class="space-y-4">
|
|
154
|
+
<li
|
|
155
|
+
v-for="q in questions"
|
|
156
|
+
:key="q.key"
|
|
157
|
+
class="rounded-lg border border-slate-800 bg-slate-950/40 p-3"
|
|
158
|
+
data-testid="doc-interview-question"
|
|
159
|
+
>
|
|
160
|
+
<p class="mb-2 text-[13px] font-medium text-slate-200">{{ q.question }}</p>
|
|
161
|
+
<UTextarea
|
|
162
|
+
v-model="drafts[q.key]"
|
|
163
|
+
:rows="2"
|
|
164
|
+
autoresize
|
|
165
|
+
:placeholder="t('docInterview.answerPlaceholder')"
|
|
166
|
+
class="w-full"
|
|
167
|
+
data-testid="doc-interview-answer"
|
|
168
|
+
@blur="persist(q)"
|
|
169
|
+
/>
|
|
170
|
+
</li>
|
|
171
|
+
</ul>
|
|
172
|
+
</template>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<!-- Action rail -->
|
|
176
|
+
<footer
|
|
177
|
+
v-if="session && !converged && questions.length > 0"
|
|
178
|
+
class="flex items-center justify-between gap-3 border-t border-slate-800 px-5 py-3"
|
|
179
|
+
>
|
|
180
|
+
<p class="text-[11px] text-slate-500">
|
|
181
|
+
{{ t('docInterview.hint') }}
|
|
182
|
+
</p>
|
|
183
|
+
<div class="flex items-center gap-2">
|
|
184
|
+
<UButton
|
|
185
|
+
color="neutral"
|
|
186
|
+
variant="ghost"
|
|
187
|
+
size="sm"
|
|
188
|
+
:loading="resuming"
|
|
189
|
+
data-testid="doc-interview-proceed"
|
|
190
|
+
@click="onProceed"
|
|
191
|
+
>
|
|
192
|
+
{{ t('docInterview.proceed') }}
|
|
193
|
+
</UButton>
|
|
194
|
+
<UButton
|
|
195
|
+
color="primary"
|
|
196
|
+
size="sm"
|
|
197
|
+
:loading="resuming"
|
|
198
|
+
:disabled="!allAnswered"
|
|
199
|
+
data-testid="doc-interview-continue"
|
|
200
|
+
@click="onContinue"
|
|
201
|
+
>
|
|
202
|
+
{{ t('docInterview.continue') }}
|
|
203
|
+
</UButton>
|
|
204
|
+
</div>
|
|
205
|
+
</footer>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
</Teleport>
|
|
209
|
+
</template>
|
|
@@ -344,7 +344,11 @@ async function unlinkSource(id: string) {
|
|
|
344
344
|
:color="tab === t ? 'primary' : 'neutral'"
|
|
345
345
|
:variant="tab === t ? 'solid' : 'ghost'"
|
|
346
346
|
size="sm"
|
|
347
|
-
@click="
|
|
347
|
+
@click="
|
|
348
|
+
() => {
|
|
349
|
+
tab = t
|
|
350
|
+
}
|
|
351
|
+
"
|
|
348
352
|
>
|
|
349
353
|
{{ tabLabel(t) }}
|
|
350
354
|
</UButton>
|
|
@@ -516,7 +520,11 @@ async function unlinkSource(id: string) {
|
|
|
516
520
|
size="xs"
|
|
517
521
|
:color="docDraft.source === s.source ? 'primary' : 'neutral'"
|
|
518
522
|
:variant="docDraft.source === s.source ? 'solid' : 'outline'"
|
|
519
|
-
@click="
|
|
523
|
+
@click="
|
|
524
|
+
() => {
|
|
525
|
+
docDraft.source = s.source
|
|
526
|
+
}
|
|
527
|
+
"
|
|
520
528
|
>
|
|
521
529
|
{{ s.label }}
|
|
522
530
|
</UButton>
|
|
@@ -319,7 +319,11 @@ async function merge(pr: GitHubPullRequest) {
|
|
|
319
319
|
:color="tab === tabItem.id ? 'primary' : 'neutral'"
|
|
320
320
|
:variant="tab === tabItem.id ? 'soft' : 'ghost'"
|
|
321
321
|
:icon="tabItem.icon"
|
|
322
|
-
@click="
|
|
322
|
+
@click="
|
|
323
|
+
() => {
|
|
324
|
+
tab = tabItem.id
|
|
325
|
+
}
|
|
326
|
+
"
|
|
323
327
|
>
|
|
324
328
|
{{ tabItem.label }}
|
|
325
329
|
</UButton>
|
|
@@ -342,7 +346,11 @@ async function merge(pr: GitHubPullRequest) {
|
|
|
342
346
|
color="neutral"
|
|
343
347
|
variant="soft"
|
|
344
348
|
icon="i-lucide-list-checks"
|
|
345
|
-
@click="
|
|
349
|
+
@click="
|
|
350
|
+
() => {
|
|
351
|
+
managing ? (managing = false) : openManage()
|
|
352
|
+
}
|
|
353
|
+
"
|
|
346
354
|
>
|
|
347
355
|
{{ managing ? t('common.close') : t('github.panel.manageRepos') }}
|
|
348
356
|
</UButton>
|
|
@@ -385,7 +393,16 @@ async function merge(pr: GitHubPullRequest) {
|
|
|
385
393
|
</button>
|
|
386
394
|
</div>
|
|
387
395
|
<div class="flex items-center justify-end gap-2 pt-1">
|
|
388
|
-
<UButton
|
|
396
|
+
<UButton
|
|
397
|
+
color="neutral"
|
|
398
|
+
variant="ghost"
|
|
399
|
+
size="sm"
|
|
400
|
+
@click="
|
|
401
|
+
() => {
|
|
402
|
+
managing = false
|
|
403
|
+
}
|
|
404
|
+
"
|
|
405
|
+
>
|
|
389
406
|
{{ t('common.cancel') }}
|
|
390
407
|
</UButton>
|
|
391
408
|
<UButton
|
|
@@ -502,7 +519,11 @@ async function merge(pr: GitHubPullRequest) {
|
|
|
502
519
|
color="neutral"
|
|
503
520
|
variant="soft"
|
|
504
521
|
icon="i-lucide-plus"
|
|
505
|
-
@click="
|
|
522
|
+
@click="
|
|
523
|
+
() => {
|
|
524
|
+
showPrForm = !showPrForm
|
|
525
|
+
}
|
|
526
|
+
"
|
|
506
527
|
>
|
|
507
528
|
{{ t('github.panel.openPr') }}
|
|
508
529
|
</UButton>
|
|
@@ -300,7 +300,16 @@ async function submitPrompt() {
|
|
|
300
300
|
/>
|
|
301
301
|
</UFormField>
|
|
302
302
|
<div class="flex justify-end gap-2">
|
|
303
|
-
<UButton
|
|
303
|
+
<UButton
|
|
304
|
+
color="neutral"
|
|
305
|
+
variant="ghost"
|
|
306
|
+
:disabled="busy"
|
|
307
|
+
@click="
|
|
308
|
+
() => {
|
|
309
|
+
prompt = null
|
|
310
|
+
}
|
|
311
|
+
"
|
|
312
|
+
>
|
|
304
313
|
{{ t('common.cancel') }}
|
|
305
314
|
</UButton>
|
|
306
315
|
<UButton type="submit" color="primary" :loading="busy">
|
|
@@ -105,7 +105,11 @@ const decisionItems = computed(() =>
|
|
|
105
105
|
variant="ghost"
|
|
106
106
|
size="sm"
|
|
107
107
|
data-testid="board-zoom-out"
|
|
108
|
-
@click="
|
|
108
|
+
@click="
|
|
109
|
+
() => {
|
|
110
|
+
zoomOut()
|
|
111
|
+
}
|
|
112
|
+
"
|
|
109
113
|
/>
|
|
110
114
|
<!-- The zoom %/LOD readout is the first thing to drop on narrow viewports. -->
|
|
111
115
|
<div class="hidden w-20 text-center text-xs tabular-nums text-slate-300 sm:block">
|
|
@@ -118,7 +122,11 @@ const decisionItems = computed(() =>
|
|
|
118
122
|
variant="ghost"
|
|
119
123
|
size="sm"
|
|
120
124
|
data-testid="board-zoom-in"
|
|
121
|
-
@click="
|
|
125
|
+
@click="
|
|
126
|
+
() => {
|
|
127
|
+
zoomIn()
|
|
128
|
+
}
|
|
129
|
+
"
|
|
122
130
|
/>
|
|
123
131
|
<UButton
|
|
124
132
|
icon="i-lucide-maximize"
|
|
@@ -126,7 +134,11 @@ const decisionItems = computed(() =>
|
|
|
126
134
|
variant="ghost"
|
|
127
135
|
size="sm"
|
|
128
136
|
data-testid="board-fit-view"
|
|
129
|
-
@click="
|
|
137
|
+
@click="
|
|
138
|
+
() => {
|
|
139
|
+
fitView({ padding: 0.2 })
|
|
140
|
+
}
|
|
141
|
+
"
|
|
130
142
|
/>
|
|
131
143
|
|
|
132
144
|
<USeparator orientation="vertical" class="mx-1 h-6" />
|
|
@@ -34,7 +34,11 @@ const show = computed(() => !!setupUrl.value && !dismissed.value)
|
|
|
34
34
|
size="xs"
|
|
35
35
|
icon="i-lucide-x"
|
|
36
36
|
:aria-label="t('common.close')"
|
|
37
|
-
@click="
|
|
37
|
+
@click="
|
|
38
|
+
() => {
|
|
39
|
+
dismissed = true
|
|
40
|
+
}
|
|
41
|
+
"
|
|
38
42
|
/>
|
|
39
43
|
</div>
|
|
40
44
|
<p class="mt-1 text-sm text-amber-200/90">
|
|
@@ -62,7 +62,11 @@ const show = computed(() => pending.value.length > 0 && !dismissed.value)
|
|
|
62
62
|
size="xs"
|
|
63
63
|
icon="i-lucide-x"
|
|
64
64
|
:aria-label="t('common.close')"
|
|
65
|
-
@click="
|
|
65
|
+
@click="
|
|
66
|
+
() => {
|
|
67
|
+
dismissed = true
|
|
68
|
+
}
|
|
69
|
+
"
|
|
66
70
|
/>
|
|
67
71
|
</div>
|
|
68
72
|
<p class="mt-1 text-sm text-amber-200/90">
|
|
@@ -403,7 +403,11 @@ async function copyOutput() {
|
|
|
403
403
|
:icon="showProvisioning ? 'i-lucide-chevron-up' : 'i-lucide-scroll-text'"
|
|
404
404
|
variant="ghost"
|
|
405
405
|
size="xs"
|
|
406
|
-
@click="
|
|
406
|
+
@click="
|
|
407
|
+
() => {
|
|
408
|
+
showProvisioning = !showProvisioning
|
|
409
|
+
}
|
|
410
|
+
"
|
|
407
411
|
>
|
|
408
412
|
{{
|
|
409
413
|
showProvisioning
|
|
@@ -323,7 +323,11 @@ const showOriginalDescription = ref(false)
|
|
|
323
323
|
variant="ghost"
|
|
324
324
|
size="xs"
|
|
325
325
|
:icon="showOriginalDescription ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
|
|
326
|
-
@click="
|
|
326
|
+
@click="
|
|
327
|
+
() => {
|
|
328
|
+
showOriginalDescription = !showOriginalDescription
|
|
329
|
+
}
|
|
330
|
+
"
|
|
327
331
|
>
|
|
328
332
|
{{ t('panels.inspector.originalDescriptionFrozen') }}
|
|
329
333
|
</UButton>
|
|
@@ -64,7 +64,11 @@ async function restart() {
|
|
|
64
64
|
variant="ghost"
|
|
65
65
|
size="sm"
|
|
66
66
|
:title="t('panels.stepRestart.restartFromStep')"
|
|
67
|
-
@click="
|
|
67
|
+
@click="
|
|
68
|
+
() => {
|
|
69
|
+
armed = true
|
|
70
|
+
}
|
|
71
|
+
"
|
|
68
72
|
/>
|
|
69
73
|
<template v-else>
|
|
70
74
|
<UButton
|
|
@@ -82,7 +86,11 @@ async function restart() {
|
|
|
82
86
|
variant="ghost"
|
|
83
87
|
size="sm"
|
|
84
88
|
:disabled="restarting"
|
|
85
|
-
@click="
|
|
89
|
+
@click="
|
|
90
|
+
() => {
|
|
91
|
+
armed = false
|
|
92
|
+
}
|
|
93
|
+
"
|
|
86
94
|
>
|
|
87
95
|
{{ t('common.cancel') }}
|
|
88
96
|
</UButton>
|
|
@@ -25,6 +25,7 @@ import FollowUpWindow from '~/components/followUp/FollowUpWindow.vue'
|
|
|
25
25
|
import MergerResultView from '~/components/panels/MergerResultView.vue'
|
|
26
26
|
import InitiativeTrackerWindow from '~/components/initiative/InitiativeTrackerWindow.vue'
|
|
27
27
|
import InitiativePlanningWindow from '~/components/initiative/InitiativePlanningWindow.vue'
|
|
28
|
+
import DocInterviewWindow from '~/components/docs/DocInterviewWindow.vue'
|
|
28
29
|
|
|
29
30
|
const ui = useUiStore()
|
|
30
31
|
|
|
@@ -59,6 +60,9 @@ const STEP_RESULT_VIEWS: Record<string, Component> = {
|
|
|
59
60
|
// as the planner step's result view.
|
|
60
61
|
'initiative-tracker': InitiativeTrackerWindow,
|
|
61
62
|
'initiative-planning': InitiativePlanningWindow,
|
|
63
|
+
// The interactive document-interview gate (WS5): the interviewer's clarifying questions +
|
|
64
|
+
// answer / continue / proceed, opened as the `doc-interviewer` step's result view.
|
|
65
|
+
'doc-interview': DocInterviewWindow,
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
const active = computed<Component | null>(() => {
|