@cat-factory/app 0.302.1 → 0.303.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 +16 -0
- package/app/app.config.ts +19 -10
- package/app/assets/css/main.css +13 -13
- package/app/assets/css/prose.css +22 -22
- package/app/assets/css/tokens.css +298 -0
- package/app/components/assistant/AssistantModal.vue +22 -22
- package/app/components/auth/AuthGate.vue +1 -1
- package/app/components/auth/BackendMisconfiguredScreen.vue +10 -10
- package/app/components/auth/LoginScreen.vue +34 -36
- package/app/components/auth/ResetPasswordScreen.vue +12 -12
- package/app/components/auth/UserMenu.vue +4 -4
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +27 -25
- package/app/components/binaryOutput/BinaryOutputReport.vue +15 -15
- package/app/components/binaryOutput/StoredAssetView.vue +5 -5
- package/app/components/board/AddTaskModal.vue +17 -20
- package/app/components/board/AgentFailureCard.vue +11 -11
- package/app/components/board/AgentFailureHistory.vue +2 -2
- package/app/components/board/BoardCanvas.vue +6 -5
- package/app/components/board/CreateInitiativeModal.vue +8 -10
- package/app/components/board/DependencyConnectOverlay.vue +1 -1
- package/app/components/board/FailureHistoryList.vue +7 -7
- package/app/components/board/RecurringPipelineModal.vue +17 -17
- package/app/components/board/ReviewFrictionDialog.vue +6 -6
- package/app/components/board/StepExecutionHistory.vue +13 -13
- package/app/components/board/TaskDependencyEdges.vue +8 -8
- package/app/components/board/nodes/AgentChip.vue +10 -10
- package/app/components/board/nodes/BlockNode.vue +29 -29
- package/app/components/board/nodes/DecisionBadge.vue +2 -2
- package/app/components/board/nodes/EpicNode.vue +14 -10
- package/app/components/board/nodes/FrameSwimlanes.vue +7 -9
- package/app/components/board/nodes/InitiativeCard.vue +8 -8
- package/app/components/board/nodes/LaneGroup.vue +1 -1
- package/app/components/board/nodes/LaneTask.vue +2 -2
- package/app/components/board/nodes/ResizeGrips.vue +4 -4
- package/app/components/board/nodes/TaskCard.vue +18 -18
- package/app/components/board/nodes/TaskLane.vue +5 -5
- package/app/components/board/nodes/TaskPipelineMini.vue +18 -18
- package/app/components/bootstrap/AdoptionReviewModal.vue +29 -26
- package/app/components/bootstrap/BootstrapModal.vue +21 -23
- package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
- package/app/components/brainstorm/BrainstormWindow.vue +30 -33
- package/app/components/bugFishing/BugFishingWindow.vue +49 -49
- package/app/components/clarity/ClarityReviewWindow.vue +30 -30
- package/app/components/common/AsyncViewError.vue +5 -5
- package/app/components/common/ClarificationItem.vue +8 -13
- package/app/components/common/ConfirmDialog.vue +4 -2
- package/app/components/common/DescriptorFields.vue +1 -1
- package/app/components/common/EmptyState.vue +3 -3
- package/app/components/common/InterviewGateNotice.vue +7 -7
- package/app/components/common/KeyboardShortcutsHelp.vue +1 -1
- package/app/components/common/MarkdownProse.vue +14 -13
- package/app/components/consensus/ConsensusSessionWindow.vue +26 -26
- package/app/components/context/ContextAttachmentFields.vue +17 -17
- package/app/components/docs/DocInterviewWindow.vue +14 -14
- package/app/components/documents/ContextDocumentPicker.vue +17 -17
- package/app/components/documents/DocumentImportModal.vue +7 -7
- package/app/components/documents/DocumentSourceConnectModal.vue +3 -3
- package/app/components/documents/DocumentSyncState.vue +5 -5
- package/app/components/documents/DocumentTemplatesModal.vue +15 -15
- package/app/components/documents/RepoContextDocPicker.vue +5 -5
- package/app/components/documents/SpawnPreviewModal.vue +12 -12
- package/app/components/documents/StartFromDesignModal.vue +11 -11
- package/app/components/documents/TaskContextDocs.vue +5 -5
- package/app/components/environments/EnvSetupStepper.vue +6 -6
- package/app/components/environments/EnvironmentStatusPanel.vue +17 -17
- package/app/components/environments/steps/EnvPickStep.vue +3 -3
- package/app/components/environments/steps/EnvPreflightStep.vue +9 -9
- package/app/components/environments/steps/EnvReviewStep.vue +25 -22
- package/app/components/environments/steps/EnvSaveStep.vue +7 -5
- package/app/components/environments/steps/JourneyStepNav.vue +1 -1
- package/app/components/focus/BlockFocusView.vue +17 -19
- package/app/components/followUp/FollowUpWindow.vue +23 -23
- package/app/components/forkDecision/ForkDecisionWindow.vue +37 -39
- package/app/components/foundational/FoundationalContractSummary.vue +7 -7
- package/app/components/foundational/FoundationalServiceCatalogList.vue +11 -11
- package/app/components/foundational/FoundationalServiceManager.vue +1 -1
- package/app/components/foundational/FoundationalServiceRegistry.vue +13 -13
- package/app/components/foundational/FoundationalServiceSources.vue +13 -13
- package/app/components/foundational/FoundationalSuppressions.vue +7 -7
- package/app/components/foundational/ServiceCatalogConnection.vue +10 -10
- package/app/components/fragments/FragmentLibraryManager.vue +41 -44
- package/app/components/fragments/FragmentSelector.vue +13 -13
- package/app/components/fragments/GitHubDocUrlImport.vue +1 -1
- package/app/components/gates/GateFailingCheckList.vue +5 -5
- package/app/components/gates/GateResultView.vue +50 -47
- package/app/components/github/AddServiceFromRepoModal.vue +14 -14
- package/app/components/github/BranchProtectionPreflight.vue +13 -13
- package/app/components/github/GitHubConnect.vue +7 -7
- package/app/components/github/GitHubOnboarding.vue +7 -7
- package/app/components/github/GitHubPanel.vue +37 -40
- package/app/components/github/RepoTreeBrowser.vue +18 -18
- package/app/components/humanTest/HumanTestWindow.vue +30 -33
- package/app/components/initiative/InitiativePlanNotice.vue +5 -5
- package/app/components/initiative/InitiativePlanReview.vue +27 -29
- package/app/components/initiative/InitiativePlanningWindow.vue +10 -10
- package/app/components/initiative/InitiativeTrackerWindow.vue +71 -65
- package/app/components/inputGate/InputGateNotice.vue +2 -4
- package/app/components/judge/JudgeResultView.vue +30 -32
- package/app/components/kaizen/KaizenPanel.vue +40 -36
- package/app/components/kaizen/KaizenStepStatus.vue +21 -21
- package/app/components/layout/AccountAuditLog.vue +10 -10
- package/app/components/layout/AccountDeploymentSettings.vue +20 -20
- 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 +9 -9
- package/app/components/layout/AccountPlatformAlertSettings.vue +11 -11
- package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
- package/app/components/layout/AccountRunCredentialSettings.vue +5 -5
- package/app/components/layout/AccountSkillSettings.vue +1 -1
- package/app/components/layout/AccountTeamSettings.vue +23 -15
- package/app/components/layout/AiProvidersBanner.vue +11 -8
- package/app/components/layout/AppearanceSwitcher.vue +108 -0
- package/app/components/layout/BoardSwitcher.vue +8 -11
- package/app/components/layout/BoardToolbar.vue +3 -3
- package/app/components/layout/CommandBar.vue +7 -9
- package/app/components/layout/ConnectionStatusBanner.vue +2 -2
- package/app/components/layout/DefaultTestEnvBanner.vue +5 -5
- package/app/components/layout/GitHubPatBanner.vue +5 -5
- package/app/components/layout/GitHubPatPermissionsBanner.vue +16 -10
- package/app/components/layout/InfraSetupBanner.vue +6 -6
- package/app/components/layout/IntegrationsHub.vue +15 -15
- package/app/components/layout/LanguageSwitcher.vue +5 -5
- package/app/components/layout/ModelProvidersHub.vue +13 -16
- package/app/components/layout/NotificationsInbox.vue +10 -10
- package/app/components/layout/PersonalSetupModal.vue +8 -8
- package/app/components/layout/ProviderConfigBanner.vue +4 -4
- package/app/components/layout/RolePrompt.vue +7 -7
- package/app/components/layout/SideBar.vue +6 -4
- package/app/components/layout/SpendWarningBanner.vue +17 -14
- package/app/components/layout/TranslationWarningBanner.vue +4 -4
- package/app/components/layout/UiModeSwitcher.vue +13 -13
- package/app/components/layout/UiRoleSwitcher.vue +8 -8
- package/app/components/layout/WorkspaceMembersSettings.vue +15 -11
- package/app/components/media/ArtifactLightbox.vue +13 -13
- package/app/components/media/ImageCompare.vue +31 -24
- package/app/components/merge/MergeEffortChips.vue +2 -2
- package/app/components/notifications/NotificationSettingsPanel.vue +14 -12
- package/app/components/observability/OutcomeFilterChips.vue +6 -6
- package/app/components/observability/RunFailureSummary.vue +28 -25
- package/app/components/observability/StepMetricsBar.vue +26 -28
- package/app/components/observability/StepModelActivity.vue +2 -2
- package/app/components/observability/ToolCallList.vue +24 -24
- package/app/components/outcome/OutcomeSummaryWindow.vue +47 -47
- package/app/components/palettes/AgentPalette.vue +8 -8
- package/app/components/palettes/AgentTierSelect.vue +1 -1
- package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
- package/app/components/panels/AgentStepDetail.vue +52 -51
- package/app/components/panels/AttemptEntryHeader.vue +4 -6
- package/app/components/panels/DecisionModal.vue +7 -7
- package/app/components/panels/GenericStructuredResultView.vue +7 -7
- package/app/components/panels/InspectorPanel.vue +17 -17
- package/app/components/panels/MergerResultView.vue +19 -19
- package/app/components/panels/ObservabilityPanel.vue +115 -123
- package/app/components/panels/OperatorDashboardPanel.vue +89 -97
- package/app/components/panels/ReportsPanel.vue +69 -66
- package/app/components/panels/ReportsSpendBreakdown.vue +9 -9
- package/app/components/panels/ResultWindowShell.vue +38 -38
- package/app/components/panels/RunDetailLoadState.vue +2 -2
- package/app/components/panels/StepContainerStatus.vue +9 -9
- package/app/components/panels/StepDelegatedStatus.logic.spec.ts +135 -0
- package/app/components/panels/StepDelegatedStatus.logic.ts +160 -0
- package/app/components/panels/StepDelegatedStatus.vue +181 -0
- package/app/components/panels/StepEffortReport.vue +16 -15
- package/app/components/panels/StepFragmentAdherence.vue +14 -10
- package/app/components/panels/StepMetadataCard.vue +74 -45
- package/app/components/panels/StepReproductionReport.vue +25 -21
- package/app/components/panels/StepRunMeta.vue +20 -20
- package/app/components/panels/StepTestReport.logic.spec.ts +8 -3
- package/app/components/panels/StepTestReport.logic.ts +4 -4
- package/app/components/panels/StepTestReport.vue +28 -28
- package/app/components/panels/StepToolServers.vue +14 -11
- package/app/components/panels/StepValidationReport.vue +7 -7
- package/app/components/panels/inspector/ContainerSummary.vue +9 -9
- package/app/components/panels/inspector/DocReferenceRepos.vue +3 -3
- package/app/components/panels/inspector/EnvProbeReport.vue +24 -27
- package/app/components/panels/inspector/EpicChildren.vue +8 -12
- package/app/components/panels/inspector/FrontendBindingsResolved.vue +11 -11
- package/app/components/panels/inspector/FrontendConfig.vue +37 -41
- package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
- package/app/components/panels/inspector/InspectorSection.vue +6 -6
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +16 -19
- package/app/components/panels/inspector/ServiceConnections.vue +2 -2
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
- package/app/components/panels/inspector/ServiceSelfTests.vue +21 -17
- package/app/components/panels/inspector/ServiceTestConfig.vue +51 -59
- package/app/components/panels/inspector/ServiceTestSecrets.vue +5 -5
- package/app/components/panels/inspector/ServiceTestingContext.vue +3 -3
- package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAgentConfig.vue +3 -3
- package/app/components/panels/inspector/TaskAprioriBranches.vue +8 -5
- package/app/components/panels/inspector/TaskDependencies.vue +1 -1
- package/app/components/panels/inspector/TaskEstimateBadge.vue +11 -11
- package/app/components/panels/inspector/TaskExecution.vue +17 -17
- package/app/components/panels/inspector/TaskReviewTarget.vue +2 -2
- package/app/components/panels/inspector/TaskRunSettings.vue +35 -37
- package/app/components/panels/inspector/TaskStructure.vue +3 -3
- package/app/components/pipeline/AgentKindIcon.vue +1 -1
- package/app/components/pipeline/AgentPromptEditor.vue +17 -17
- package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -56
- package/app/components/pipeline/EstimateThresholdFields.vue +4 -4
- package/app/components/pipeline/GateConfigFields.vue +13 -10
- package/app/components/pipeline/IterationCapPrompt.vue +4 -2
- package/app/components/pipeline/PipelineBuilder.vue +47 -55
- package/app/components/pipeline/PipelineHealthModal.vue +27 -29
- package/app/components/pipeline/PipelinePicker.vue +10 -10
- package/app/components/pipeline/PipelinePreview.vue +10 -10
- package/app/components/pipeline/PipelineProgress.vue +64 -67
- package/app/components/prReview/PrReviewPhaseBadge.vue +7 -7
- package/app/components/prReview/PrReviewWindow.vue +75 -77
- package/app/components/providers/AiPresetMismatchDialog.vue +5 -5
- package/app/components/providers/AiProviderOnboardingModal.vue +9 -9
- package/app/components/providers/ApiKeysSection.vue +13 -13
- package/app/components/providers/PersonalCredentialModal.vue +2 -2
- package/app/components/providers/PersonalSubscriptionSection.vue +10 -10
- package/app/components/providers/SignInRequiredNotice.vue +1 -1
- package/app/components/providers/VendorCredentialsModal.vue +10 -10
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +13 -13
- package/app/components/ralph/RalphLoopResultView.vue +28 -30
- package/app/components/recurring/RecurrenceEditor.vue +2 -2
- package/app/components/requirements/RequirementsReviewWindow.vue +51 -58
- package/app/components/riskPolicy/RiskPolicyPicker.vue +12 -15
- package/app/components/riskPolicy/RiskPolicyPreview.vue +14 -14
- package/app/components/sandbox/SandboxPanel.vue +58 -59
- package/app/components/settings/AccountSettingsPanel.vue +1 -1
- package/app/components/settings/ApiTokensPanel.vue +10 -10
- package/app/components/settings/BudgetSettings.vue +18 -22
- package/app/components/settings/CapabilityCredentialsPanel.vue +15 -15
- package/app/components/settings/CloudflareHandlerSection.vue +20 -20
- package/app/components/settings/ComposeEnvironmentSetupSection.vue +13 -13
- package/app/components/settings/ConnectionTestVerdict.vue +3 -3
- package/app/components/settings/ConnectionWarnings.vue +1 -1
- package/app/components/settings/ConsensusGroupsSection.vue +27 -35
- package/app/components/settings/CustomManifestTypeEditor.vue +10 -10
- package/app/components/settings/DefaultProvisionTypeSection.vue +6 -6
- package/app/components/settings/InfraHandlersConfigurator.vue +24 -22
- package/app/components/settings/InfrastructureBackendPicker.vue +6 -6
- package/app/components/settings/InfrastructureWindow.vue +5 -5
- package/app/components/settings/IssueTrackerPanel.vue +29 -23
- package/app/components/settings/KubernetesEngineForm.vue +11 -11
- package/app/components/settings/KubernetesEnvironmentForm.vue +4 -4
- package/app/components/settings/LocalContainerPoolSettings.vue +6 -11
- package/app/components/settings/LocalModelEndpointsPanel.vue +20 -18
- package/app/components/settings/McpAuthorizeScreen.vue +13 -15
- package/app/components/settings/McpOAuthCallbackScreen.vue +16 -10
- package/app/components/settings/MergeClassRulesEditor.vue +6 -9
- package/app/components/settings/MergeRolePolicyEditor.vue +16 -16
- package/app/components/settings/ModelConfigurationPanel.vue +23 -30
- package/app/components/settings/ModelPresetHealthModal.vue +15 -13
- package/app/components/settings/ObservabilityConnectionPanel.vue +4 -4
- package/app/components/settings/OpenRouterCatalogPanel.vue +23 -19
- package/app/components/settings/PackageRegistriesPanel.vue +8 -8
- package/app/components/settings/ProviderConnectionTab.vue +8 -11
- package/app/components/settings/ProviderManifestEditor.vue +9 -9
- package/app/components/settings/ProviderPreferenceEditor.vue +8 -8
- package/app/components/settings/RiskPolicyCreateForm.vue +10 -10
- package/app/components/settings/RiskPolicyEditorRow.vue +14 -14
- package/app/components/settings/RiskPolicyHealthModal.vue +15 -13
- package/app/components/settings/RiskPolicyInheritedRow.vue +1 -1
- package/app/components/settings/RiskPolicyPanel.vue +10 -15
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +7 -7
- package/app/components/settings/SharedStacksPanel.vue +9 -12
- package/app/components/settings/TaskSourceCard.vue +4 -4
- package/app/components/settings/TaskTypeSuppressionsPanel.vue +6 -6
- package/app/components/settings/ToolServerChecklist.vue +36 -29
- package/app/components/settings/UsageSettings.vue +15 -15
- package/app/components/settings/UserSecretsSection.vue +9 -12
- package/app/components/settings/WorkspaceMetadataSettings.vue +5 -5
- package/app/components/settings/WorkspaceSettingsPanel.vue +47 -47
- package/app/components/skills/ReviewSkillQueue.vue +10 -10
- package/app/components/skills/SkillLibraryManager.vue +23 -20
- package/app/components/slack/SlackPanel.vue +13 -17
- package/app/components/spec/ServiceSpecWindow.vue +45 -42
- package/app/components/tasks/BugHuntModal.vue +24 -27
- package/app/components/tasks/ContextIssuePicker.vue +11 -11
- package/app/components/tasks/TaskContextIssues.vue +3 -3
- package/app/components/tasks/TaskImportModal.vue +7 -7
- package/app/components/tasks/TaskSourceConnectModal.vue +10 -8
- package/app/components/testing/TestReportWindow.vue +99 -82
- package/app/components/theme/ThemeImportModal.vue +115 -0
- package/app/components/tutorial/TutorialCatalogue.vue +9 -9
- package/app/components/tutorial/TutorialNudge.vue +5 -5
- package/app/components/tutorial/TutorialOverlay.vue +12 -12
- package/app/components/tutorial/TutorialPrompt.vue +6 -9
- package/app/components/vcs/GitLabConnect.vue +4 -4
- package/app/components/vcs/VcsConnectSurfaces.vue +2 -2
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +36 -36
- package/app/composables/api/client.ts +6 -1
- package/app/composables/usePipelineErrorToast.ts +17 -0
- package/app/modular/agent-kinds.ts +24 -0
- package/app/pages/index.vue +5 -5
- package/app/plugins/theme.client.ts +125 -0
- package/app/spa-loading-template.html +52 -14
- package/app/stores/agents.ts +1 -1
- package/app/stores/theme.spec.ts +56 -0
- package/app/stores/theme.ts +87 -0
- package/app/types/domain.ts +19 -0
- package/app/types/execution.ts +4 -0
- package/app/utils/agentOutput.ts +1 -1
- package/app/utils/binaryOutput.ts +6 -6
- package/app/utils/bootstrapSteps.ts +14 -14
- package/app/utils/catalog.ts +87 -83
- package/app/utils/colorTint.ts +10 -0
- package/app/utils/failureKinds.ts +1 -0
- package/app/utils/observability.ts +3 -3
- package/app/utils/pipelineRender.ts +13 -17
- package/app/utils/swimlanes.ts +4 -4
- package/app/utils/theme/bootPalette.spec.ts +54 -0
- package/app/utils/theme/bootPalette.ts +108 -0
- package/app/utils/theme/builtins.spec.ts +38 -0
- package/app/utils/theme/builtins.ts +55 -0
- package/app/utils/theme/css.ts +162 -0
- package/app/utils/theme/doc.ts +353 -0
- package/app/utils/theme/link.ts +93 -0
- package/app/utils/theme/presets.ts +509 -0
- package/app/utils/theme/theme.spec.ts +224 -0
- package/i18n/locales/de.json +61 -4
- package/i18n/locales/en.json +70 -4
- package/i18n/locales/es.json +61 -4
- package/i18n/locales/fr.json +61 -4
- package/i18n/locales/he.json +61 -4
- package/i18n/locales/it.json +61 -4
- package/i18n/locales/ja.json +61 -4
- package/i18n/locales/pl.json +61 -4
- package/i18n/locales/tr.json +61 -4
- package/i18n/locales/uk.json +61 -4
- package/nuxt.config.ts +37 -11
- package/package.json +10 -9
|
@@ -145,13 +145,17 @@ const STATUS_META = computed<
|
|
|
145
145
|
>(() => ({
|
|
146
146
|
passed: {
|
|
147
147
|
icon: 'i-lucide-circle-check',
|
|
148
|
-
text: 'text-
|
|
148
|
+
text: 'text-app-success-400',
|
|
149
149
|
label: t('testing.status.passed'),
|
|
150
150
|
},
|
|
151
|
-
failed: {
|
|
151
|
+
failed: {
|
|
152
|
+
icon: 'i-lucide-circle-x',
|
|
153
|
+
text: 'text-app-error-400',
|
|
154
|
+
label: t('testing.status.failed'),
|
|
155
|
+
},
|
|
152
156
|
skipped: {
|
|
153
157
|
icon: 'i-lucide-circle-minus',
|
|
154
|
-
text: 'text-
|
|
158
|
+
text: 'text-dimmed',
|
|
155
159
|
label: t('testing.status.skipped'),
|
|
156
160
|
},
|
|
157
161
|
}))
|
|
@@ -167,10 +171,18 @@ const SEVERITY_LABELS = computed<Record<TestConcern['severity'], string>>(() =>
|
|
|
167
171
|
|
|
168
172
|
const SEVERITY_META: Record<TestConcern['severity'], { text: string; chip: string; rank: number }> =
|
|
169
173
|
{
|
|
170
|
-
critical: {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
critical: {
|
|
175
|
+
text: 'text-app-error-300',
|
|
176
|
+
chip: 'bg-app-error-500/15 text-app-error-300',
|
|
177
|
+
rank: 0,
|
|
178
|
+
},
|
|
179
|
+
high: { text: 'text-app-error-300', chip: 'bg-app-error-500/15 text-app-error-300', rank: 1 },
|
|
180
|
+
medium: {
|
|
181
|
+
text: 'text-app-warning-300',
|
|
182
|
+
chip: 'bg-app-warning-500/15 text-app-warning-300',
|
|
183
|
+
rank: 2,
|
|
184
|
+
},
|
|
185
|
+
low: { text: 'text-toned', chip: 'bg-app-500/15 text-toned', rank: 3 },
|
|
174
186
|
}
|
|
175
187
|
|
|
176
188
|
/** Case-insensitive "these two labels refer to the same thing" heuristic. */
|
|
@@ -318,11 +330,11 @@ function toggle(key: string) {
|
|
|
318
330
|
}
|
|
319
331
|
|
|
320
332
|
const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: string }> = {
|
|
321
|
-
passed: { icon: 'i-lucide-circle-check', text: 'text-
|
|
322
|
-
failed: { icon: 'i-lucide-circle-x', text: 'text-
|
|
323
|
-
skipped: { icon: 'i-lucide-circle-minus', text: 'text-
|
|
324
|
-
mixed: { icon: 'i-lucide-circle-dot', text: 'text-
|
|
325
|
-
empty: { icon: 'i-lucide-circle-dashed', text: 'text-
|
|
333
|
+
passed: { icon: 'i-lucide-circle-check', text: 'text-app-success-400' },
|
|
334
|
+
failed: { icon: 'i-lucide-circle-x', text: 'text-app-error-400' },
|
|
335
|
+
skipped: { icon: 'i-lucide-circle-minus', text: 'text-dimmed' },
|
|
336
|
+
mixed: { icon: 'i-lucide-circle-dot', text: 'text-app-warning-400' },
|
|
337
|
+
empty: { icon: 'i-lucide-circle-dashed', text: 'text-dimmed' },
|
|
326
338
|
}
|
|
327
339
|
</script>
|
|
328
340
|
|
|
@@ -330,7 +342,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
330
342
|
<ResultWindowShell
|
|
331
343
|
:open="open"
|
|
332
344
|
icon="i-lucide-flask-conical"
|
|
333
|
-
icon-class="bg-
|
|
345
|
+
icon-class="bg-app-warning-500/15 text-app-warning-300"
|
|
334
346
|
:title="headerTitle"
|
|
335
347
|
:subtitle="t('testing.subtitle')"
|
|
336
348
|
:step-ref="{ instanceId, stepIndex }"
|
|
@@ -349,7 +361,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
349
361
|
</UBadge>
|
|
350
362
|
<span
|
|
351
363
|
v-if="testState && testState.attempts > 0"
|
|
352
|
-
class="text-[11px] text-
|
|
364
|
+
class="text-[11px] text-muted"
|
|
353
365
|
:title="t('testing.fixerAttempts')"
|
|
354
366
|
>
|
|
355
367
|
{{ t('testing.fixCount', { attempts: testState.attempts, max: testState.maxAttempts }) }}
|
|
@@ -372,7 +384,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
372
384
|
data-testid="tester-infrastructure"
|
|
373
385
|
class="space-y-3"
|
|
374
386
|
>
|
|
375
|
-
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-
|
|
387
|
+
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
376
388
|
{{ t('testing.infrastructure') }}
|
|
377
389
|
</h3>
|
|
378
390
|
<StepContainerStatus :step="step" :run-failed="runFailed" :run-active="runActive" />
|
|
@@ -392,20 +404,20 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
392
404
|
class="rounded-lg border px-3 py-2"
|
|
393
405
|
:class="
|
|
394
406
|
infraSetup.started
|
|
395
|
-
? 'border-
|
|
396
|
-
: 'border-
|
|
407
|
+
? 'border-default bg-default/60'
|
|
408
|
+
: 'border-app-error-500/40 bg-app-error-500/10'
|
|
397
409
|
"
|
|
398
410
|
>
|
|
399
411
|
<div class="flex items-center gap-2">
|
|
400
412
|
<UIcon
|
|
401
413
|
:name="infraSetup.started ? 'i-lucide-container' : 'i-lucide-circle-x'"
|
|
402
414
|
class="h-3.5 w-3.5 shrink-0"
|
|
403
|
-
:class="infraSetup.started ? 'text-
|
|
415
|
+
:class="infraSetup.started ? 'text-app-success-400' : 'text-app-error-400'"
|
|
404
416
|
/>
|
|
405
|
-
<span class="text-[13px] font-medium text-
|
|
417
|
+
<span class="text-[13px] font-medium text-default">
|
|
406
418
|
{{ standupHeadline }}
|
|
407
419
|
</span>
|
|
408
|
-
<span v-if="infraSetup.durationMs != null" class="ms-auto text-[11px] text-
|
|
420
|
+
<span v-if="infraSetup.durationMs != null" class="ms-auto text-[11px] text-dimmed">
|
|
409
421
|
{{
|
|
410
422
|
t('testing.standup.took', {
|
|
411
423
|
seconds: n(infraSetup.durationMs / 1000, 'decimal'),
|
|
@@ -413,12 +425,12 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
413
425
|
}}
|
|
414
426
|
</span>
|
|
415
427
|
</div>
|
|
416
|
-
<p v-if="infraSetup.composePath" class="mt-1 font-mono text-[11px] text-
|
|
428
|
+
<p v-if="infraSetup.composePath" class="mt-1 font-mono text-[11px] text-dimmed">
|
|
417
429
|
{{ infraSetup.composePath }}
|
|
418
430
|
</p>
|
|
419
431
|
<p
|
|
420
432
|
v-if="infraSetup.error"
|
|
421
|
-
class="mt-1 text-[12px] leading-snug text-
|
|
433
|
+
class="mt-1 text-[12px] leading-snug text-app-error-300"
|
|
422
434
|
data-testid="tester-infra-setup-error"
|
|
423
435
|
>
|
|
424
436
|
{{ infraSetup.error }}
|
|
@@ -443,7 +455,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
443
455
|
<pre
|
|
444
456
|
v-if="showInfraSetupLogs"
|
|
445
457
|
data-testid="tester-infra-setup-logs"
|
|
446
|
-
class="mt-2 max-h-64 overflow-auto rounded bg-
|
|
458
|
+
class="mt-2 max-h-64 overflow-auto rounded bg-app-950/70 p-2 font-mono text-[11px] leading-relaxed text-toned"
|
|
447
459
|
>{{ infraSetup.logs }}</pre>
|
|
448
460
|
</template>
|
|
449
461
|
</div>
|
|
@@ -455,9 +467,9 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
455
467
|
<div
|
|
456
468
|
v-if="infraReady"
|
|
457
469
|
data-testid="tester-env-ready"
|
|
458
|
-
class="flex items-center gap-2 rounded-lg border border-
|
|
470
|
+
class="flex items-center gap-2 rounded-lg border border-app-success-500/30 bg-app-success-500/10 px-3 py-2 text-[13px] text-app-success-200"
|
|
459
471
|
>
|
|
460
|
-
<UIcon name="i-lucide-rocket" class="h-4 w-4 shrink-0 text-
|
|
472
|
+
<UIcon name="i-lucide-rocket" class="h-4 w-4 shrink-0 text-app-success-400" />
|
|
461
473
|
<span>{{ t('testing.readyBanner') }}</span>
|
|
462
474
|
</div>
|
|
463
475
|
|
|
@@ -492,7 +504,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
492
504
|
how it ended), so the otherwise-opaque fixer sub-jobs have a surface — the
|
|
493
505
|
analogue of the polling gate's attempt history. -->
|
|
494
506
|
<section v-if="fixerAttempts.length" data-testid="tester-fixer-attempts" class="space-y-2">
|
|
495
|
-
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-
|
|
507
|
+
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
496
508
|
{{ t('testing.fixerAttempts') }}
|
|
497
509
|
</h3>
|
|
498
510
|
<ol class="space-y-2">
|
|
@@ -500,7 +512,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
500
512
|
v-for="a in fixerAttempts"
|
|
501
513
|
:key="a.attempt"
|
|
502
514
|
data-testid="tester-fixer-attempt"
|
|
503
|
-
class="rounded-lg border border-
|
|
515
|
+
class="rounded-lg border border-default bg-default/60 px-3 py-2"
|
|
504
516
|
>
|
|
505
517
|
<AttemptEntryHeader
|
|
506
518
|
:label="t('testing.fixerTimeline.attempt', { n: a.attempt })"
|
|
@@ -512,22 +524,24 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
512
524
|
"
|
|
513
525
|
:at="a.at"
|
|
514
526
|
:icon="a.outcome === 'completed' ? 'i-lucide-wrench' : 'i-lucide-circle-x'"
|
|
515
|
-
:icon-class="
|
|
527
|
+
:icon-class="
|
|
528
|
+
a.outcome === 'completed' ? 'text-app-warning-300' : 'text-app-error-400'
|
|
529
|
+
"
|
|
516
530
|
/>
|
|
517
531
|
<MarkdownProse
|
|
518
532
|
v-if="a.summary"
|
|
519
533
|
:text="a.summary"
|
|
520
|
-
class="mt-1 max-w-3xl text-[12px] leading-snug text-
|
|
534
|
+
class="mt-1 max-w-3xl text-[12px] leading-snug text-muted"
|
|
521
535
|
/>
|
|
522
536
|
<div v-if="a.concerns && a.concerns.length" class="mt-1.5">
|
|
523
|
-
<p class="text-[11px] text-
|
|
537
|
+
<p class="text-[11px] text-dimmed">
|
|
524
538
|
{{ t('testing.fixerTimeline.addressed') }}
|
|
525
539
|
</p>
|
|
526
540
|
<ul class="mt-1 space-y-0.5">
|
|
527
541
|
<li
|
|
528
542
|
v-for="(c, ci) in a.concerns"
|
|
529
543
|
:key="`fa${a.attempt}-c${ci}`"
|
|
530
|
-
class="flex items-center gap-1.5 text-[12px] text-
|
|
544
|
+
class="flex items-center gap-1.5 text-[12px] text-toned"
|
|
531
545
|
>
|
|
532
546
|
<span
|
|
533
547
|
class="rounded px-1 text-[10px] uppercase"
|
|
@@ -552,12 +566,12 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
552
566
|
class="space-y-2"
|
|
553
567
|
>
|
|
554
568
|
<div class="flex items-center gap-2">
|
|
555
|
-
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-
|
|
569
|
+
<h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
556
570
|
{{ t('testing.quality.heading') }}
|
|
557
571
|
</h3>
|
|
558
572
|
<span
|
|
559
573
|
v-if="quality.attempts"
|
|
560
|
-
class="text-[11px] text-
|
|
574
|
+
class="text-[11px] text-muted"
|
|
561
575
|
:title="t('testing.quality.reruns')"
|
|
562
576
|
>
|
|
563
577
|
{{
|
|
@@ -582,40 +596,43 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
582
596
|
v-for="(vd, vi) in qualityVerdicts"
|
|
583
597
|
:key="`qc${vi}`"
|
|
584
598
|
data-testid="tester-quality-verdict"
|
|
585
|
-
class="rounded-lg border border-
|
|
599
|
+
class="rounded-lg border border-default bg-default/60 px-3 py-2"
|
|
586
600
|
>
|
|
587
601
|
<div class="flex items-center gap-2">
|
|
588
602
|
<UIcon
|
|
589
603
|
:name="vd.adequate ? 'i-lucide-shield-check' : 'i-lucide-shield-alert'"
|
|
590
604
|
class="h-3.5 w-3.5 shrink-0"
|
|
591
|
-
:class="vd.adequate ? 'text-
|
|
605
|
+
:class="vd.adequate ? 'text-app-success-400' : 'text-app-warning-300'"
|
|
592
606
|
/>
|
|
593
|
-
<span class="text-[13px] font-medium text-
|
|
607
|
+
<span class="text-[13px] font-medium text-default">
|
|
594
608
|
{{
|
|
595
609
|
vd.adequate ? t('testing.quality.adequate') : t('testing.quality.inadequate')
|
|
596
610
|
}}
|
|
597
611
|
</span>
|
|
598
|
-
<span v-if="vd.model" class="ms-auto font-mono text-[10px] text-
|
|
612
|
+
<span v-if="vd.model" class="ms-auto font-mono text-[10px] text-dimmed">{{
|
|
599
613
|
vd.model
|
|
600
614
|
}}</span>
|
|
601
|
-
<span class="text-[11px] text-
|
|
615
|
+
<span class="text-[11px] text-dimmed" :class="{ 'ms-auto': !vd.model }">{{
|
|
602
616
|
d(new Date(vd.at), 'short')
|
|
603
617
|
}}</span>
|
|
604
618
|
</div>
|
|
605
619
|
<MarkdownProse
|
|
606
620
|
v-if="vd.feedback"
|
|
607
621
|
:text="vd.feedback"
|
|
608
|
-
class="mt-1 text-[12px] leading-snug text-
|
|
622
|
+
class="mt-1 text-[12px] leading-snug text-muted"
|
|
609
623
|
/>
|
|
610
624
|
<div v-if="vd.gaps.length" class="mt-1.5">
|
|
611
|
-
<p class="text-[11px] text-
|
|
625
|
+
<p class="text-[11px] text-dimmed">{{ t('testing.quality.gaps') }}</p>
|
|
612
626
|
<ul class="mt-1 space-y-0.5">
|
|
613
627
|
<li
|
|
614
628
|
v-for="(gap, gi) in vd.gaps"
|
|
615
629
|
:key="`qc${vi}-g${gi}`"
|
|
616
|
-
class="flex items-start gap-1.5 text-[12px] text-
|
|
630
|
+
class="flex items-start gap-1.5 text-[12px] text-toned"
|
|
617
631
|
>
|
|
618
|
-
<UIcon
|
|
632
|
+
<UIcon
|
|
633
|
+
name="i-lucide-dot"
|
|
634
|
+
class="mt-0.5 h-3.5 w-3.5 shrink-0 text-app-warning-400"
|
|
635
|
+
/>
|
|
619
636
|
<span>{{ gap }}</span>
|
|
620
637
|
</li>
|
|
621
638
|
</ul>
|
|
@@ -626,11 +643,11 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
626
643
|
|
|
627
644
|
<div
|
|
628
645
|
v-if="!report"
|
|
629
|
-
class="flex flex-col items-center justify-center gap-2 py-12 text-center text-
|
|
646
|
+
class="flex flex-col items-center justify-center gap-2 py-12 text-center text-muted"
|
|
630
647
|
>
|
|
631
648
|
<UIcon name="i-lucide-flask-conical" class="h-8 w-8 opacity-40" />
|
|
632
649
|
<p class="text-sm">{{ t('testing.empty.title') }}</p>
|
|
633
|
-
<p class="max-w-sm text-[11px] text-
|
|
650
|
+
<p class="max-w-sm text-[11px] text-dimmed">
|
|
634
651
|
{{ t('testing.empty.hint') }}
|
|
635
652
|
</p>
|
|
636
653
|
</div>
|
|
@@ -642,25 +659,25 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
642
659
|
<MarkdownProse
|
|
643
660
|
v-if="report.summary"
|
|
644
661
|
:text="report.summary"
|
|
645
|
-
class="mb-4 max-w-3xl text-[13px] leading-relaxed text-
|
|
662
|
+
class="mb-4 max-w-3xl text-[13px] leading-relaxed text-toned"
|
|
646
663
|
/>
|
|
647
664
|
|
|
648
|
-
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-
|
|
665
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
649
666
|
{{ t('testing.scenariosOutcomes') }}
|
|
650
667
|
</h3>
|
|
651
668
|
<ul class="space-y-2">
|
|
652
669
|
<li
|
|
653
670
|
v-for="g in groups"
|
|
654
671
|
:key="g.key"
|
|
655
|
-
class="overflow-hidden rounded-lg border border-
|
|
672
|
+
class="overflow-hidden rounded-lg border border-default bg-default/60"
|
|
656
673
|
>
|
|
657
674
|
<button
|
|
658
|
-
class="flex w-full items-center gap-2 px-3 py-2 text-start hover:bg-
|
|
675
|
+
class="flex w-full items-center gap-2 px-3 py-2 text-start hover:bg-elevated/40"
|
|
659
676
|
@click="toggle(g.key)"
|
|
660
677
|
>
|
|
661
678
|
<UIcon
|
|
662
679
|
:name="collapsed.has(g.key) ? 'i-lucide-chevron-right' : 'i-lucide-chevron-down'"
|
|
663
|
-
class="h-3.5 w-3.5 shrink-0 text-
|
|
680
|
+
class="h-3.5 w-3.5 shrink-0 text-dimmed"
|
|
664
681
|
/>
|
|
665
682
|
<UIcon
|
|
666
683
|
:name="GROUP_STATUS_META[g.status].icon"
|
|
@@ -669,14 +686,14 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
669
686
|
/>
|
|
670
687
|
<span
|
|
671
688
|
class="min-w-0 flex-1 truncate text-[13px]"
|
|
672
|
-
:class="g.other ? 'text-
|
|
689
|
+
:class="g.other ? 'text-muted' : 'font-medium text-default'"
|
|
673
690
|
>
|
|
674
691
|
{{ g.title }}
|
|
675
692
|
</span>
|
|
676
693
|
<UIcon
|
|
677
694
|
v-if="g.screenshots.length"
|
|
678
695
|
name="i-lucide-camera"
|
|
679
|
-
class="h-3.5 w-3.5 shrink-0 text-
|
|
696
|
+
class="h-3.5 w-3.5 shrink-0 text-dimmed"
|
|
680
697
|
:title="
|
|
681
698
|
t(
|
|
682
699
|
'testing.screenshotCount',
|
|
@@ -685,7 +702,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
685
702
|
)
|
|
686
703
|
"
|
|
687
704
|
/>
|
|
688
|
-
<span class="shrink-0 text-[11px] text-
|
|
705
|
+
<span class="shrink-0 text-[11px] text-dimmed">
|
|
689
706
|
{{ t('testing.checkCount', { count: g.outcomes.length }, g.outcomes.length) }}
|
|
690
707
|
<template v-if="g.concerns.length">
|
|
691
708
|
·
|
|
@@ -707,15 +724,15 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
707
724
|
:class="STATUS_META[o.status].text"
|
|
708
725
|
/>
|
|
709
726
|
<div class="min-w-0">
|
|
710
|
-
<span class="text-[13px] text-
|
|
727
|
+
<span class="text-[13px] text-default">{{ o.name }}</span>
|
|
711
728
|
<MarkdownProse
|
|
712
729
|
v-if="o.detail"
|
|
713
730
|
:text="o.detail"
|
|
714
|
-
class="max-w-3xl text-[12px] leading-snug text-
|
|
731
|
+
class="max-w-3xl text-[12px] leading-snug text-muted"
|
|
715
732
|
/>
|
|
716
733
|
</div>
|
|
717
734
|
</div>
|
|
718
|
-
<p v-if="!g.outcomes.length" class="py-0.5 text-[12px] italic text-
|
|
735
|
+
<p v-if="!g.outcomes.length" class="py-0.5 text-[12px] italic text-dimmed">
|
|
719
736
|
{{ t('testing.noDiscreteCheck') }}
|
|
720
737
|
</p>
|
|
721
738
|
|
|
@@ -723,7 +740,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
723
740
|
<div
|
|
724
741
|
v-for="(c, ci) in g.concerns"
|
|
725
742
|
:key="`c${ci}`"
|
|
726
|
-
class="mt-1 flex items-start gap-2 rounded-md border border-
|
|
743
|
+
class="mt-1 flex items-start gap-2 rounded-md border border-default bg-app-950/40 px-2 py-1.5"
|
|
727
744
|
>
|
|
728
745
|
<UIcon
|
|
729
746
|
name="i-lucide-alert-triangle"
|
|
@@ -732,7 +749,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
732
749
|
/>
|
|
733
750
|
<div class="min-w-0">
|
|
734
751
|
<div class="flex items-center gap-1.5">
|
|
735
|
-
<span class="text-[12px] font-medium text-
|
|
752
|
+
<span class="text-[12px] font-medium text-default">{{ c.title }}</span>
|
|
736
753
|
<span
|
|
737
754
|
class="rounded px-1 text-[10px] uppercase"
|
|
738
755
|
:class="SEVERITY_META[c.severity].chip"
|
|
@@ -743,7 +760,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
743
760
|
<MarkdownProse
|
|
744
761
|
v-if="c.detail"
|
|
745
762
|
:text="c.detail"
|
|
746
|
-
class="max-w-3xl text-[12px] leading-snug text-
|
|
763
|
+
class="max-w-3xl text-[12px] leading-snug text-muted"
|
|
747
764
|
/>
|
|
748
765
|
</div>
|
|
749
766
|
</div>
|
|
@@ -754,7 +771,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
754
771
|
v-for="(s, si) in g.screenshots"
|
|
755
772
|
:key="`shot${si}`"
|
|
756
773
|
data-testid="tester-screenshot"
|
|
757
|
-
class="group relative h-20 w-28 shrink-0 overflow-hidden rounded border border-
|
|
774
|
+
class="group relative h-20 w-28 shrink-0 overflow-hidden rounded border border-default bg-app-950/60 hover:border-app-600"
|
|
758
775
|
:title="s.view"
|
|
759
776
|
@click="openShot(s.artifactId)"
|
|
760
777
|
>
|
|
@@ -766,7 +783,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
766
783
|
/>
|
|
767
784
|
<span
|
|
768
785
|
v-else
|
|
769
|
-
class="flex h-full w-full items-center justify-center text-[10px] text-
|
|
786
|
+
class="flex h-full w-full items-center justify-center text-[10px] text-app-600"
|
|
770
787
|
>
|
|
771
788
|
{{
|
|
772
789
|
blobs.statusFor(s.artifactId) === 'error'
|
|
@@ -775,7 +792,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
775
792
|
}}
|
|
776
793
|
</span>
|
|
777
794
|
<span
|
|
778
|
-
class="absolute inset-x-0 bottom-0 truncate bg-
|
|
795
|
+
class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1 py-0.5 text-[9px] text-toned"
|
|
779
796
|
>{{ s.view }}</span
|
|
780
797
|
>
|
|
781
798
|
</button>
|
|
@@ -786,14 +803,14 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
786
803
|
|
|
787
804
|
<!-- Standalone gallery: any captures not mapped to a scenario above -->
|
|
788
805
|
<section v-if="ungroupedScreenshots.length" class="mt-5">
|
|
789
|
-
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-
|
|
806
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
790
807
|
{{ t('testing.screenshots') }}
|
|
791
808
|
</h3>
|
|
792
809
|
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3">
|
|
793
810
|
<button
|
|
794
811
|
v-for="(s, si) in ungroupedScreenshots"
|
|
795
812
|
:key="`gal${si}`"
|
|
796
|
-
class="group relative aspect-video overflow-hidden rounded-lg border border-
|
|
813
|
+
class="group relative aspect-video overflow-hidden rounded-lg border border-default bg-app-950/60 hover:border-app-600"
|
|
797
814
|
:title="s.view"
|
|
798
815
|
@click="openShot(s.artifactId)"
|
|
799
816
|
>
|
|
@@ -805,7 +822,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
805
822
|
/>
|
|
806
823
|
<span
|
|
807
824
|
v-else
|
|
808
|
-
class="flex h-full w-full items-center justify-center text-[11px] text-
|
|
825
|
+
class="flex h-full w-full items-center justify-center text-[11px] text-app-600"
|
|
809
826
|
>
|
|
810
827
|
{{
|
|
811
828
|
blobs.statusFor(s.artifactId) === 'error'
|
|
@@ -814,7 +831,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
814
831
|
}}
|
|
815
832
|
</span>
|
|
816
833
|
<span
|
|
817
|
-
class="absolute inset-x-0 bottom-0 truncate bg-
|
|
834
|
+
class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1.5 py-0.5 text-[10px] text-toned"
|
|
818
835
|
>{{ s.view }}</span
|
|
819
836
|
>
|
|
820
837
|
</button>
|
|
@@ -825,44 +842,44 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
825
842
|
|
|
826
843
|
<!-- Sidebar: metadata -->
|
|
827
844
|
<aside
|
|
828
|
-
class="hidden w-60 shrink-0 flex-col gap-4 border-s border-
|
|
845
|
+
class="hidden w-60 shrink-0 flex-col gap-4 border-s border-default bg-default/50 px-4 py-4 lg:flex"
|
|
829
846
|
>
|
|
830
847
|
<div v-if="report">
|
|
831
|
-
<h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-
|
|
848
|
+
<h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
832
849
|
{{ t('testing.verdict.heading') }}
|
|
833
850
|
</h4>
|
|
834
851
|
<div class="flex items-center gap-2 text-[13px]">
|
|
835
852
|
<UIcon
|
|
836
853
|
:name="report.greenlight ? 'i-lucide-circle-check' : 'i-lucide-circle-x'"
|
|
837
854
|
class="h-4 w-4"
|
|
838
|
-
:class="report.greenlight ? 'text-
|
|
855
|
+
:class="report.greenlight ? 'text-app-success-400' : 'text-app-error-400'"
|
|
839
856
|
/>
|
|
840
|
-
<span :class="report.greenlight ? 'text-
|
|
857
|
+
<span :class="report.greenlight ? 'text-app-success-300' : 'text-app-error-300'">
|
|
841
858
|
{{ report.greenlight ? t('testing.verdict.safe') : t('testing.verdict.withheld') }}
|
|
842
859
|
</span>
|
|
843
860
|
</div>
|
|
844
861
|
</div>
|
|
845
862
|
|
|
846
863
|
<div v-if="report">
|
|
847
|
-
<h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-
|
|
864
|
+
<h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
848
865
|
{{ t('testing.outcomes.heading') }}
|
|
849
866
|
</h4>
|
|
850
867
|
<dl class="space-y-1 text-[12px]">
|
|
851
868
|
<div class="flex items-center justify-between">
|
|
852
|
-
<dt class="text-
|
|
853
|
-
<dd class="text-
|
|
869
|
+
<dt class="text-muted">{{ t('testing.outcomes.passed') }}</dt>
|
|
870
|
+
<dd class="text-app-success-300">{{ counts.passed }}</dd>
|
|
854
871
|
</div>
|
|
855
872
|
<div class="flex items-center justify-between">
|
|
856
|
-
<dt class="text-
|
|
857
|
-
<dd class="text-
|
|
873
|
+
<dt class="text-muted">{{ t('testing.outcomes.failed') }}</dt>
|
|
874
|
+
<dd class="text-app-error-300">{{ counts.failed }}</dd>
|
|
858
875
|
</div>
|
|
859
876
|
<div class="flex items-center justify-between">
|
|
860
|
-
<dt class="text-
|
|
861
|
-
<dd class="text-
|
|
877
|
+
<dt class="text-muted">{{ t('testing.outcomes.skipped') }}</dt>
|
|
878
|
+
<dd class="text-toned">{{ counts.skipped }}</dd>
|
|
862
879
|
</div>
|
|
863
|
-
<div class="flex items-center justify-between border-t border-
|
|
864
|
-
<dt class="text-
|
|
865
|
-
<dd class="text-
|
|
880
|
+
<div class="flex items-center justify-between border-t border-default pt-1">
|
|
881
|
+
<dt class="text-muted">{{ t('testing.outcomes.concerns') }}</dt>
|
|
882
|
+
<dd class="text-app-warning-300">
|
|
866
883
|
{{ counts.concerns
|
|
867
884
|
}}<template v-if="counts.blocking">
|
|
868
885
|
{{
|
|
@@ -875,10 +892,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
875
892
|
</div>
|
|
876
893
|
|
|
877
894
|
<div v-if="report?.environment">
|
|
878
|
-
<h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-
|
|
895
|
+
<h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
|
|
879
896
|
{{ t('testing.environment') }}
|
|
880
897
|
</h4>
|
|
881
|
-
<p class="text-[12px] capitalize text-
|
|
898
|
+
<p class="text-[12px] capitalize text-toned">{{ report.environment }}</p>
|
|
882
899
|
</div>
|
|
883
900
|
|
|
884
901
|
<!-- Shared run metadata + embedded observability (model, run id, timing,
|
|
@@ -893,7 +910,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
|
|
|
893
910
|
:failure-at="instance?.failure?.occurredAt"
|
|
894
911
|
/>
|
|
895
912
|
|
|
896
|
-
<p class="mt-auto text-[10px] leading-relaxed text-
|
|
913
|
+
<p class="mt-auto text-[10px] leading-relaxed text-app-600">
|
|
897
914
|
{{ t('testing.footer') }}
|
|
898
915
|
</p>
|
|
899
916
|
</aside>
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
|
+
import { useThemeStore } from '~/stores/theme'
|
|
4
|
+
import { decodeThemeLink, type ThemeLinkDecodeResult } from '~/utils/theme/link'
|
|
5
|
+
|
|
6
|
+
// Import a theme built in the Nuxt UI theme editor (https://ui.nuxt.com/theme): the user pastes
|
|
7
|
+
// the editor's share link (or the raw document JSON), names it, and the theme is stored in this
|
|
8
|
+
// browser and applied. The document format is the editor's own (`utils/theme/doc.ts`), so there
|
|
9
|
+
// is no translation step to get wrong: what the editor previewed is what the app renders.
|
|
10
|
+
const open = defineModel<boolean>('open', { default: false })
|
|
11
|
+
|
|
12
|
+
const { t } = useI18n()
|
|
13
|
+
const theme = useThemeStore()
|
|
14
|
+
|
|
15
|
+
const link = ref('')
|
|
16
|
+
const name = ref('')
|
|
17
|
+
const error = ref<Extract<ThemeLinkDecodeResult, { ok: false }>['reason'] | null>(null)
|
|
18
|
+
const busy = ref(false)
|
|
19
|
+
|
|
20
|
+
// The name the theme will actually be saved under. Shown as help text only when it differs from
|
|
21
|
+
// what was typed, so a taken name is explained before the import rather than discovered after.
|
|
22
|
+
const resolvedName = computed(() => {
|
|
23
|
+
const requested = name.value.trim()
|
|
24
|
+
return requested ? theme.uniqueName(requested) : ''
|
|
25
|
+
})
|
|
26
|
+
const nameTaken = computed(
|
|
27
|
+
() => resolvedName.value !== '' && resolvedName.value !== name.value.trim(),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
// Static literal keys per decode outcome, so the typed-message-keys check sees them.
|
|
31
|
+
const ERROR_KEYS: Record<NonNullable<typeof error.value>, string> = {
|
|
32
|
+
not_a_link: 'appearance.import.error.notALink',
|
|
33
|
+
malformed: 'appearance.import.error.malformed',
|
|
34
|
+
preset_shorthand: 'appearance.import.error.presetShorthand',
|
|
35
|
+
unsupported_version: 'appearance.import.error.unsupportedVersion',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
watch(open, (isOpen) => {
|
|
39
|
+
if (!isOpen) return
|
|
40
|
+
link.value = ''
|
|
41
|
+
name.value = ''
|
|
42
|
+
error.value = null
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
async function submit() {
|
|
46
|
+
busy.value = true
|
|
47
|
+
try {
|
|
48
|
+
const result = await decodeThemeLink(link.value)
|
|
49
|
+
if (!result.ok) {
|
|
50
|
+
error.value = result.reason
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
error.value = null
|
|
54
|
+
theme.addCustom(name.value, result.doc)
|
|
55
|
+
open.value = false
|
|
56
|
+
} finally {
|
|
57
|
+
busy.value = false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<UModal
|
|
64
|
+
v-model:open="open"
|
|
65
|
+
:title="t('appearance.import.title')"
|
|
66
|
+
:description="t('appearance.import.description')"
|
|
67
|
+
>
|
|
68
|
+
<template #body>
|
|
69
|
+
<form class="space-y-4" data-testid="theme-import-form" @submit.prevent="submit">
|
|
70
|
+
<UFormField
|
|
71
|
+
:label="t('appearance.import.linkLabel')"
|
|
72
|
+
:error="error ? t(ERROR_KEYS[error]) : undefined"
|
|
73
|
+
>
|
|
74
|
+
<UTextarea
|
|
75
|
+
v-model="link"
|
|
76
|
+
:rows="3"
|
|
77
|
+
autoresize
|
|
78
|
+
class="w-full font-mono text-xs"
|
|
79
|
+
:placeholder="t('appearance.import.linkPlaceholder')"
|
|
80
|
+
data-testid="theme-import-link"
|
|
81
|
+
/>
|
|
82
|
+
</UFormField>
|
|
83
|
+
<UFormField
|
|
84
|
+
:label="t('appearance.import.nameLabel')"
|
|
85
|
+
:help="
|
|
86
|
+
nameTaken
|
|
87
|
+
? t('appearance.import.nameTaken', { typed: name.trim(), name: resolvedName })
|
|
88
|
+
: undefined
|
|
89
|
+
"
|
|
90
|
+
>
|
|
91
|
+
<UInput
|
|
92
|
+
v-model="name"
|
|
93
|
+
class="w-full"
|
|
94
|
+
:placeholder="t('appearance.import.namePlaceholder')"
|
|
95
|
+
data-testid="theme-import-name"
|
|
96
|
+
/>
|
|
97
|
+
</UFormField>
|
|
98
|
+
<p class="text-xs text-muted">{{ t('appearance.import.fontNote') }}</p>
|
|
99
|
+
<div class="flex justify-end gap-2">
|
|
100
|
+
<UButton color="neutral" variant="ghost" @click="open = false">
|
|
101
|
+
{{ t('appearance.import.cancel') }}
|
|
102
|
+
</UButton>
|
|
103
|
+
<UButton
|
|
104
|
+
type="submit"
|
|
105
|
+
:loading="busy"
|
|
106
|
+
:disabled="!link.trim()"
|
|
107
|
+
data-testid="theme-import-submit"
|
|
108
|
+
>
|
|
109
|
+
{{ t('appearance.import.submit') }}
|
|
110
|
+
</UButton>
|
|
111
|
+
</div>
|
|
112
|
+
</form>
|
|
113
|
+
</template>
|
|
114
|
+
</UModal>
|
|
115
|
+
</template>
|