@cat-factory/app 0.308.0 → 0.310.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/README.md +32 -2
- package/app/assets/css/main.css +22 -0
- package/app/assets/css/prose.css +4 -4
- package/app/assets/css/type.css +24 -0
- package/app/components/assistant/AssistantModal.vue +8 -6
- package/app/components/auth/BackendMisconfiguredScreen.vue +4 -3
- package/app/components/auth/LoginScreen.vue +40 -26
- package/app/components/auth/ResetPasswordScreen.vue +9 -4
- package/app/components/auth/UserMenu.vue +5 -4
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +48 -37
- package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
- package/app/components/binaryOutput/StoredAssetView.vue +13 -11
- package/app/components/board/AddTaskModal.vue +30 -27
- package/app/components/board/AgentFailureCard.vue +21 -18
- package/app/components/board/AgentFailureHistory.vue +18 -9
- package/app/components/board/CreateInitiativeModal.vue +7 -6
- package/app/components/board/FailureDetail.vue +22 -12
- package/app/components/board/FailureHistoryList.vue +5 -5
- package/app/components/board/RecurringPipelineModal.vue +12 -11
- package/app/components/board/ReviewFrictionDialog.vue +8 -6
- package/app/components/board/StepExecutionHistory.vue +8 -8
- package/app/components/board/nodes/AgentChip.vue +1 -1
- package/app/components/board/nodes/BlockNode.vue +25 -24
- package/app/components/board/nodes/DecisionBadge.vue +4 -3
- package/app/components/board/nodes/EpicNode.vue +4 -4
- package/app/components/board/nodes/FrameSwimlanes.vue +8 -10
- package/app/components/board/nodes/InitiativeCard.vue +4 -4
- package/app/components/board/nodes/LaneGroup.vue +3 -5
- package/app/components/board/nodes/TaskCard.vue +20 -15
- package/app/components/board/nodes/TaskLane.vue +3 -3
- package/app/components/board/nodes/TaskPipelineMini.vue +21 -18
- package/app/components/bootstrap/AdoptionReviewModal.vue +36 -26
- package/app/components/bootstrap/BootstrapModal.vue +14 -13
- package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
- package/app/components/brainstorm/BrainstormWindow.vue +13 -10
- package/app/components/bugFishing/BugFishingWindow.vue +81 -58
- package/app/components/clarity/ClarityReviewWindow.vue +13 -10
- package/app/components/common/AsyncViewError.vue +1 -1
- package/app/components/common/ClarificationItem.vue +6 -6
- package/app/components/common/CopyButton.vue +12 -11
- package/app/components/common/DescriptorFields.vue +1 -1
- package/app/components/common/EmptyState.vue +1 -1
- package/app/components/common/IconButton.vue +34 -9
- package/app/components/common/InterviewGateNotice.vue +4 -4
- package/app/components/common/MarkdownProse.vue +8 -2
- package/app/components/common/SectionLabel.vue +38 -0
- package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
- package/app/components/context/ContextAttachmentFields.vue +32 -20
- package/app/components/docs/DocInterviewWindow.vue +10 -9
- package/app/components/documents/ContextDocumentPicker.vue +22 -21
- package/app/components/documents/DocumentImportModal.vue +7 -5
- package/app/components/documents/DocumentOriginLink.vue +12 -9
- package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
- package/app/components/documents/DocumentSyncState.vue +4 -4
- package/app/components/documents/DocumentTemplatesModal.vue +5 -4
- package/app/components/documents/RepoContextDocPicker.vue +7 -9
- package/app/components/documents/StartFromDesignModal.vue +4 -4
- package/app/components/documents/TaskContextDocs.vue +1 -1
- package/app/components/environments/EnvSetupStepper.vue +3 -3
- package/app/components/environments/EnvironmentStatusPanel.vue +15 -13
- package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
- package/app/components/environments/steps/EnvReviewStep.vue +23 -22
- package/app/components/environments/steps/EnvSaveStep.vue +5 -5
- package/app/components/focus/BlockFocusView.vue +11 -10
- package/app/components/followUp/FollowUpWindow.vue +18 -15
- package/app/components/forkDecision/ForkDecisionWindow.vue +85 -97
- package/app/components/foundational/FoundationalContractSummary.vue +2 -2
- package/app/components/foundational/FoundationalServiceCatalogList.vue +6 -5
- package/app/components/foundational/FoundationalServiceRegistry.vue +10 -9
- package/app/components/foundational/FoundationalServiceSources.vue +7 -6
- package/app/components/foundational/FoundationalSuppressions.vue +2 -2
- package/app/components/fragments/FragmentLibraryManager.vue +8 -7
- package/app/components/fragments/FragmentSelector.vue +22 -20
- package/app/components/gates/GateFailingCheckList.vue +7 -6
- package/app/components/gates/GateResultView.vue +55 -49
- package/app/components/github/AddServiceFromRepoModal.vue +16 -11
- package/app/components/github/BranchProtectionPreflight.vue +5 -5
- package/app/components/github/GitHubConnect.vue +5 -3
- package/app/components/github/GitHubOnboarding.vue +7 -2
- package/app/components/github/GitHubPanel.vue +23 -19
- package/app/components/github/RepoTreeBrowser.vue +16 -13
- package/app/components/humanTest/HumanTestWindow.vue +29 -24
- package/app/components/initiative/InitiativePlanNotice.vue +3 -3
- package/app/components/initiative/InitiativePlanReview.vue +46 -38
- package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
- package/app/components/initiative/InitiativeTrackerWindow.vue +213 -165
- package/app/components/judge/JudgeResultView.vue +28 -27
- package/app/components/kaizen/KaizenPanel.vue +70 -56
- package/app/components/kaizen/KaizenStepStatus.vue +7 -6
- package/app/components/layout/AccountAuditLog.vue +1 -1
- package/app/components/layout/AccountDeploymentSettings.vue +10 -10
- package/app/components/layout/AccountFailureKindRules.vue +13 -13
- package/app/components/layout/AccountFoundationalSettings.vue +1 -1
- package/app/components/layout/AccountFragmentSettings.vue +1 -1
- package/app/components/layout/AccountModelPolicySettings.vue +7 -7
- package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
- package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
- package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
- package/app/components/layout/AccountSkillSettings.vue +1 -1
- package/app/components/layout/AccountTeamSettings.vue +13 -9
- package/app/components/layout/AiProvidersBanner.vue +1 -1
- package/app/components/layout/AppearanceSwitcher.vue +5 -4
- package/app/components/layout/BoardSwitcher.vue +13 -10
- package/app/components/layout/BoardToolbar.vue +10 -5
- package/app/components/layout/CommandBar.vue +8 -5
- package/app/components/layout/DefaultTestEnvBanner.vue +6 -5
- package/app/components/layout/IntegrationsHub.vue +12 -9
- package/app/components/layout/LanguageSwitcher.vue +5 -4
- package/app/components/layout/ModelProvidersHub.vue +10 -7
- package/app/components/layout/NotificationsInbox.vue +47 -36
- package/app/components/layout/PersonalSetupModal.vue +9 -6
- package/app/components/layout/RolePrompt.vue +5 -4
- package/app/components/layout/SideBar.vue +7 -8
- package/app/components/layout/SpendWarningBanner.vue +3 -3
- package/app/components/layout/TranslationWarningBanner.vue +5 -4
- package/app/components/layout/UiModeSwitcher.vue +15 -12
- package/app/components/layout/UiRoleSwitcher.vue +10 -8
- package/app/components/layout/WorkspaceMembersSettings.vue +2 -2
- package/app/components/media/ArtifactLightbox.vue +74 -44
- package/app/components/media/ImageCompare.vue +80 -85
- package/app/components/merge/MergeEffortChips.vue +4 -6
- package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
- package/app/components/observability/OutcomeFilterChips.vue +6 -5
- package/app/components/observability/RunFailureSummary.vue +22 -23
- package/app/components/observability/StepMetricsBar.vue +9 -8
- package/app/components/observability/StepModelActivity.vue +8 -5
- package/app/components/observability/ToolCallList.vue +19 -20
- package/app/components/outcome/OutcomeSummaryWindow.vue +48 -46
- package/app/components/palettes/AgentPalette.vue +21 -15
- package/app/components/palettes/AgentTierSelect.vue +1 -1
- package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
- package/app/components/panels/AgentStepDetail.vue +57 -49
- package/app/components/panels/AttemptEntryHeader.vue +2 -2
- package/app/components/panels/DecisionModal.vue +1 -1
- package/app/components/panels/GenericStructuredResultView.vue +6 -5
- package/app/components/panels/InspectorPanel.vue +15 -13
- package/app/components/panels/MergerResultView.vue +10 -9
- package/app/components/panels/ObservabilityPanel.vue +211 -186
- package/app/components/panels/OperatorDashboardPanel.vue +124 -115
- package/app/components/panels/ReportsPanel.vue +87 -83
- package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
- package/app/components/panels/ResultWindowShell.vue +152 -137
- package/app/components/panels/RunDetailLoadState.vue +1 -1
- package/app/components/panels/StepContainerStatus.vue +17 -16
- package/app/components/panels/StepDelegatedStatus.vue +24 -21
- package/app/components/panels/StepEffortReport.vue +12 -17
- package/app/components/panels/StepFragmentAdherence.vue +9 -10
- package/app/components/panels/StepMetadataCard.vue +41 -43
- package/app/components/panels/StepReproductionReport.vue +18 -20
- package/app/components/panels/StepRestartControl.vue +3 -2
- package/app/components/panels/StepRunMeta.vue +27 -26
- package/app/components/panels/StepTestReport.vue +16 -15
- package/app/components/panels/StepToolServers.vue +7 -8
- package/app/components/panels/StepValidationReport.vue +5 -5
- package/app/components/panels/inspector/ContainerSummary.vue +4 -4
- package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
- package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
- package/app/components/panels/inspector/EpicChildren.vue +12 -10
- package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
- package/app/components/panels/inspector/FrontendConfig.vue +29 -36
- package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
- package/app/components/panels/inspector/InspectorSection.vue +25 -17
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
- package/app/components/panels/inspector/ServiceConnections.vue +5 -4
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
- package/app/components/panels/inspector/ServiceSelfTests.vue +9 -13
- package/app/components/panels/inspector/ServiceTestConfig.vue +46 -49
- package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
- package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
- package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
- package/app/components/panels/inspector/TaskDependencies.vue +1 -1
- package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
- package/app/components/panels/inspector/TaskExecution.vue +18 -16
- package/app/components/panels/inspector/TaskRunSettings.vue +45 -44
- package/app/components/panels/inspector/TaskStructure.vue +5 -4
- package/app/components/pipeline/AgentPromptEditor.vue +15 -14
- package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
- package/app/components/pipeline/EstimateThresholdFields.vue +14 -11
- package/app/components/pipeline/GateConfigFields.vue +19 -23
- package/app/components/pipeline/IterationCapPrompt.vue +1 -1
- package/app/components/pipeline/PipelineBuilder.vue +113 -99
- package/app/components/pipeline/PipelineHealthModal.vue +7 -7
- package/app/components/pipeline/PipelinePicker.vue +11 -9
- package/app/components/pipeline/PipelinePreview.vue +6 -7
- package/app/components/pipeline/PipelineProgress.vue +49 -45
- package/app/components/prReview/PrReviewWindow.vue +87 -65
- package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
- package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
- package/app/components/providers/ApiKeysSection.vue +11 -9
- package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
- package/app/components/providers/VendorCredentialsModal.vue +5 -4
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
- package/app/components/ralph/RalphLoopResultView.vue +29 -29
- package/app/components/requirements/RequirementsReviewWindow.vue +22 -17
- package/app/components/riskPolicy/RiskPolicyPicker.vue +13 -11
- package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
- package/app/components/sandbox/SandboxPanel.vue +93 -73
- package/app/components/settings/ApiTokensPanel.vue +1 -1
- package/app/components/settings/BudgetSettings.vue +18 -17
- package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
- package/app/components/settings/CloudflareHandlerSection.vue +44 -41
- package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
- package/app/components/settings/ConnectionTestVerdict.vue +1 -1
- package/app/components/settings/ConsensusGroupsSection.vue +58 -47
- package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
- package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
- package/app/components/settings/InfraHandlersConfigurator.vue +26 -24
- package/app/components/settings/InfrastructureBackendPicker.vue +18 -18
- package/app/components/settings/IssueTrackerPanel.vue +30 -21
- package/app/components/settings/KubernetesEngineForm.vue +9 -8
- package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
- package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
- package/app/components/settings/LocalModelEndpointsPanel.vue +13 -11
- package/app/components/settings/MergeClassRulesEditor.vue +6 -5
- package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
- package/app/components/settings/ModelConfigurationPanel.vue +17 -19
- package/app/components/settings/ModelPresetHealthModal.vue +3 -3
- package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
- package/app/components/settings/OpenRouterCatalogPanel.vue +10 -8
- package/app/components/settings/PackageRegistriesPanel.vue +4 -4
- package/app/components/settings/ProviderConnectionTab.vue +5 -4
- package/app/components/settings/ProviderManifestEditor.vue +9 -8
- package/app/components/settings/ProviderPreferenceEditor.vue +13 -13
- package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
- package/app/components/settings/RiskPolicyEditorRow.vue +21 -19
- package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
- package/app/components/settings/RiskPolicyPanel.vue +11 -13
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +15 -12
- package/app/components/settings/SharedStacksPanel.vue +5 -5
- package/app/components/settings/TaskSourceCard.vue +2 -2
- package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
- package/app/components/settings/ToolServerChecklist.vue +22 -22
- package/app/components/settings/UsageSettings.vue +13 -13
- package/app/components/settings/UserSecretsSection.vue +4 -3
- package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
- package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
- package/app/components/skills/ReviewSkillQueue.vue +12 -10
- package/app/components/skills/SkillLibraryManager.vue +9 -8
- package/app/components/slack/SlackPanel.vue +17 -12
- package/app/components/spec/ServiceSpecWindow.vue +19 -19
- package/app/components/tasks/BugHuntModal.vue +1 -1
- package/app/components/tasks/ContextIssuePicker.vue +16 -15
- package/app/components/tasks/TaskContextIssues.vue +5 -4
- package/app/components/tasks/TaskImportModal.vue +3 -2
- package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
- package/app/components/testing/TestReportWindow.vue +67 -60
- package/app/components/theme/ThemeImportModal.vue +2 -2
- package/app/components/tutorial/TutorialNudge.vue +3 -2
- package/app/components/tutorial/TutorialOverlay.vue +3 -2
- package/app/components/vcs/GitLabConnect.vue +1 -1
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +79 -54
- package/app/utils/theme/builtins.ts +7 -1
- package/i18n/locales/de.json +7 -3
- package/i18n/locales/en.json +7 -3
- package/i18n/locales/es.json +7 -3
- package/i18n/locales/fr.json +7 -3
- package/i18n/locales/he.json +7 -3
- package/i18n/locales/it.json +7 -3
- package/i18n/locales/ja.json +7 -3
- package/i18n/locales/pl.json +7 -3
- package/i18n/locales/tr.json +7 -3
- package/i18n/locales/uk.json +7 -3
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// as a drag-and-drop / click upload target (emits `uploadReference`).
|
|
10
10
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
11
11
|
import type { ArtifactBlobs } from '~/composables/useArtifactBlobs'
|
|
12
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
12
13
|
|
|
13
14
|
const props = defineProps<{
|
|
14
15
|
view: string
|
|
@@ -88,7 +89,7 @@ const diffCanvas = ref<HTMLCanvasElement | null>(null)
|
|
|
88
89
|
// there reads as "no difference", the same zero the difference composite produces, in either colour
|
|
89
90
|
// mode, so no mode-following token fits. Bound as a const so the guard's `fixed-colour-ok:` marker
|
|
90
91
|
// stays on the class string; the inline-template form gets reflowed off its own line by oxfmt.
|
|
91
|
-
const DIFF_CANVAS_CLASS = 'w-full rounded border border-default bg-black' // fixed-colour-ok: diff canvas backdrop
|
|
92
|
+
const DIFF_CANVAS_CLASS = 'w-full rounded-sm border border-default bg-black' // fixed-colour-ok: diff canvas backdrop
|
|
92
93
|
const CAP = 2000
|
|
93
94
|
// Bumped on every renderDiff entry so a render whose async work (image decode) is overtaken
|
|
94
95
|
// by a newer mode/image change bails out instead of drawing stale pixels onto the canvas.
|
|
@@ -135,56 +136,60 @@ async function renderDiff() {
|
|
|
135
136
|
watch([mode, actualUrl, refUrl], renderDiff, { immediate: true })
|
|
136
137
|
|
|
137
138
|
// --- reference upload (drag-drop + click) ---
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
//
|
|
141
|
-
// can't slip past the picker's `accept` filter.
|
|
139
|
+
// `UFileUpload` owns the picker, the drop zone and the drag state; the click-to-replace
|
|
140
|
+
// affordance calls its `open()`. The type guard stays ours: `accept` filters the PICKER, and a
|
|
141
|
+
// dropped GIF/SVG/WebP would otherwise arrive anyway.
|
|
142
142
|
const ACCEPTED = /^image\/(png|jpeg)$/
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
const pendingRef = ref<File | null>(null)
|
|
144
|
+
watch(pendingRef, (file) => {
|
|
145
145
|
if (file && ACCEPTED.test(file.type)) emit('uploadReference', file)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
function onRefInput(e: Event) {
|
|
152
|
-
pickFile((e.target as HTMLInputElement).files)
|
|
153
|
-
if (refInput.value) refInput.value.value = ''
|
|
154
|
-
}
|
|
146
|
+
// Cleared either way, so a fresh pick is a fresh file. `UFileUpload` carries `reset` for the
|
|
147
|
+
// other half of this: clearing the model alone leaves the native input holding the file it
|
|
148
|
+
// already has, and the browser fires no change event when the same one is chosen twice.
|
|
149
|
+
if (file) pendingRef.value = null
|
|
150
|
+
})
|
|
155
151
|
</script>
|
|
156
152
|
|
|
157
153
|
<template>
|
|
158
154
|
<div class="rounded-lg border border-default bg-default/60 p-3">
|
|
159
155
|
<div class="mb-2 flex items-center justify-between gap-2">
|
|
160
|
-
<h3 class="min-w-0 truncate text-
|
|
156
|
+
<h3 class="min-w-0 truncate text-xs font-semibold text-default">{{ view }}</h3>
|
|
161
157
|
<!-- Mode switch -->
|
|
162
158
|
<div
|
|
163
159
|
v-if="MODES.length > 1"
|
|
164
160
|
class="flex items-center gap-0.5 rounded-md border border-default bg-app-950/60 p-0.5"
|
|
165
161
|
>
|
|
166
|
-
<
|
|
162
|
+
<IconButton
|
|
167
163
|
v-for="m in MODES"
|
|
168
164
|
:key="m.id"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
:
|
|
165
|
+
color="neutral"
|
|
166
|
+
variant="ghost"
|
|
167
|
+
:icon="m.icon"
|
|
168
|
+
:label="m.label"
|
|
169
|
+
:aria-pressed="mode === m.id"
|
|
170
|
+
:ui="{
|
|
171
|
+
base: [
|
|
172
|
+
'rounded-sm px-1.5 py-1 text-muted hover:bg-transparent hover:text-default',
|
|
173
|
+
mode === m.id ? 'bg-elevated text-app-100' : '',
|
|
174
|
+
].join(' '),
|
|
175
|
+
leadingIcon: 'h-3.5 w-3.5',
|
|
176
|
+
}"
|
|
172
177
|
@click="mode = m.id"
|
|
173
|
-
|
|
174
|
-
<UIcon :name="m.icon" class="h-3.5 w-3.5" />
|
|
175
|
-
</button>
|
|
178
|
+
/>
|
|
176
179
|
</div>
|
|
177
180
|
</div>
|
|
178
181
|
|
|
179
182
|
<!-- SIDE BY SIDE -->
|
|
180
183
|
<div v-if="mode === 'side-by-side'" class="grid grid-cols-2 gap-3">
|
|
181
184
|
<figure class="space-y-1">
|
|
182
|
-
<figcaption class="text-
|
|
185
|
+
<figcaption class="text-3xs uppercase tracking-wide text-dimmed">
|
|
183
186
|
{{ t('media.compare.actual') }}
|
|
184
187
|
</figcaption>
|
|
185
|
-
<
|
|
188
|
+
<UButton
|
|
186
189
|
v-if="actualUrl"
|
|
187
|
-
|
|
190
|
+
color="neutral"
|
|
191
|
+
variant="ghost"
|
|
192
|
+
class="block w-full overflow-hidden rounded-sm border border-default p-0 hover:border-app-600 hover:bg-transparent"
|
|
188
193
|
@click="actualId && emit('expand', actualId)"
|
|
189
194
|
>
|
|
190
195
|
<img
|
|
@@ -192,10 +197,10 @@ function onRefInput(e: Event) {
|
|
|
192
197
|
:alt="t('media.compare.actualAlt', { view })"
|
|
193
198
|
class="w-full cursor-zoom-in"
|
|
194
199
|
/>
|
|
195
|
-
</
|
|
200
|
+
</UButton>
|
|
196
201
|
<div
|
|
197
202
|
v-else
|
|
198
|
-
class="flex h-32 items-center justify-center rounded border border-dashed border-muted text-
|
|
203
|
+
class="flex h-32 items-center justify-center rounded-sm border border-dashed border-muted text-2xs text-app-600"
|
|
199
204
|
>
|
|
200
205
|
{{
|
|
201
206
|
props.blobs.statusFor(actualId) === 'error'
|
|
@@ -208,52 +213,51 @@ function onRefInput(e: Event) {
|
|
|
208
213
|
</figure>
|
|
209
214
|
|
|
210
215
|
<figure class="space-y-1">
|
|
211
|
-
<figcaption class="text-
|
|
216
|
+
<figcaption class="text-3xs uppercase tracking-wide text-dimmed">
|
|
212
217
|
{{ t('media.compare.reference') }}
|
|
213
218
|
<span v-if="referenceOrigin === 'design'" class="text-app-warning-300/80">
|
|
214
219
|
{{ t('media.compare.fromLinkedDesign') }}
|
|
215
220
|
</span>
|
|
216
221
|
</figcaption>
|
|
217
|
-
<
|
|
218
|
-
v-
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
<UFileUpload
|
|
223
|
+
v-model="pendingRef"
|
|
224
|
+
reset
|
|
225
|
+
accept="image/png,image/jpeg"
|
|
226
|
+
:disabled="busy"
|
|
227
|
+
:preview="false"
|
|
228
|
+
:label="t('media.compare.dropHint')"
|
|
229
|
+
icon="i-lucide-image-up"
|
|
230
|
+
:ui="{ base: 'h-32 text-2xs' }"
|
|
221
231
|
>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
@dragleave.prevent="dragOver = false"
|
|
246
|
-
@drop.prevent="onDrop"
|
|
247
|
-
>
|
|
248
|
-
<UIcon name="i-lucide-image-up" class="h-5 w-5" />
|
|
249
|
-
<span>{{ t('media.compare.dropHint') }}</span>
|
|
250
|
-
</div>
|
|
232
|
+
<!-- With a reference already in place the tile IS the surface: it opens the lightbox,
|
|
233
|
+
and the hover affordance opens the picker the same drop zone would. -->
|
|
234
|
+
<template v-if="refUrl" #default="{ open }">
|
|
235
|
+
<UButton
|
|
236
|
+
variant="ghost"
|
|
237
|
+
color="neutral"
|
|
238
|
+
class="group relative block w-full overflow-hidden rounded-sm border border-default p-0 hover:border-app-600 hover:bg-transparent"
|
|
239
|
+
@click="referenceId && emit('expand', referenceId)"
|
|
240
|
+
>
|
|
241
|
+
<img
|
|
242
|
+
:src="refUrl"
|
|
243
|
+
:alt="t('media.compare.referenceAlt', { view })"
|
|
244
|
+
class="w-full cursor-zoom-in"
|
|
245
|
+
/>
|
|
246
|
+
<span
|
|
247
|
+
class="absolute bottom-1 end-1 rounded-sm bg-app-950/80 px-1.5 py-0.5 text-3xs text-toned opacity-0 group-hover:opacity-100"
|
|
248
|
+
@click.stop="open()"
|
|
249
|
+
>
|
|
250
|
+
{{ t('media.compare.replace') }}
|
|
251
|
+
</span>
|
|
252
|
+
</UButton>
|
|
253
|
+
</template>
|
|
254
|
+
</UFileUpload>
|
|
251
255
|
</figure>
|
|
252
256
|
</div>
|
|
253
257
|
|
|
254
258
|
<!-- OVERLAY (onion-skin) -->
|
|
255
259
|
<div v-else-if="mode === 'overlay'" class="space-y-2">
|
|
256
|
-
<div class="relative w-full overflow-hidden rounded border border-default">
|
|
260
|
+
<div class="relative w-full overflow-hidden rounded-sm border border-default">
|
|
257
261
|
<img :src="refUrl" :alt="t('media.compare.referenceAlt', { view })" class="w-full" />
|
|
258
262
|
<!-- object-contain so a differing aspect ratio onion-skins undistorted over the reference. -->
|
|
259
263
|
<img
|
|
@@ -263,14 +267,15 @@ function onRefInput(e: Event) {
|
|
|
263
267
|
:style="{ opacity: overlayOpacity / 100 }"
|
|
264
268
|
/>
|
|
265
269
|
</div>
|
|
266
|
-
<div class="flex items-center gap-2 text-
|
|
270
|
+
<div class="flex items-center gap-2 text-2xs uppercase tracking-wide text-muted">
|
|
267
271
|
<span>{{ t('media.compare.reference') }}</span>
|
|
268
|
-
<
|
|
269
|
-
v-model
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
272
|
+
<USlider
|
|
273
|
+
v-model="overlayOpacity"
|
|
274
|
+
:min="0"
|
|
275
|
+
:max="100"
|
|
276
|
+
color="warning"
|
|
277
|
+
size="xs"
|
|
278
|
+
class="flex-1"
|
|
274
279
|
/>
|
|
275
280
|
<span>{{ t('media.compare.actual') }}</span>
|
|
276
281
|
</div>
|
|
@@ -280,7 +285,7 @@ function onRefInput(e: Event) {
|
|
|
280
285
|
<div
|
|
281
286
|
v-else-if="mode === 'swipe'"
|
|
282
287
|
ref="swipeBox"
|
|
283
|
-
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded border border-default"
|
|
288
|
+
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded-sm border border-default"
|
|
284
289
|
@pointerdown="onSwipeDown"
|
|
285
290
|
@pointermove="moveSwipe"
|
|
286
291
|
@pointerup="onSwipeUp"
|
|
@@ -312,11 +317,11 @@ function onRefInput(e: Event) {
|
|
|
312
317
|
</span>
|
|
313
318
|
</div>
|
|
314
319
|
<span
|
|
315
|
-
class="absolute left-1 top-1 rounded bg-app-950/70 px-1 text-
|
|
320
|
+
class="absolute left-1 top-1 rounded-sm bg-app-950/70 px-1 text-3xs uppercase text-toned"
|
|
316
321
|
>{{ t('media.compare.actual') }}</span
|
|
317
322
|
>
|
|
318
323
|
<span
|
|
319
|
-
class="absolute right-1 top-1 rounded bg-app-950/70 px-1 text-
|
|
324
|
+
class="absolute right-1 top-1 rounded-sm bg-app-950/70 px-1 text-3xs uppercase text-toned"
|
|
320
325
|
>{{ t('media.compare.reference') }}</span
|
|
321
326
|
>
|
|
322
327
|
</div>
|
|
@@ -324,17 +329,7 @@ function onRefInput(e: Event) {
|
|
|
324
329
|
<!-- DIFF (canvas) -->
|
|
325
330
|
<div v-else-if="mode === 'diff'" class="space-y-1">
|
|
326
331
|
<canvas ref="diffCanvas" :class="DIFF_CANVAS_CLASS" />
|
|
327
|
-
<p class="text-
|
|
332
|
+
<p class="text-3xs text-dimmed">{{ t('media.compare.diffHint') }}</p>
|
|
328
333
|
</div>
|
|
329
|
-
|
|
330
|
-
<!-- Hidden file input shared by replace/drop zone -->
|
|
331
|
-
<input
|
|
332
|
-
ref="refInput"
|
|
333
|
-
type="file"
|
|
334
|
-
accept="image/png,image/jpeg"
|
|
335
|
-
class="hidden"
|
|
336
|
-
:disabled="busy"
|
|
337
|
-
@change="onRefInput"
|
|
338
|
-
/>
|
|
339
334
|
</div>
|
|
340
335
|
</template>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { computed } from 'vue'
|
|
11
11
|
import { REVIEW_EFFORTS } from '@cat-factory/contracts'
|
|
12
12
|
import type { ChangeClass, MergeClassRollup, ReviewEffort } from '~/types/merge'
|
|
13
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
13
14
|
|
|
14
15
|
const props = defineProps<{
|
|
15
16
|
/** The currently picked effort, or null for "not chosen". */
|
|
@@ -87,12 +88,9 @@ function pick(effort: ReviewEffort) {
|
|
|
87
88
|
<template>
|
|
88
89
|
<div data-testid="merge-effort-chips" class="mt-2">
|
|
89
90
|
<div class="flex items-center gap-1.5">
|
|
90
|
-
<span
|
|
91
|
-
class="text-[10px] uppercase tracking-wide text-dimmed"
|
|
92
|
-
:title="t('merge.effort.promptHint')"
|
|
93
|
-
>
|
|
91
|
+
<SectionLabel as="span" :title="t('merge.effort.promptHint')">
|
|
94
92
|
{{ t('merge.effort.prompt') }}
|
|
95
|
-
</
|
|
93
|
+
</SectionLabel>
|
|
96
94
|
<UBadge
|
|
97
95
|
v-if="classLabel"
|
|
98
96
|
data-testid="merge-effort-class"
|
|
@@ -119,7 +117,7 @@ function pick(effort: ReviewEffort) {
|
|
|
119
117
|
{{ chip.label }}
|
|
120
118
|
</UButton>
|
|
121
119
|
</div>
|
|
122
|
-
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-
|
|
120
|
+
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-3xs text-dimmed">
|
|
123
121
|
{{ history }}
|
|
124
122
|
</p>
|
|
125
123
|
</div>
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
NotificationType,
|
|
26
26
|
} from '~/types/notifications'
|
|
27
27
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
28
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
28
29
|
|
|
29
30
|
const ui = useUiStore()
|
|
30
31
|
const notifications = useNotificationsStore()
|
|
@@ -174,11 +175,11 @@ function resetToDefaults() {
|
|
|
174
175
|
</div>
|
|
175
176
|
|
|
176
177
|
<template v-else>
|
|
177
|
-
<
|
|
178
|
+
<SectionLabel class="flex items-center gap-3 px-2">
|
|
178
179
|
<span class="flex-1">{{ t('notificationSettings.column.event') }}</span>
|
|
179
180
|
<span class="w-16 text-center">{{ t('notificationSettings.column.inApp') }}</span>
|
|
180
181
|
<span class="w-16 text-center">{{ t('notificationSettings.column.email') }}</span>
|
|
181
|
-
</
|
|
182
|
+
</SectionLabel>
|
|
182
183
|
|
|
183
184
|
<div class="max-h-[50vh] space-y-1 overflow-y-auto pr-1">
|
|
184
185
|
<div
|
|
@@ -198,13 +199,13 @@ function resetToDefaults() {
|
|
|
198
199
|
</div>
|
|
199
200
|
</div>
|
|
200
201
|
|
|
201
|
-
<p class="text-
|
|
202
|
+
<p class="text-2xs text-dimmed">
|
|
202
203
|
{{ t('notificationSettings.panel.inAppNote') }}
|
|
203
204
|
</p>
|
|
204
|
-
<p class="text-
|
|
205
|
+
<p class="text-2xs text-dimmed">
|
|
205
206
|
{{ t('notificationSettings.panel.emailNote') }}
|
|
206
207
|
</p>
|
|
207
|
-
<p class="text-
|
|
208
|
+
<p class="text-2xs text-dimmed">
|
|
208
209
|
{{ t('notificationSettings.panel.otherChannelsNote') }}
|
|
209
210
|
<UButton
|
|
210
211
|
v-if="slack.available"
|
|
@@ -24,18 +24,19 @@ function toneClass(option: (typeof props.options)[number], active: boolean): str
|
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
26
|
<template>
|
|
27
|
-
<div class="flex rounded-lg border border-default p-0.5 text-
|
|
28
|
-
<
|
|
27
|
+
<div class="flex rounded-lg border border-default p-0.5 text-xs">
|
|
28
|
+
<UButton
|
|
29
|
+
color="neutral"
|
|
30
|
+
variant="ghost"
|
|
29
31
|
v-for="option in options"
|
|
30
32
|
:key="option.value"
|
|
31
|
-
|
|
32
|
-
class="rounded-md px-2.5 py-1 transition"
|
|
33
|
+
class="rounded-md px-2.5 py-1 text-xs transition"
|
|
33
34
|
:class="toneClass(option, option.value === modelValue)"
|
|
34
35
|
:aria-pressed="option.value === modelValue"
|
|
35
36
|
@click="emit('update:modelValue', option.value)"
|
|
36
37
|
>
|
|
37
38
|
{{ option.label }}
|
|
38
39
|
<span class="tabular-nums opacity-70">{{ option.count }}</span>
|
|
39
|
-
</
|
|
40
|
+
</UButton>
|
|
40
41
|
</div>
|
|
41
42
|
</template>
|
|
@@ -86,15 +86,15 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
86
86
|
<div class="flex items-start gap-3">
|
|
87
87
|
<UIcon name="i-lucide-siren" class="mt-0.5 h-5 w-5 shrink-0 text-app-error-400" />
|
|
88
88
|
<div class="min-w-0 flex-1">
|
|
89
|
-
<h2 class="text-
|
|
89
|
+
<h2 class="text-sm font-semibold text-app-error-200">
|
|
90
90
|
{{ t('observability.failure.title') }}
|
|
91
91
|
</h2>
|
|
92
92
|
|
|
93
93
|
<!-- The run's own structured record. Absent on a run that is still going, or that
|
|
94
94
|
failed without one; the evidence below stands on its own either way. -->
|
|
95
95
|
<template v-if="evidence.failure">
|
|
96
|
-
<p class="mt-1 text-
|
|
97
|
-
<div class="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-
|
|
96
|
+
<p class="mt-1 text-sm text-default">{{ evidence.failure.message }}</p>
|
|
97
|
+
<div class="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-2xs text-dimmed">
|
|
98
98
|
<span>{{ t('observability.failure.kind', { kind: failureKindLabel }) }}</span>
|
|
99
99
|
<span v-if="evidence.failure.stepIndex != null">
|
|
100
100
|
{{ t('observability.failure.atStep', { index: evidence.failure.stepIndex + 1 }) }}
|
|
@@ -108,10 +108,10 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
108
108
|
<FailureDetail
|
|
109
109
|
:detail="evidence.failure.detail"
|
|
110
110
|
:message="evidence.failure.message"
|
|
111
|
-
summary-class="text-
|
|
112
|
-
pre-class="bg-app-950/60 text-
|
|
111
|
+
summary-class="text-2xs text-dimmed hover:text-toned"
|
|
112
|
+
pre-class="bg-app-950/60 text-2xs text-muted"
|
|
113
113
|
/>
|
|
114
|
-
<p v-if="evidence.failure.hint" class="mt-1.5 text-
|
|
114
|
+
<p v-if="evidence.failure.hint" class="mt-1.5 text-xs text-toned">
|
|
115
115
|
{{ evidence.failure.hint }}
|
|
116
116
|
</p>
|
|
117
117
|
</template>
|
|
@@ -121,9 +121,10 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
121
121
|
<!-- The failing calls themselves. -->
|
|
122
122
|
<div class="mt-3 space-y-2">
|
|
123
123
|
<!-- Last model call that FAILED outright. -->
|
|
124
|
-
<
|
|
124
|
+
<UButton
|
|
125
|
+
color="neutral"
|
|
126
|
+
variant="ghost"
|
|
125
127
|
v-if="evidence.lastErroredCall"
|
|
126
|
-
type="button"
|
|
127
128
|
class="flex w-full items-start gap-3 rounded-lg border border-app-error-900/50 bg-app-950/50 px-3 py-2 text-start transition hover:bg-default/70"
|
|
128
129
|
@click="emit('showCall', evidence.lastErroredCall.id)"
|
|
129
130
|
>
|
|
@@ -133,7 +134,7 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
133
134
|
:style="{ color: agentMeta(evidence.lastErroredCall.agentKind).color }"
|
|
134
135
|
/>
|
|
135
136
|
<div class="min-w-0 flex-1">
|
|
136
|
-
<div class="flex flex-wrap items-baseline gap-x-2 text-
|
|
137
|
+
<div class="flex flex-wrap items-baseline gap-x-2 text-xs">
|
|
137
138
|
<span class="font-medium text-default">
|
|
138
139
|
{{ t('observability.failure.lastErroredCall') }}
|
|
139
140
|
</span>
|
|
@@ -145,13 +146,10 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
145
146
|
{{ evidence.lastErroredCall.httpStatus ?? t('observability.call.error') }}
|
|
146
147
|
</UBadge>
|
|
147
148
|
</div>
|
|
148
|
-
<p
|
|
149
|
-
v-if="evidence.lastErroredCall.errorMessage"
|
|
150
|
-
class="mt-0.5 text-[12px] text-app-error-300"
|
|
151
|
-
>
|
|
149
|
+
<p v-if="evidence.lastErroredCall.errorMessage" class="mt-0.5 text-xs text-app-error-300">
|
|
152
150
|
{{ evidence.lastErroredCall.errorMessage }}
|
|
153
151
|
</p>
|
|
154
|
-
<p v-if="evidence.erroredCallCount > 1" class="mt-0.5 text-
|
|
152
|
+
<p v-if="evidence.erroredCallCount > 1" class="mt-0.5 text-2xs text-dimmed">
|
|
155
153
|
{{
|
|
156
154
|
t(
|
|
157
155
|
'observability.failure.moreErroredCalls',
|
|
@@ -162,18 +160,19 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
162
160
|
</p>
|
|
163
161
|
</div>
|
|
164
162
|
<UIcon name="i-lucide-chevron-right" class="mt-0.5 h-4 w-4 shrink-0 text-app-600" />
|
|
165
|
-
</
|
|
163
|
+
</UButton>
|
|
166
164
|
|
|
167
165
|
<!-- Last TOOL call that failed: the row no rollup counts. -->
|
|
168
|
-
<
|
|
166
|
+
<UButton
|
|
167
|
+
color="neutral"
|
|
168
|
+
variant="ghost"
|
|
169
169
|
v-if="evidence.lastFailedToolCall"
|
|
170
|
-
type="button"
|
|
171
170
|
class="flex w-full items-start gap-3 rounded-lg border border-app-error-900/50 bg-app-950/50 px-3 py-2 text-start transition hover:bg-default/70"
|
|
172
171
|
@click="emit('showFailingTools')"
|
|
173
172
|
>
|
|
174
173
|
<UIcon name="i-lucide-wrench" class="mt-0.5 h-4 w-4 shrink-0 text-app-error-400" />
|
|
175
174
|
<div class="min-w-0 flex-1">
|
|
176
|
-
<div class="flex flex-wrap items-baseline gap-x-2 text-
|
|
175
|
+
<div class="flex flex-wrap items-baseline gap-x-2 text-xs">
|
|
177
176
|
<span class="font-medium text-default">
|
|
178
177
|
<!-- "One of the failing calls" when even the failures were bounded: the row is
|
|
179
178
|
real either way, but calling it the LAST would be a claim about rows this
|
|
@@ -191,16 +190,16 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
191
190
|
</div>
|
|
192
191
|
<pre
|
|
193
192
|
v-if="failedToolResult"
|
|
194
|
-
class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap text-
|
|
193
|
+
class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap text-2xs leading-relaxed text-app-error-300"
|
|
195
194
|
>{{ failedToolResult }}</pre>
|
|
196
|
-
<p v-else class="mt-0.5 text-
|
|
195
|
+
<p v-else class="mt-0.5 text-2xs italic text-dimmed">
|
|
197
196
|
{{
|
|
198
197
|
evidence.lastFailedToolCall.bodies === 'stored'
|
|
199
198
|
? t('observability.failure.toolReturnedNothing')
|
|
200
199
|
: t('observability.failure.toolBodiesWithheld')
|
|
201
200
|
}}
|
|
202
201
|
</p>
|
|
203
|
-
<p v-if="earlierFailedToolCalls" class="mt-0.5 text-
|
|
202
|
+
<p v-if="earlierFailedToolCalls" class="mt-0.5 text-2xs text-dimmed">
|
|
204
203
|
{{
|
|
205
204
|
t(
|
|
206
205
|
'observability.failure.moreFailedToolCalls',
|
|
@@ -211,7 +210,7 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
211
210
|
</p>
|
|
212
211
|
</div>
|
|
213
212
|
<UIcon name="i-lucide-chevron-right" class="mt-0.5 h-4 w-4 shrink-0 text-app-600" />
|
|
214
|
-
</
|
|
213
|
+
</UButton>
|
|
215
214
|
|
|
216
215
|
<!-- Nothing failing to point at. Which of the reasons it is decides what an operator should
|
|
217
216
|
do next, so each gets its own sentence rather than one shared shrug. `emptyReason` is
|
|
@@ -220,7 +219,7 @@ const earlierFailedToolCalls = computed(() =>
|
|
|
220
219
|
come back from being reported as one that came back clean. -->
|
|
221
220
|
<div
|
|
222
221
|
v-else-if="emptyReason"
|
|
223
|
-
class="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-dashed px-3 py-2 text-
|
|
222
|
+
class="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-dashed px-3 py-2 text-xs"
|
|
224
223
|
:class="
|
|
225
224
|
emptyReason === 'sink-unreachable'
|
|
226
225
|
? 'border-app-warning-900/60 text-app-warning-300'
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
totalInputTokens,
|
|
12
12
|
transportRatio,
|
|
13
13
|
} from '~/utils/observability'
|
|
14
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
14
15
|
|
|
15
16
|
// Compact, at-a-glance LLM rollup for one pipeline step: token usage, an
|
|
16
17
|
// output-limit headroom bar (how close the step ran to truncation), a
|
|
@@ -57,7 +58,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
57
58
|
<template>
|
|
58
59
|
<div
|
|
59
60
|
v-if="m.calls > 0"
|
|
60
|
-
class="rounded-lg border border-default bg-default/40 p-2.5 text-
|
|
61
|
+
class="rounded-lg border border-default bg-default/40 p-2.5 text-xs"
|
|
61
62
|
:class="clickable ? 'cursor-pointer transition hover:border-muted hover:bg-default/70' : ''"
|
|
62
63
|
:role="clickable ? 'button' : undefined"
|
|
63
64
|
@click="clickable ? $emit('inspect') : undefined"
|
|
@@ -88,13 +89,13 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
88
89
|
>
|
|
89
90
|
{{ onSubscription ? `~${cost}` : cost }}
|
|
90
91
|
</span>
|
|
91
|
-
<
|
|
92
|
+
<SectionLabel
|
|
92
93
|
v-if="onSubscription"
|
|
93
|
-
|
|
94
|
+
as="span"
|
|
94
95
|
:title="t('observability.metricsBar.subscriptionCostHint')"
|
|
95
96
|
>
|
|
96
97
|
{{ t('observability.metricsBar.subscription') }}
|
|
97
|
-
</
|
|
98
|
+
</SectionLabel>
|
|
98
99
|
</template>
|
|
99
100
|
<div class="ms-auto flex items-center gap-1">
|
|
100
101
|
<UBadge v-if="m.errors > 0" color="error" variant="subtle" size="sm">
|
|
@@ -112,7 +113,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
112
113
|
</div>
|
|
113
114
|
|
|
114
115
|
<!-- input breakdown: the headline's three classes, priced an order of magnitude apart -->
|
|
115
|
-
<div v-if="hasCache" class="mt-1.5 flex items-center gap-1.5 text-
|
|
116
|
+
<div v-if="hasCache" class="mt-1.5 flex items-center gap-1.5 text-2xs tabular-nums">
|
|
116
117
|
<span class="text-muted" :title="t('observability.metricsBar.freshHint')">
|
|
117
118
|
{{ t('observability.metricsBar.fresh', { tokens: formatTokens(m.promptTokens) }) }}
|
|
118
119
|
</span>
|
|
@@ -136,7 +137,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
136
137
|
|
|
137
138
|
<!-- output-limit headroom -->
|
|
138
139
|
<div v-if="headroom !== null" class="mt-2">
|
|
139
|
-
<div class="flex items-center justify-between text-
|
|
140
|
+
<div class="flex items-center justify-between text-2xs">
|
|
140
141
|
<span class="text-dimmed">{{ t('observability.metricsBar.outputLimit') }}</span>
|
|
141
142
|
<span class="tabular-nums" :class="headroomTone">
|
|
142
143
|
{{ formatTokens(m.peakCompletionTokens) }} /
|
|
@@ -156,7 +157,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
156
157
|
:style="{ width: `${Math.max(2, pct(headroom))}%` }"
|
|
157
158
|
/>
|
|
158
159
|
</div>
|
|
159
|
-
<p v-if="m.truncatedCalls > 0" class="mt-1 text-
|
|
160
|
+
<p v-if="m.truncatedCalls > 0" class="mt-1 text-2xs text-app-error-400">
|
|
160
161
|
{{
|
|
161
162
|
t(
|
|
162
163
|
'observability.metricsBar.truncatedCalls',
|
|
@@ -169,7 +170,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
|
|
|
169
170
|
|
|
170
171
|
<!-- transport overhead vs model execution -->
|
|
171
172
|
<div v-if="transport !== null" class="mt-2">
|
|
172
|
-
<div class="flex items-center justify-between text-
|
|
173
|
+
<div class="flex items-center justify-between text-2xs">
|
|
173
174
|
<span class="text-dimmed">{{ t('observability.metricsBar.transportVsExecution') }}</span>
|
|
174
175
|
<span class="tabular-nums text-muted">
|
|
175
176
|
{{ formatMs(m.overheadMs) }} / {{ formatMs(m.upstreamMs) }}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import type { StepMetrics } from '~/types/execution'
|
|
4
4
|
import StepMetricsBar from '~/components/observability/StepMetricsBar.vue'
|
|
5
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
5
6
|
|
|
6
7
|
// The shared "Model activity" block: the LLM observability rollup (StepMetricsBar) under
|
|
7
8
|
// a labelled header with a "View all calls →" link into the full per-call panel. Used by
|
|
@@ -31,16 +32,18 @@ function openObservability() {
|
|
|
31
32
|
<template>
|
|
32
33
|
<div v-if="instanceId || hasCalls">
|
|
33
34
|
<div class="mb-1 flex items-center justify-between">
|
|
34
|
-
<
|
|
35
|
+
<SectionLabel as="span">
|
|
35
36
|
{{ t('observability.modelActivity') }}
|
|
36
|
-
</
|
|
37
|
-
<
|
|
37
|
+
</SectionLabel>
|
|
38
|
+
<UButton
|
|
39
|
+
color="neutral"
|
|
40
|
+
variant="ghost"
|
|
38
41
|
v-if="instanceId"
|
|
39
|
-
class="text-
|
|
42
|
+
class="p-0 text-2xs text-app-info-400 hover:bg-transparent hover:text-app-info-300"
|
|
40
43
|
@click="openObservability"
|
|
41
44
|
>
|
|
42
45
|
{{ t('observability.viewAllCalls') }}
|
|
43
|
-
</
|
|
46
|
+
</UButton>
|
|
44
47
|
</div>
|
|
45
48
|
<StepMetricsBar
|
|
46
49
|
v-if="hasCalls && metrics"
|