@cat-factory/app 0.54.4 → 0.55.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/app.vue +14 -0
- package/app/components/auth/UserMenu.vue +1 -1
- package/app/components/board/AddTaskModal.vue +5 -4
- package/app/components/board/nodes/AgentChip.vue +2 -2
- package/app/components/board/nodes/BlockNode.vue +12 -8
- package/app/components/board/nodes/DraggableTask.vue +1 -1
- package/app/components/board/nodes/EpicNode.vue +1 -1
- package/app/components/board/nodes/ModuleFrame.vue +7 -4
- package/app/components/board/nodes/TaskCard.vue +2 -2
- package/app/components/board/nodes/TaskPipelineMini.vue +3 -3
- package/app/components/brainstorm/BrainstormWindow.vue +8 -7
- package/app/components/clarity/ClarityReviewWindow.vue +8 -7
- package/app/components/consensus/ConsensusSessionWindow.vue +2 -2
- package/app/components/documents/ContextDocumentPicker.vue +4 -4
- package/app/components/documents/SpawnPreviewModal.vue +4 -4
- package/app/components/focus/BlockFocusView.vue +11 -4
- package/app/components/fragments/FragmentLibraryManager.vue +5 -5
- package/app/components/gates/GateResultView.vue +3 -3
- package/app/components/github/GitHubPanel.vue +5 -2
- package/app/components/humanTest/HumanTestWindow.vue +1 -1
- package/app/components/kaizen/KaizenPanel.vue +5 -5
- package/app/components/kaizen/KaizenStepStatus.vue +2 -2
- package/app/components/layout/BoardSwitcher.vue +4 -4
- package/app/components/layout/CommandBar.vue +1 -1
- package/app/components/layout/IntegrationBackTitle.vue +2 -1
- package/app/components/layout/IntegrationsHub.vue +10 -4
- package/app/components/layout/LanguageSwitcher.vue +1 -1
- package/app/components/layout/NotificationsInbox.vue +1 -1
- package/app/components/layout/PersonalSetupModal.vue +5 -2
- package/app/components/layout/SideBar.vue +5 -3
- package/app/components/media/ArtifactLightbox.vue +5 -5
- package/app/components/media/ImageCompare.vue +6 -1
- package/app/components/observability/StepMetricsBar.vue +6 -2
- package/app/components/palettes/AgentPalette.vue +4 -4
- package/app/components/panels/AgentStepDetail.vue +12 -12
- package/app/components/panels/GenericStructuredResultView.vue +1 -1
- package/app/components/panels/InspectorPanel.vue +2 -2
- package/app/components/panels/ObservabilityPanel.vue +6 -6
- package/app/components/panels/StepMetadataCard.vue +1 -1
- package/app/components/panels/inspector/ContainerSummary.vue +2 -2
- package/app/components/panels/inspector/EpicChildren.vue +3 -3
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +1 -1
- package/app/components/panels/inspector/ServiceFragments.vue +1 -1
- package/app/components/panels/inspector/ServiceTestConfig.vue +1 -1
- package/app/components/panels/inspector/TaskDependencies.vue +1 -1
- package/app/components/panels/inspector/TaskEstimateBadge.vue +1 -1
- package/app/components/panels/inspector/TaskExecution.vue +9 -9
- package/app/components/panels/inspector/TaskRunSettings.vue +2 -2
- package/app/components/panels/inspector/TaskStructure.vue +1 -1
- package/app/components/pipeline/IterationCapPrompt.vue +1 -0
- package/app/components/pipeline/PipelineBuilder.vue +8 -8
- package/app/components/pipeline/PipelineProgress.vue +4 -4
- package/app/components/providers/ApiKeysSection.vue +2 -2
- package/app/components/providers/PersonalSubscriptionSection.vue +2 -2
- package/app/components/providers/VendorCredentialsModal.vue +2 -2
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +1 -1
- package/app/components/requirements/RequirementsReviewWindow.vue +9 -8
- package/app/components/sandbox/SandboxPanel.vue +17 -17
- package/app/components/settings/LocalModelEndpointsPanel.vue +1 -1
- package/app/components/settings/ModelConfigurationPanel.vue +4 -3
- package/app/components/settings/OpenRouterCatalogPanel.vue +3 -3
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +1 -1
- package/app/components/spec/ServiceSpecWindow.vue +3 -3
- package/app/components/tasks/ContextIssuePicker.vue +5 -5
- package/app/components/tasks/TaskContextIssues.vue +1 -1
- package/app/components/tasks/TaskImportModal.vue +1 -1
- package/app/components/testing/TestReportWindow.vue +5 -5
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +2 -2
- package/app/pages/index.vue +1 -1
- package/i18n/i18n.config.ts +9 -0
- package/i18n/locales/he.json +3385 -0
- package/nuxt.config.ts +1 -0
- package/package.json +1 -1
|
@@ -69,7 +69,7 @@ function statusLabel(g: KaizenGrading): string {
|
|
|
69
69
|
{{ t('kaizen.subtitle') }}
|
|
70
70
|
</p>
|
|
71
71
|
</div>
|
|
72
|
-
<div class="
|
|
72
|
+
<div class="ms-auto flex items-center gap-2">
|
|
73
73
|
<UButton
|
|
74
74
|
icon="i-lucide-refresh-cw"
|
|
75
75
|
size="xs"
|
|
@@ -124,9 +124,9 @@ function statusLabel(g: KaizenGrading): string {
|
|
|
124
124
|
<UIcon
|
|
125
125
|
v-if="c.verified"
|
|
126
126
|
name="i-lucide-badge-check"
|
|
127
|
-
class="
|
|
127
|
+
class="ms-auto h-3.5 w-3.5 text-emerald-400"
|
|
128
128
|
/>
|
|
129
|
-
<span v-else class="
|
|
129
|
+
<span v-else class="ms-auto text-[11px] text-slate-500">
|
|
130
130
|
{{ t('kaizen.verifiedCombos.progress', { count: c.consecutiveHighGrades }) }}
|
|
131
131
|
</span>
|
|
132
132
|
</div>
|
|
@@ -152,7 +152,7 @@ function statusLabel(g: KaizenGrading): string {
|
|
|
152
152
|
{{ t('kaizen.history.title') }}
|
|
153
153
|
</h2>
|
|
154
154
|
<div class="overflow-hidden rounded-lg border border-slate-800">
|
|
155
|
-
<table class="w-full text-
|
|
155
|
+
<table class="w-full text-start text-xs">
|
|
156
156
|
<thead class="bg-slate-900/60 text-[11px] uppercase tracking-wide text-slate-500">
|
|
157
157
|
<tr>
|
|
158
158
|
<th class="px-3 py-2 font-medium">{{ t('kaizen.history.col.when') }}</th>
|
|
@@ -189,7 +189,7 @@ function statusLabel(g: KaizenGrading): string {
|
|
|
189
189
|
{{ statusLabel(g) }}
|
|
190
190
|
</td>
|
|
191
191
|
<td class="px-3 py-2 text-slate-400">
|
|
192
|
-
<ul v-if="g.recommendations.length" class="list-disc space-y-0.5
|
|
192
|
+
<ul v-if="g.recommendations.length" class="list-disc space-y-0.5 ps-4">
|
|
193
193
|
<li v-for="(r, i) in g.recommendations" :key="i">{{ r }}</li>
|
|
194
194
|
</ul>
|
|
195
195
|
<span v-else-if="g.status === 'complete'" class="text-slate-600">—</span>
|
|
@@ -47,7 +47,7 @@ const tone = computed(() => {
|
|
|
47
47
|
<div class="flex items-center gap-2">
|
|
48
48
|
<UIcon name="i-lucide-sparkles" class="h-4 w-4 text-teal-400" />
|
|
49
49
|
<h3 class="text-sm font-semibold text-slate-200">{{ t('kaizen.grading.title') }}</h3>
|
|
50
|
-
<span class="
|
|
50
|
+
<span class="ms-auto flex items-center gap-1.5 text-xs">
|
|
51
51
|
<template v-if="grading.status === 'scheduled'">
|
|
52
52
|
<UIcon name="i-lucide-clock" class="h-3.5 w-3.5 text-slate-500" />
|
|
53
53
|
<span class="text-slate-400">{{ t('kaizen.status.scheduled') }}</span>
|
|
@@ -78,7 +78,7 @@ const tone = computed(() => {
|
|
|
78
78
|
<p class="text-[11px] font-medium uppercase tracking-wide text-slate-500">
|
|
79
79
|
{{ t('kaizen.recommendations') }}
|
|
80
80
|
</p>
|
|
81
|
-
<ul class="mt-1 list-disc space-y-0.5
|
|
81
|
+
<ul class="mt-1 list-disc space-y-0.5 ps-4 text-xs text-slate-300">
|
|
82
82
|
<li v-for="(r, i) in grading.recommendations" :key="i">{{ r }}</li>
|
|
83
83
|
</ul>
|
|
84
84
|
</div>
|
|
@@ -232,7 +232,7 @@ async function submitPrompt() {
|
|
|
232
232
|
>
|
|
233
233
|
<button
|
|
234
234
|
type="button"
|
|
235
|
-
class="flex w-full items-center gap-2 rounded-md px-1.5 py-1 text-
|
|
235
|
+
class="flex w-full items-center gap-2 rounded-md px-1.5 py-1 text-start transition hover:bg-slate-800/60"
|
|
236
236
|
:disabled="busy"
|
|
237
237
|
>
|
|
238
238
|
<UIcon
|
|
@@ -244,7 +244,7 @@ async function submitPrompt() {
|
|
|
244
244
|
</span>
|
|
245
245
|
<UIcon
|
|
246
246
|
name="i-lucide-chevrons-up-down"
|
|
247
|
-
class="
|
|
247
|
+
class="ms-auto h-3.5 w-3.5 shrink-0 text-slate-600"
|
|
248
248
|
/>
|
|
249
249
|
</button>
|
|
250
250
|
</UDropdownMenu>
|
|
@@ -253,14 +253,14 @@ async function submitPrompt() {
|
|
|
253
253
|
<UDropdownMenu :items="boardItems" :content="{ align: 'start' }" class="w-full">
|
|
254
254
|
<button
|
|
255
255
|
type="button"
|
|
256
|
-
class="flex w-full items-center gap-2 rounded-lg border border-slate-800 bg-slate-900/60 px-2.5 py-1.5 text-
|
|
256
|
+
class="flex w-full items-center gap-2 rounded-lg border border-slate-800 bg-slate-900/60 px-2.5 py-1.5 text-start transition hover:bg-slate-800/60"
|
|
257
257
|
:disabled="busy"
|
|
258
258
|
>
|
|
259
259
|
<UIcon name="i-lucide-layout-dashboard" class="h-4 w-4 shrink-0 text-indigo-400" />
|
|
260
260
|
<span class="truncate text-sm font-medium text-white">
|
|
261
261
|
{{ workspace.activeWorkspace?.name ?? t('layout.boardSwitcher.boardFallback') }}
|
|
262
262
|
</span>
|
|
263
|
-
<UIcon name="i-lucide-chevron-down" class="
|
|
263
|
+
<UIcon name="i-lucide-chevron-down" class="ms-auto h-4 w-4 shrink-0 text-slate-500" />
|
|
264
264
|
</button>
|
|
265
265
|
</UDropdownMenu>
|
|
266
266
|
|
|
@@ -321,7 +321,7 @@ function indexOf(cmd: Command) {
|
|
|
321
321
|
v-for="cmd in group.items"
|
|
322
322
|
:key="cmd.id"
|
|
323
323
|
type="button"
|
|
324
|
-
class="flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-
|
|
324
|
+
class="flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-start text-sm transition"
|
|
325
325
|
:class="
|
|
326
326
|
indexOf(cmd) === activeIndex
|
|
327
327
|
? 'bg-slate-800 text-slate-100'
|
|
@@ -23,10 +23,11 @@ const backLabel = computed(() =>
|
|
|
23
23
|
<UButton
|
|
24
24
|
v-if="cameFromHub"
|
|
25
25
|
icon="i-lucide-arrow-left"
|
|
26
|
+
:ui="{ leadingIcon: 'rtl:-scale-x-100', trailingIcon: 'rtl:-scale-x-100' }"
|
|
26
27
|
color="neutral"
|
|
27
28
|
variant="ghost"
|
|
28
29
|
size="xs"
|
|
29
|
-
class="-
|
|
30
|
+
class="-ms-1.5 shrink-0"
|
|
30
31
|
:aria-label="backLabel"
|
|
31
32
|
@click.stop="emit('back')"
|
|
32
33
|
/>
|
|
@@ -390,7 +390,7 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
390
390
|
v-for="item in group.items"
|
|
391
391
|
:key="item.key"
|
|
392
392
|
type="button"
|
|
393
|
-
class="flex w-full items-center gap-3 rounded-lg border border-slate-800 bg-slate-900/50 px-3 py-2.5 text-
|
|
393
|
+
class="flex w-full items-center gap-3 rounded-lg border border-slate-800 bg-slate-900/50 px-3 py-2.5 text-start transition hover:border-slate-700 hover:bg-slate-900"
|
|
394
394
|
@click="item.onClick()"
|
|
395
395
|
>
|
|
396
396
|
<UIcon :name="item.icon" class="h-5 w-5 shrink-0 text-slate-300" />
|
|
@@ -417,7 +417,10 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
417
417
|
</div>
|
|
418
418
|
<p class="truncate text-xs text-slate-400">{{ item.description }}</p>
|
|
419
419
|
</div>
|
|
420
|
-
<UIcon
|
|
420
|
+
<UIcon
|
|
421
|
+
name="i-lucide-chevron-right"
|
|
422
|
+
class="h-4 w-4 shrink-0 text-slate-500 rtl:-scale-x-100"
|
|
423
|
+
/>
|
|
421
424
|
</button>
|
|
422
425
|
</div>
|
|
423
426
|
|
|
@@ -425,7 +428,7 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
425
428
|
<button
|
|
426
429
|
v-if="group.footerLink"
|
|
427
430
|
type="button"
|
|
428
|
-
class="mt-1.5 flex w-full items-center gap-2 rounded-md px-3 py-1.5 text-
|
|
431
|
+
class="mt-1.5 flex w-full items-center gap-2 rounded-md px-3 py-1.5 text-start text-xs text-slate-400 transition hover:bg-slate-900/60 hover:text-slate-200"
|
|
429
432
|
@click="group.footerLink.onClick()"
|
|
430
433
|
>
|
|
431
434
|
<UIcon :name="group.footerLink.icon" class="h-3.5 w-3.5 shrink-0" />
|
|
@@ -433,7 +436,10 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
433
436
|
<span v-if="group.footerLink.status" class="shrink-0 text-slate-500">{{
|
|
434
437
|
group.footerLink.status
|
|
435
438
|
}}</span>
|
|
436
|
-
<UIcon
|
|
439
|
+
<UIcon
|
|
440
|
+
name="i-lucide-chevron-right"
|
|
441
|
+
class="h-3.5 w-3.5 shrink-0 text-slate-600 rtl:-scale-x-100"
|
|
442
|
+
/>
|
|
437
443
|
</button>
|
|
438
444
|
</section>
|
|
439
445
|
</div>
|
|
@@ -39,7 +39,7 @@ const items = computed<DropdownMenuItem[][]>(() => [
|
|
|
39
39
|
type="button"
|
|
40
40
|
data-testid="language-switcher"
|
|
41
41
|
:aria-label="t('language.switcher')"
|
|
42
|
-
class="flex w-full items-center gap-2 rounded-lg border border-slate-800 bg-slate-900/60 p-2 text-
|
|
42
|
+
class="flex w-full items-center gap-2 rounded-lg border border-slate-800 bg-slate-900/60 p-2 text-start transition hover:bg-slate-800/60"
|
|
43
43
|
>
|
|
44
44
|
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-slate-400" />
|
|
45
45
|
<div class="min-w-0 flex-1">
|
|
@@ -226,7 +226,7 @@ function revealDecision(n: Notification) {
|
|
|
226
226
|
<div class="min-w-0 flex-1">
|
|
227
227
|
<div class="flex items-center gap-1.5">
|
|
228
228
|
<button
|
|
229
|
-
class="block min-w-0 flex-1 truncate text-
|
|
229
|
+
class="block min-w-0 flex-1 truncate text-start text-sm font-medium text-slate-200 hover:underline"
|
|
230
230
|
:title="n.title"
|
|
231
231
|
@click="reveal(n)"
|
|
232
232
|
>
|
|
@@ -125,7 +125,7 @@ const groups = computed<PersonalGroup[]>(() => {
|
|
|
125
125
|
v-for="item in group.items"
|
|
126
126
|
:key="item.key"
|
|
127
127
|
type="button"
|
|
128
|
-
class="flex w-full items-center gap-3 rounded-lg border border-slate-800 bg-slate-900/50 px-3 py-2.5 text-
|
|
128
|
+
class="flex w-full items-center gap-3 rounded-lg border border-slate-800 bg-slate-900/50 px-3 py-2.5 text-start transition hover:border-slate-700 hover:bg-slate-900"
|
|
129
129
|
@click="item.onClick()"
|
|
130
130
|
>
|
|
131
131
|
<UIcon :name="item.icon" class="h-5 w-5 shrink-0 text-slate-300" />
|
|
@@ -141,7 +141,10 @@ const groups = computed<PersonalGroup[]>(() => {
|
|
|
141
141
|
</div>
|
|
142
142
|
<p class="truncate text-xs text-slate-400">{{ item.description }}</p>
|
|
143
143
|
</div>
|
|
144
|
-
<UIcon
|
|
144
|
+
<UIcon
|
|
145
|
+
name="i-lucide-chevron-right"
|
|
146
|
+
class="h-4 w-4 shrink-0 text-slate-500 rtl:-scale-x-100"
|
|
147
|
+
/>
|
|
145
148
|
</button>
|
|
146
149
|
</div>
|
|
147
150
|
</section>
|
|
@@ -139,8 +139,10 @@ watch(
|
|
|
139
139
|
:aria-modal="drawerOpen ? 'true' : undefined"
|
|
140
140
|
:aria-label="isCompact ? t('nav.menu') : undefined"
|
|
141
141
|
:inert="isCompact && !ui.mobileNavOpen"
|
|
142
|
-
class="fixed inset-y-0
|
|
143
|
-
:class="
|
|
142
|
+
class="fixed inset-y-0 start-0 z-40 flex h-full w-64 shrink-0 flex-col gap-4 overflow-y-auto border-e border-slate-800 bg-slate-900/95 p-3 backdrop-blur transition-transform duration-200 focus:outline-none lg:static lg:z-auto lg:translate-x-0 lg:bg-slate-900/80"
|
|
143
|
+
:class="
|
|
144
|
+
ui.mobileNavOpen ? 'translate-x-0' : '-translate-x-full rtl:translate-x-full lg:translate-x-0'
|
|
145
|
+
"
|
|
144
146
|
>
|
|
145
147
|
<BoardSwitcher />
|
|
146
148
|
|
|
@@ -149,7 +151,7 @@ watch(
|
|
|
149
151
|
and reach every action below. -->
|
|
150
152
|
<button
|
|
151
153
|
type="button"
|
|
152
|
-
class="flex items-center gap-2 rounded-lg border border-slate-700 bg-slate-800/60 px-2.5 py-2 text-
|
|
154
|
+
class="flex items-center gap-2 rounded-lg border border-slate-700 bg-slate-800/60 px-2.5 py-2 text-start text-sm text-slate-400 transition hover:border-slate-500 hover:bg-slate-800"
|
|
153
155
|
@click="ui.openCommandBar()"
|
|
154
156
|
>
|
|
155
157
|
<UIcon name="i-lucide-search" class="h-4 w-4 shrink-0" />
|
|
@@ -206,7 +206,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
206
206
|
<UIcon name="i-lucide-maximize" class="h-4 w-4" />
|
|
207
207
|
</button>
|
|
208
208
|
<button
|
|
209
|
-
class="
|
|
209
|
+
class="ms-1 rounded-md p-1.5 text-slate-400 hover:bg-slate-800 hover:text-slate-200"
|
|
210
210
|
:title="t('media.lightbox.close')"
|
|
211
211
|
@click="close"
|
|
212
212
|
>
|
|
@@ -223,11 +223,11 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
223
223
|
>
|
|
224
224
|
<button
|
|
225
225
|
v-if="total > 1"
|
|
226
|
-
class="absolute
|
|
226
|
+
class="absolute start-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-slate-900/80 p-2 text-slate-300 hover:bg-slate-800 hover:text-white"
|
|
227
227
|
:title="t('media.lightbox.prev')"
|
|
228
228
|
@click="go(-1)"
|
|
229
229
|
>
|
|
230
|
-
<UIcon name="i-lucide-chevron-left" class="h-5 w-5" />
|
|
230
|
+
<UIcon name="i-lucide-chevron-left" class="h-5 w-5 rtl:-scale-x-100" />
|
|
231
231
|
</button>
|
|
232
232
|
|
|
233
233
|
<img
|
|
@@ -267,11 +267,11 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
267
267
|
|
|
268
268
|
<button
|
|
269
269
|
v-if="total > 1"
|
|
270
|
-
class="absolute
|
|
270
|
+
class="absolute end-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-slate-900/80 p-2 text-slate-300 hover:bg-slate-800 hover:text-white"
|
|
271
271
|
:title="t('media.lightbox.next')"
|
|
272
272
|
@click="go(1)"
|
|
273
273
|
>
|
|
274
|
-
<UIcon name="i-lucide-chevron-right" class="h-5 w-5" />
|
|
274
|
+
<UIcon name="i-lucide-chevron-right" class="h-5 w-5 rtl:-scale-x-100" />
|
|
275
275
|
</button>
|
|
276
276
|
</div>
|
|
277
277
|
</div>
|
|
@@ -208,7 +208,7 @@ function onRefInput(e: Event) {
|
|
|
208
208
|
class="w-full cursor-zoom-in"
|
|
209
209
|
/>
|
|
210
210
|
<span
|
|
211
|
-
class="absolute bottom-1
|
|
211
|
+
class="absolute bottom-1 end-1 rounded bg-slate-950/80 px-1.5 py-0.5 text-[10px] text-slate-300 opacity-0 group-hover:opacity-100"
|
|
212
212
|
@click.stop="refInput?.click()"
|
|
213
213
|
>
|
|
214
214
|
{{ t('media.compare.replace') }}
|
|
@@ -282,6 +282,11 @@ function onRefInput(e: Event) {
|
|
|
282
282
|
class="absolute inset-0 block h-full w-full object-contain"
|
|
283
283
|
/>
|
|
284
284
|
</div>
|
|
285
|
+
<!-- The split geometry is physical and unmirrored (the divider is positioned by a
|
|
286
|
+
`left` percent, the clip-path insets from the right, and the pointer math reads
|
|
287
|
+
`clientX - rect.left`), so the handle and the corner labels stay PHYSICAL too.
|
|
288
|
+
Logical (`start-`/`end-`) here would flip the labels under RTL while the image
|
|
289
|
+
regions stayed put, mislabeling actual vs reference. -->
|
|
285
290
|
<div class="absolute inset-y-0 w-0.5 bg-amber-400" :style="{ left: `${splitPct}%` }">
|
|
286
291
|
<span
|
|
287
292
|
class="absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-amber-400 text-slate-950 shadow"
|
|
@@ -61,14 +61,18 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
61
61
|
})
|
|
62
62
|
}}
|
|
63
63
|
</span>
|
|
64
|
-
<div class="
|
|
64
|
+
<div class="ms-auto flex items-center gap-1">
|
|
65
65
|
<UBadge v-if="m.errors > 0" color="error" variant="subtle" size="sm">
|
|
66
66
|
{{ t('observability.metricsBar.errors', { count: m.errors }, m.errors) }}
|
|
67
67
|
</UBadge>
|
|
68
68
|
<UBadge v-if="m.warnings > 0" color="warning" variant="subtle" size="sm">
|
|
69
69
|
{{ t('observability.metricsBar.warnings', { count: m.warnings }, m.warnings) }}
|
|
70
70
|
</UBadge>
|
|
71
|
-
<UIcon
|
|
71
|
+
<UIcon
|
|
72
|
+
v-if="clickable"
|
|
73
|
+
name="i-lucide-chevron-right"
|
|
74
|
+
class="h-3.5 w-3.5 text-slate-600 rtl:-scale-x-100"
|
|
75
|
+
/>
|
|
72
76
|
</div>
|
|
73
77
|
</div>
|
|
74
78
|
|
|
@@ -50,7 +50,7 @@ function toggle(id: string) {
|
|
|
50
50
|
<section v-for="g in groups" :key="g.id">
|
|
51
51
|
<button
|
|
52
52
|
type="button"
|
|
53
|
-
class="flex w-full items-center gap-1.5 rounded px-1 py-1 text-
|
|
53
|
+
class="flex w-full items-center gap-1.5 rounded px-1 py-1 text-start text-[11px] font-semibold uppercase tracking-wide text-slate-400 transition hover:text-slate-200"
|
|
54
54
|
@click="toggle(g.id)"
|
|
55
55
|
>
|
|
56
56
|
<UIcon
|
|
@@ -58,14 +58,14 @@ function toggle(id: string) {
|
|
|
58
58
|
class="h-3.5 w-3.5 shrink-0"
|
|
59
59
|
/>
|
|
60
60
|
<span>{{ g.label }}</span>
|
|
61
|
-
<span class="
|
|
61
|
+
<span class="ms-auto text-slate-600">{{ g.agents.length }}</span>
|
|
62
62
|
</button>
|
|
63
63
|
<div v-if="!isCollapsed(g.id)" class="mt-1 space-y-1.5">
|
|
64
64
|
<button
|
|
65
65
|
v-for="a in g.agents"
|
|
66
66
|
:key="a.kind"
|
|
67
67
|
type="button"
|
|
68
|
-
class="flex w-full items-center gap-2.5 rounded-lg border border-slate-700 bg-slate-800/60 p-2 text-
|
|
68
|
+
class="flex w-full items-center gap-2.5 rounded-lg border border-slate-700 bg-slate-800/60 p-2 text-start transition hover:border-slate-500 hover:bg-slate-800"
|
|
69
69
|
:title="a.description"
|
|
70
70
|
@click="$emit('add', a.kind)"
|
|
71
71
|
>
|
|
@@ -79,7 +79,7 @@ function toggle(id: string) {
|
|
|
79
79
|
<div class="text-xs font-semibold text-slate-100">{{ a.label }}</div>
|
|
80
80
|
<div class="truncate text-[10px] text-slate-400">{{ a.description }}</div>
|
|
81
81
|
</div>
|
|
82
|
-
<UIcon name="i-lucide-plus" class="
|
|
82
|
+
<UIcon name="i-lucide-plus" class="ms-auto h-4 w-4 shrink-0 text-slate-500" />
|
|
83
83
|
</button>
|
|
84
84
|
</div>
|
|
85
85
|
</section>
|
|
@@ -185,7 +185,7 @@ async function copyOutput() {
|
|
|
185
185
|
<!-- ToC sidebar (only meaningful when there are prose headings) -->
|
|
186
186
|
<aside
|
|
187
187
|
v-if="outline.hasToc"
|
|
188
|
-
class="hidden w-72 shrink-0 flex-col border-
|
|
188
|
+
class="hidden w-72 shrink-0 flex-col border-e border-slate-800 bg-slate-900/60 md:flex"
|
|
189
189
|
>
|
|
190
190
|
<div class="border-b border-slate-800 px-4 py-3">
|
|
191
191
|
<div class="text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
@@ -194,7 +194,7 @@ async function copyOutput() {
|
|
|
194
194
|
</div>
|
|
195
195
|
<nav class="flex-1 space-y-0.5 overflow-auto px-2 py-3">
|
|
196
196
|
<button
|
|
197
|
-
class="block w-full truncate rounded-md px-2 py-1 text-
|
|
197
|
+
class="block w-full truncate rounded-md px-2 py-1 text-start text-[13px] transition"
|
|
198
198
|
:class="
|
|
199
199
|
activeId === 'step-details'
|
|
200
200
|
? 'bg-indigo-500/15 font-medium text-indigo-200'
|
|
@@ -207,7 +207,7 @@ async function copyOutput() {
|
|
|
207
207
|
<button
|
|
208
208
|
v-for="s in tocSections"
|
|
209
209
|
:key="s.id"
|
|
210
|
-
class="block w-full truncate rounded-md px-2 py-1 text-
|
|
210
|
+
class="block w-full truncate rounded-md px-2 py-1 text-start text-[13px] transition"
|
|
211
211
|
:class="
|
|
212
212
|
activeId === s.id
|
|
213
213
|
? 'bg-indigo-500/15 font-medium text-indigo-200'
|
|
@@ -235,15 +235,15 @@ async function copyOutput() {
|
|
|
235
235
|
<h1 class="truncate text-base font-semibold text-white">{{ agent.label }}</h1>
|
|
236
236
|
<p v-if="block" class="truncate text-xs text-slate-500">{{ block.title }}</p>
|
|
237
237
|
</div>
|
|
238
|
-
<div class="
|
|
238
|
+
<div class="ms-auto flex items-center gap-1.5">
|
|
239
239
|
<UBadge
|
|
240
240
|
v-if="approvalPending && !companionExceeded"
|
|
241
241
|
color="warning"
|
|
242
242
|
variant="subtle"
|
|
243
243
|
size="sm"
|
|
244
|
-
class="
|
|
244
|
+
class="me-1"
|
|
245
245
|
>
|
|
246
|
-
<UIcon name="i-lucide-shield-check" class="
|
|
246
|
+
<UIcon name="i-lucide-shield-check" class="me-1 h-3 w-3" />
|
|
247
247
|
{{ t('panels.stepDetail.approvalRequired') }}
|
|
248
248
|
</UBadge>
|
|
249
249
|
<UBadge
|
|
@@ -251,9 +251,9 @@ async function copyOutput() {
|
|
|
251
251
|
color="warning"
|
|
252
252
|
variant="subtle"
|
|
253
253
|
size="sm"
|
|
254
|
-
class="
|
|
254
|
+
class="me-1"
|
|
255
255
|
>
|
|
256
|
-
<UIcon name="i-lucide-alert-triangle" class="
|
|
256
|
+
<UIcon name="i-lucide-alert-triangle" class="me-1 h-3 w-3" />
|
|
257
257
|
{{ t('panels.stepDetail.decisionRequired') }}
|
|
258
258
|
</UBadge>
|
|
259
259
|
<UButton
|
|
@@ -403,7 +403,7 @@ async function copyOutput() {
|
|
|
403
403
|
>
|
|
404
404
|
<button
|
|
405
405
|
v-if="s.depth > 0"
|
|
406
|
-
class="group flex w-full items-center gap-2 rounded-md py-1 text-
|
|
406
|
+
class="group flex w-full items-center gap-2 rounded-md py-1 text-start transition hover:text-white"
|
|
407
407
|
@click="toggle(s.id)"
|
|
408
408
|
>
|
|
409
409
|
<UIcon
|
|
@@ -422,7 +422,7 @@ async function copyOutput() {
|
|
|
422
422
|
v-show="!collapsed[s.id]"
|
|
423
423
|
class="reader-prose mt-1 text-[13px] leading-relaxed text-slate-300"
|
|
424
424
|
:class="[
|
|
425
|
-
s.depth > 0 ? '
|
|
425
|
+
s.depth > 0 ? 'ps-6' : '',
|
|
426
426
|
approvalPending && !editing && !companionExceeded ? 'review-mode' : '',
|
|
427
427
|
]"
|
|
428
428
|
@click="onProseClick"
|
|
@@ -442,11 +442,11 @@ async function copyOutput() {
|
|
|
442
442
|
</div>
|
|
443
443
|
|
|
444
444
|
<!-- review rail (approval mode): per-block comments + overall feedback +
|
|
445
|
-
Approve / Request changes / Reject. A
|
|
445
|
+
Approve / Request changes / Reject. A end-side rail on wide screens; a
|
|
446
446
|
bottom sheet (still reachable) below lg, so the gate is always actionable. -->
|
|
447
447
|
<aside
|
|
448
448
|
v-if="approvalPending && !companionExceeded"
|
|
449
|
-
class="absolute inset-x-0 bottom-0 z-10 flex max-h-[70dvh] flex-col rounded-t-2xl border-t border-slate-700 bg-slate-900/95 shadow-2xl backdrop-blur lg:static lg:inset-auto lg:z-auto lg:max-h-none lg:w-96 lg:shrink-0 lg:rounded-none lg:border-
|
|
449
|
+
class="absolute inset-x-0 bottom-0 z-10 flex max-h-[70dvh] flex-col rounded-t-2xl border-t border-slate-700 bg-slate-900/95 shadow-2xl backdrop-blur lg:static lg:inset-auto lg:z-auto lg:max-h-none lg:w-96 lg:shrink-0 lg:rounded-none lg:border-s lg:border-t-0 lg:border-slate-800 lg:bg-slate-900/60 lg:shadow-none lg:backdrop-blur-none"
|
|
450
450
|
>
|
|
451
451
|
<div class="border-b border-slate-800 px-4 py-3">
|
|
452
452
|
<div class="text-[11px] font-semibold uppercase tracking-wide text-amber-400">
|
|
@@ -122,7 +122,7 @@ const customJson = computed<string | null>(() => {
|
|
|
122
122
|
|
|
123
123
|
<!-- Sidebar: shared run metadata + observability rollup -->
|
|
124
124
|
<aside
|
|
125
|
-
class="hidden w-60 shrink-0 flex-col gap-4 border-
|
|
125
|
+
class="hidden w-60 shrink-0 flex-col gap-4 border-s border-slate-800 bg-slate-900/50 px-4 py-4 lg:flex"
|
|
126
126
|
>
|
|
127
127
|
<StepRunMeta
|
|
128
128
|
v-if="step"
|
|
@@ -207,7 +207,7 @@ const showOriginalDescription = ref(false)
|
|
|
207
207
|
<div
|
|
208
208
|
v-if="block && statusMeta && typeMeta"
|
|
209
209
|
data-testid="inspector-panel"
|
|
210
|
-
class="fixed inset-x-0 bottom-0 z-20 overflow-hidden rounded-t-2xl border border-slate-700 bg-slate-900/95 shadow-2xl backdrop-blur lg:absolute lg:inset-x-auto lg:bottom-auto lg:
|
|
210
|
+
class="fixed inset-x-0 bottom-0 z-20 overflow-hidden rounded-t-2xl border border-slate-700 bg-slate-900/95 shadow-2xl backdrop-blur lg:absolute lg:inset-x-auto lg:bottom-auto lg:end-4 lg:top-4 lg:w-80 lg:rounded-2xl"
|
|
211
211
|
>
|
|
212
212
|
<div class="h-1.5 w-full" :style="{ backgroundColor: statusMeta.color }" />
|
|
213
213
|
<!-- A tall task (execution steps + scenarios + docs) can overflow the
|
|
@@ -487,7 +487,7 @@ const showOriginalDescription = ref(false)
|
|
|
487
487
|
variant="ghost"
|
|
488
488
|
size="sm"
|
|
489
489
|
icon="i-lucide-trash-2"
|
|
490
|
-
class="
|
|
490
|
+
class="ms-auto"
|
|
491
491
|
:title="deleteLabel"
|
|
492
492
|
@click="remove"
|
|
493
493
|
>
|
|
@@ -158,8 +158,8 @@ function exportJson() {
|
|
|
158
158
|
{{ block.title }} · {{ instance?.pipelineName }}
|
|
159
159
|
</p>
|
|
160
160
|
</div>
|
|
161
|
-
<div class="
|
|
162
|
-
<div class="
|
|
161
|
+
<div class="ms-auto flex items-center gap-1.5">
|
|
162
|
+
<div class="me-1 flex rounded-lg border border-slate-800 p-0.5 text-[12px]">
|
|
163
163
|
<button
|
|
164
164
|
class="rounded-md px-2.5 py-1 transition"
|
|
165
165
|
:class="
|
|
@@ -304,7 +304,7 @@ function exportJson() {
|
|
|
304
304
|
:class="!c.ok ? 'border-rose-900/60' : ''"
|
|
305
305
|
>
|
|
306
306
|
<button
|
|
307
|
-
class="flex w-full items-center gap-3 px-4 py-2.5 text-
|
|
307
|
+
class="flex w-full items-center gap-3 px-4 py-2.5 text-start transition hover:bg-slate-900/70"
|
|
308
308
|
@click="toggle(c)"
|
|
309
309
|
>
|
|
310
310
|
<UIcon
|
|
@@ -325,7 +325,7 @@ function exportJson() {
|
|
|
325
325
|
{{ c.provider }}:{{ c.model }}
|
|
326
326
|
</span>
|
|
327
327
|
<div
|
|
328
|
-
class="
|
|
328
|
+
class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-slate-400"
|
|
329
329
|
>
|
|
330
330
|
<span
|
|
331
331
|
:title="
|
|
@@ -456,7 +456,7 @@ function exportJson() {
|
|
|
456
456
|
class="overflow-hidden rounded-xl border border-slate-800 bg-slate-900/40"
|
|
457
457
|
>
|
|
458
458
|
<button
|
|
459
|
-
class="flex w-full items-center gap-3 px-4 py-2.5 text-
|
|
459
|
+
class="flex w-full items-center gap-3 px-4 py-2.5 text-start transition hover:bg-slate-900/70"
|
|
460
460
|
@click="toggleCtx(s)"
|
|
461
461
|
>
|
|
462
462
|
<UIcon
|
|
@@ -474,7 +474,7 @@ function exportJson() {
|
|
|
474
474
|
{{ s.model }}
|
|
475
475
|
</span>
|
|
476
476
|
<div
|
|
477
|
-
class="
|
|
477
|
+
class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-slate-400"
|
|
478
478
|
>
|
|
479
479
|
<span :title="t('observability.context.injectedFiles')">{{
|
|
480
480
|
t('observability.context.filesCount', { count: s.contextFiles.length })
|
|
@@ -275,7 +275,7 @@ async function copyRunId() {
|
|
|
275
275
|
<span :class="v.passed ? 'text-emerald-300' : 'text-amber-300'">
|
|
276
276
|
{{ pctOf(v.rating) }} {{ v.passed ? '≥' : '<' }} {{ pctOf(v.threshold) }}
|
|
277
277
|
</span>
|
|
278
|
-
<span v-if="v.feedback" class="
|
|
278
|
+
<span v-if="v.feedback" class="ms-1 text-slate-400">— {{ v.feedback }}</span>
|
|
279
279
|
</div>
|
|
280
280
|
</li>
|
|
281
281
|
</ol>
|
|
@@ -35,7 +35,7 @@ function addTask() {
|
|
|
35
35
|
>
|
|
36
36
|
<UIcon name="i-lucide-package" class="h-3.5 w-3.5 text-violet-400" />
|
|
37
37
|
<span class="truncate text-xs text-slate-200">{{ m.title }}</span>
|
|
38
|
-
<span class="
|
|
38
|
+
<span class="ms-auto text-[10px] text-slate-500">{{
|
|
39
39
|
t(
|
|
40
40
|
'inspector.container.taskCount',
|
|
41
41
|
{ count: board.tasksOf(m.id).length },
|
|
@@ -71,7 +71,7 @@ function addTask() {
|
|
|
71
71
|
:style="{ backgroundColor: STATUS_META[task.status].color }"
|
|
72
72
|
/>
|
|
73
73
|
<span class="truncate text-xs text-slate-200">{{ task.title }}</span>
|
|
74
|
-
<span class="
|
|
74
|
+
<span class="ms-auto text-[10px] text-slate-500">{{
|
|
75
75
|
STATUS_META[task.status].label
|
|
76
76
|
}}</span>
|
|
77
77
|
</li>
|
|
@@ -69,7 +69,7 @@ const groups = computed(() => {
|
|
|
69
69
|
<UIcon name="i-lucide-box" class="h-3 w-3 text-slate-500" />
|
|
70
70
|
{{ group.service?.title ?? t('inspector.epicChildren.unassigned') }}
|
|
71
71
|
</div>
|
|
72
|
-
<div v-for="(mod, mi) in [...group.modules.values()]" :key="mi" class="
|
|
72
|
+
<div v-for="(mod, mi) in [...group.modules.values()]" :key="mi" class="ps-1">
|
|
73
73
|
<div v-if="mod.module" class="text-[10px] uppercase tracking-wide text-slate-500">
|
|
74
74
|
{{ mod.module.title }}
|
|
75
75
|
</div>
|
|
@@ -77,7 +77,7 @@ const groups = computed(() => {
|
|
|
77
77
|
v-for="task in mod.tasks"
|
|
78
78
|
:key="task.id"
|
|
79
79
|
type="button"
|
|
80
|
-
class="flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-
|
|
80
|
+
class="flex w-full items-center gap-1.5 rounded px-1 py-0.5 text-start text-xs text-slate-200 hover:bg-slate-800"
|
|
81
81
|
@click="ui.select(task.id)"
|
|
82
82
|
>
|
|
83
83
|
<span
|
|
@@ -85,7 +85,7 @@ const groups = computed(() => {
|
|
|
85
85
|
:style="{ backgroundColor: STATUS_META[task.status].color }"
|
|
86
86
|
/>
|
|
87
87
|
<span class="truncate">{{ task.title }}</span>
|
|
88
|
-
<span class="
|
|
88
|
+
<span class="ms-auto shrink-0 text-[10px] text-slate-500">
|
|
89
89
|
{{ STATUS_META[task.status].label }}
|
|
90
90
|
</span>
|
|
91
91
|
</button>
|
|
@@ -212,7 +212,7 @@ function fmtTime(ms: number) {
|
|
|
212
212
|
{{ runStatusLabel(run.status) }}
|
|
213
213
|
</span>
|
|
214
214
|
<span class="truncate text-slate-500">{{ fmtTime(run.startedAt) }}</span>
|
|
215
|
-
<span v-if="run.outcome" class="
|
|
215
|
+
<span v-if="run.outcome" class="ms-auto truncate text-slate-500">{{ run.outcome }}</span>
|
|
216
216
|
</div>
|
|
217
217
|
</div>
|
|
218
218
|
</div>
|
|
@@ -99,7 +99,7 @@ function removeFragment(id: string) {
|
|
|
99
99
|
:title="f.summary"
|
|
100
100
|
@click="removeFragment(f.id)"
|
|
101
101
|
>
|
|
102
|
-
{{ f.title }}<UIcon name="i-lucide-x" class="
|
|
102
|
+
{{ f.title }}<UIcon name="i-lucide-x" class="ms-0.5 h-3 w-3" />
|
|
103
103
|
</UBadge>
|
|
104
104
|
</div>
|
|
105
105
|
<div v-else class="text-[11px] text-slate-500">
|
|
@@ -222,7 +222,7 @@ const missingInfra = computed(() => !noInfra.value && composePath.value.trim() =
|
|
|
222
222
|
<div class="border-t border-slate-800 pt-2">
|
|
223
223
|
<button
|
|
224
224
|
type="button"
|
|
225
|
-
class="flex w-full items-center gap-1.5 text-
|
|
225
|
+
class="flex w-full items-center gap-1.5 text-start text-[11px] font-semibold uppercase tracking-wide text-slate-500 hover:text-slate-300"
|
|
226
226
|
@click="showProvisioning = !showProvisioning"
|
|
227
227
|
>
|
|
228
228
|
<UIcon
|
|
@@ -64,7 +64,7 @@ function removeDep(depId: string) {
|
|
|
64
64
|
@click="removeDep(d.id)"
|
|
65
65
|
>
|
|
66
66
|
{{ label(d) }}
|
|
67
|
-
<UIcon name="i-lucide-x" class="
|
|
67
|
+
<UIcon name="i-lucide-x" class="ms-0.5 h-3 w-3" />
|
|
68
68
|
</UBadge>
|
|
69
69
|
</div>
|
|
70
70
|
<div v-else class="text-[11px] text-slate-500">{{ t('inspector.dependencies.empty') }}</div>
|
|
@@ -45,7 +45,7 @@ function barClass(n: number): string {
|
|
|
45
45
|
:style="{ width: `${Math.round(estimate[axis.key] * 100)}%` }"
|
|
46
46
|
/>
|
|
47
47
|
</div>
|
|
48
|
-
<span class="w-9 shrink-0 text-
|
|
48
|
+
<span class="w-9 shrink-0 text-end text-xs tabular-nums text-slate-300">{{
|
|
49
49
|
n(estimate[axis.key], { key: 'percent' })
|
|
50
50
|
}}</span>
|
|
51
51
|
</div>
|