@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
|
@@ -24,6 +24,7 @@ import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
|
24
24
|
import type { AppSlots } from '~/modular/slots'
|
|
25
25
|
import { usePipelinesStore } from '~/stores/pipelines'
|
|
26
26
|
import { pipelineAllowedForTaskType } from '~/utils/pipeline'
|
|
27
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
27
28
|
|
|
28
29
|
const { t, te } = useI18n()
|
|
29
30
|
const ui = useUiStore()
|
|
@@ -360,7 +361,7 @@ async function save() {
|
|
|
360
361
|
<h3 class="text-sm font-semibold text-default">
|
|
361
362
|
{{ t('settings.workspaceSettings.waiting.heading') }}
|
|
362
363
|
</h3>
|
|
363
|
-
<p class="text-
|
|
364
|
+
<p class="text-2xs text-muted">
|
|
364
365
|
<i18n-t keypath="settings.workspaceSettings.waiting.body" tag="span" scope="global">
|
|
365
366
|
<template #overdue>
|
|
366
367
|
<span class="text-app-error-400">{{
|
|
@@ -369,11 +370,12 @@ async function save() {
|
|
|
369
370
|
</template>
|
|
370
371
|
</i18n-t>
|
|
371
372
|
</p>
|
|
372
|
-
<label class="block
|
|
373
|
-
<span class="mb-1 block
|
|
373
|
+
<label class="block">
|
|
374
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
374
375
|
{{ t('settings.workspaceSettings.waiting.escalateAfter') }}
|
|
375
|
-
</
|
|
376
|
+
</SectionLabel>
|
|
376
377
|
<UInput
|
|
378
|
+
class="w-48"
|
|
377
379
|
v-model.number="draft.waitingEscalationMinutes"
|
|
378
380
|
type="number"
|
|
379
381
|
:min="1"
|
|
@@ -387,34 +389,40 @@ async function save() {
|
|
|
387
389
|
<h3 class="text-sm font-semibold text-default">
|
|
388
390
|
{{ t('settings.workspaceSettings.taskLimit.heading') }}
|
|
389
391
|
</h3>
|
|
390
|
-
<p class="text-
|
|
392
|
+
<p class="text-2xs text-muted">
|
|
391
393
|
{{ t('settings.workspaceSettings.taskLimit.body') }}
|
|
392
394
|
</p>
|
|
393
|
-
<label class="block
|
|
394
|
-
<span class="mb-1 block
|
|
395
|
+
<label class="block">
|
|
396
|
+
<SectionLabel as="span" class="mb-1 block">{{
|
|
395
397
|
t('settings.workspaceSettings.taskLimit.mode')
|
|
396
|
-
}}</
|
|
398
|
+
}}</SectionLabel>
|
|
397
399
|
<USelect
|
|
398
400
|
v-model="draft.taskLimitMode"
|
|
399
401
|
:items="MODES"
|
|
400
402
|
value-key="value"
|
|
401
403
|
size="sm"
|
|
402
|
-
class="w-
|
|
404
|
+
class="w-64"
|
|
403
405
|
/>
|
|
404
406
|
</label>
|
|
405
407
|
|
|
406
|
-
<label v-if="draft.taskLimitMode === 'shared'" class="block
|
|
407
|
-
<span class="mb-1 block
|
|
408
|
+
<label v-if="draft.taskLimitMode === 'shared'" class="block">
|
|
409
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
408
410
|
{{ t('settings.workspaceSettings.taskLimit.maxRunning') }}
|
|
409
|
-
</
|
|
410
|
-
<UInput
|
|
411
|
+
</SectionLabel>
|
|
412
|
+
<UInput
|
|
413
|
+
class="w-48"
|
|
414
|
+
v-model.number="draft.taskLimitShared"
|
|
415
|
+
type="number"
|
|
416
|
+
:min="1"
|
|
417
|
+
size="sm"
|
|
418
|
+
/>
|
|
411
419
|
</label>
|
|
412
420
|
|
|
413
421
|
<div v-else-if="draft.taskLimitMode === 'per_type'" class="grid grid-cols-2 gap-3">
|
|
414
422
|
<label v-for="taskType in TASK_TYPES" :key="taskType" class="block">
|
|
415
|
-
<span class="mb-1 block
|
|
423
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
416
424
|
{{ maxTaskTypeLabel(taskType) }}
|
|
417
|
-
</
|
|
425
|
+
</SectionLabel>
|
|
418
426
|
<UInput
|
|
419
427
|
v-model.number="draft.perType[taskType]"
|
|
420
428
|
type="number"
|
|
@@ -431,19 +439,19 @@ async function save() {
|
|
|
431
439
|
<h3 class="text-sm font-semibold text-default">
|
|
432
440
|
{{ t('settings.workspaceSettings.inputGate.heading') }}
|
|
433
441
|
</h3>
|
|
434
|
-
<p class="text-
|
|
442
|
+
<p class="text-2xs text-muted">
|
|
435
443
|
{{ t('settings.workspaceSettings.inputGate.body') }}
|
|
436
444
|
</p>
|
|
437
|
-
<label class="block
|
|
438
|
-
<span class="mb-1 block
|
|
445
|
+
<label class="block">
|
|
446
|
+
<SectionLabel as="span" class="mb-1 block">{{
|
|
439
447
|
t('settings.workspaceSettings.inputGate.mode')
|
|
440
|
-
}}</
|
|
448
|
+
}}</SectionLabel>
|
|
441
449
|
<USelect
|
|
442
450
|
v-model="draft.inputGateMode"
|
|
443
451
|
:items="INPUT_GATE_MODES"
|
|
444
452
|
value-key="value"
|
|
445
453
|
size="sm"
|
|
446
|
-
class="w-
|
|
454
|
+
class="w-64"
|
|
447
455
|
data-testid="input-gate-mode"
|
|
448
456
|
/>
|
|
449
457
|
</label>
|
|
@@ -454,27 +462,28 @@ async function save() {
|
|
|
454
462
|
<h3 class="text-sm font-semibold text-default">
|
|
455
463
|
{{ t('settings.workspaceSettings.reviewFriction.heading') }}
|
|
456
464
|
</h3>
|
|
457
|
-
<p class="text-
|
|
465
|
+
<p class="text-2xs text-muted">
|
|
458
466
|
{{ t('settings.workspaceSettings.reviewFriction.body') }}
|
|
459
467
|
</p>
|
|
460
|
-
<label class="block
|
|
461
|
-
<span class="mb-1 block
|
|
468
|
+
<label class="block">
|
|
469
|
+
<SectionLabel as="span" class="mb-1 block">{{
|
|
462
470
|
t('settings.workspaceSettings.reviewFriction.mode')
|
|
463
|
-
}}</
|
|
471
|
+
}}</SectionLabel>
|
|
464
472
|
<USelect
|
|
465
473
|
v-model="draft.reviewFrictionMode"
|
|
466
474
|
:items="REVIEW_FRICTION_MODES"
|
|
467
475
|
value-key="value"
|
|
468
476
|
size="sm"
|
|
469
|
-
class="w-
|
|
477
|
+
class="w-64"
|
|
470
478
|
/>
|
|
471
479
|
</label>
|
|
472
480
|
|
|
473
|
-
<label v-if="draft.reviewFrictionMode !== 'off'" class="block
|
|
474
|
-
<span class="mb-1 block
|
|
481
|
+
<label v-if="draft.reviewFrictionMode !== 'off'" class="block">
|
|
482
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
475
483
|
{{ t('settings.workspaceSettings.reviewFriction.warnCount') }}
|
|
476
|
-
</
|
|
484
|
+
</SectionLabel>
|
|
477
485
|
<UInput
|
|
486
|
+
class="w-48"
|
|
478
487
|
v-model.number="draft.reviewFrictionWarnCount"
|
|
479
488
|
type="number"
|
|
480
489
|
:min="1"
|
|
@@ -483,20 +492,21 @@ async function save() {
|
|
|
483
492
|
</label>
|
|
484
493
|
|
|
485
494
|
<div v-if="draft.reviewFrictionMode === 'enforce'" class="space-y-2">
|
|
486
|
-
<p class="text-
|
|
495
|
+
<p class="text-2xs text-muted">
|
|
487
496
|
{{ t('settings.workspaceSettings.reviewFriction.enforceHint') }}
|
|
488
497
|
</p>
|
|
489
498
|
<label class="flex items-center gap-2">
|
|
490
499
|
<USwitch v-model="draft.reviewFrictionBlockCountEnabled" size="sm" />
|
|
491
|
-
<span class="text-
|
|
500
|
+
<span class="text-sm text-toned">{{
|
|
492
501
|
t('settings.workspaceSettings.reviewFriction.blockCountToggle')
|
|
493
502
|
}}</span>
|
|
494
503
|
</label>
|
|
495
|
-
<label v-if="draft.reviewFrictionBlockCountEnabled" class="block
|
|
496
|
-
<span class="mb-1 block
|
|
504
|
+
<label v-if="draft.reviewFrictionBlockCountEnabled" class="block">
|
|
505
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
497
506
|
{{ t('settings.workspaceSettings.reviewFriction.blockCount') }}
|
|
498
|
-
</
|
|
507
|
+
</SectionLabel>
|
|
499
508
|
<UInput
|
|
509
|
+
class="w-48"
|
|
500
510
|
v-model.number="draft.reviewFrictionBlockCount"
|
|
501
511
|
type="number"
|
|
502
512
|
:min="1"
|
|
@@ -505,15 +515,16 @@ async function save() {
|
|
|
505
515
|
</label>
|
|
506
516
|
<label class="flex items-center gap-2">
|
|
507
517
|
<USwitch v-model="draft.reviewFrictionBlockStuckEnabled" size="sm" />
|
|
508
|
-
<span class="text-
|
|
518
|
+
<span class="text-sm text-toned">{{
|
|
509
519
|
t('settings.workspaceSettings.reviewFriction.blockStuckToggle')
|
|
510
520
|
}}</span>
|
|
511
521
|
</label>
|
|
512
|
-
<label v-if="draft.reviewFrictionBlockStuckEnabled" class="block
|
|
513
|
-
<span class="mb-1 block
|
|
522
|
+
<label v-if="draft.reviewFrictionBlockStuckEnabled" class="block">
|
|
523
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
514
524
|
{{ t('settings.workspaceSettings.reviewFriction.blockStuckMinutes') }}
|
|
515
|
-
</
|
|
525
|
+
</SectionLabel>
|
|
516
526
|
<UInput
|
|
527
|
+
class="w-48"
|
|
517
528
|
v-model.number="draft.reviewFrictionBlockStuckMinutes"
|
|
518
529
|
type="number"
|
|
519
530
|
:min="1"
|
|
@@ -528,7 +539,7 @@ async function save() {
|
|
|
528
539
|
<h3 class="text-sm font-semibold text-default">
|
|
529
540
|
{{ t('settings.workspaceSettings.observability.heading') }}
|
|
530
541
|
</h3>
|
|
531
|
-
<p class="text-
|
|
542
|
+
<p class="text-2xs text-muted">
|
|
532
543
|
{{ t('settings.workspaceSettings.observability.body') }}
|
|
533
544
|
</p>
|
|
534
545
|
<label class="flex items-center gap-2">
|
|
@@ -544,7 +555,7 @@ async function save() {
|
|
|
544
555
|
<h3 class="text-sm font-semibold text-default">
|
|
545
556
|
{{ t('settings.workspaceSettings.prReport.heading') }}
|
|
546
557
|
</h3>
|
|
547
|
-
<p class="text-
|
|
558
|
+
<p class="text-2xs text-muted">
|
|
548
559
|
{{ t('settings.workspaceSettings.prReport.body') }}
|
|
549
560
|
</p>
|
|
550
561
|
<label class="flex items-center gap-2">
|
|
@@ -560,14 +571,15 @@ async function save() {
|
|
|
560
571
|
<h3 class="text-sm font-semibold text-default">
|
|
561
572
|
{{ t('settings.workspaceSettings.retention.heading') }}
|
|
562
573
|
</h3>
|
|
563
|
-
<p class="text-
|
|
574
|
+
<p class="text-2xs text-muted">
|
|
564
575
|
{{ t('settings.workspaceSettings.retention.body') }}
|
|
565
576
|
</p>
|
|
566
|
-
<label class="block
|
|
567
|
-
<span class="mb-1 block
|
|
577
|
+
<label class="block">
|
|
578
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
568
579
|
{{ t('settings.workspaceSettings.retention.days') }}
|
|
569
|
-
</
|
|
580
|
+
</SectionLabel>
|
|
570
581
|
<UInput
|
|
582
|
+
class="w-48"
|
|
571
583
|
v-model.number="draft.artifactRetentionDays"
|
|
572
584
|
type="number"
|
|
573
585
|
:min="1"
|
|
@@ -582,14 +594,15 @@ async function save() {
|
|
|
582
594
|
<h3 class="text-sm font-semibold text-default">
|
|
583
595
|
{{ t('settings.workspaceSettings.doneLane.heading') }}
|
|
584
596
|
</h3>
|
|
585
|
-
<p class="text-
|
|
597
|
+
<p class="text-2xs text-muted">
|
|
586
598
|
{{ t('settings.workspaceSettings.doneLane.body') }}
|
|
587
599
|
</p>
|
|
588
|
-
<label class="block
|
|
589
|
-
<span class="mb-1 block
|
|
600
|
+
<label class="block">
|
|
601
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
590
602
|
{{ t('settings.workspaceSettings.doneLane.maxItems') }}
|
|
591
|
-
</
|
|
603
|
+
</SectionLabel>
|
|
592
604
|
<UInput
|
|
605
|
+
class="w-48"
|
|
593
606
|
v-model.number="draft.doneLaneMaxItems"
|
|
594
607
|
type="number"
|
|
595
608
|
:min="0"
|
|
@@ -598,20 +611,21 @@ async function save() {
|
|
|
598
611
|
data-testid="done-lane-max-items"
|
|
599
612
|
/>
|
|
600
613
|
</label>
|
|
601
|
-
<p v-if="draft.doneLaneMaxItems === 0" class="text-
|
|
614
|
+
<p v-if="draft.doneLaneMaxItems === 0" class="text-2xs text-dimmed">
|
|
602
615
|
{{ t('settings.workspaceSettings.doneLane.zeroHint') }}
|
|
603
616
|
</p>
|
|
604
617
|
<label class="flex items-center gap-2">
|
|
605
618
|
<UCheckbox v-model="draft.doneLaneRetentionEnabled" size="sm" />
|
|
606
|
-
<span class="text-
|
|
619
|
+
<span class="text-2xs text-toned">{{
|
|
607
620
|
t('settings.workspaceSettings.doneLane.ageToggle')
|
|
608
621
|
}}</span>
|
|
609
622
|
</label>
|
|
610
|
-
<label v-if="draft.doneLaneRetentionEnabled" class="block
|
|
611
|
-
<span class="mb-1 block
|
|
623
|
+
<label v-if="draft.doneLaneRetentionEnabled" class="block">
|
|
624
|
+
<SectionLabel as="span" class="mb-1 block">
|
|
612
625
|
{{ t('settings.workspaceSettings.doneLane.days') }}
|
|
613
|
-
</
|
|
626
|
+
</SectionLabel>
|
|
614
627
|
<UInput
|
|
628
|
+
class="w-48"
|
|
615
629
|
v-model.number="draft.doneLaneRetentionDays"
|
|
616
630
|
type="number"
|
|
617
631
|
:min="1"
|
|
@@ -620,7 +634,7 @@ async function save() {
|
|
|
620
634
|
data-testid="done-lane-retention-days"
|
|
621
635
|
/>
|
|
622
636
|
</label>
|
|
623
|
-
<p class="text-
|
|
637
|
+
<p class="text-2xs text-dimmed">
|
|
624
638
|
{{ t('settings.workspaceSettings.doneLane.hidesOnlyHint') }}
|
|
625
639
|
</p>
|
|
626
640
|
</section>
|
|
@@ -630,7 +644,7 @@ async function save() {
|
|
|
630
644
|
<h3 class="text-sm font-semibold text-default">
|
|
631
645
|
{{ t('settings.workspaceSettings.runCredential.heading') }}
|
|
632
646
|
</h3>
|
|
633
|
-
<p class="text-
|
|
647
|
+
<p class="text-2xs text-muted">
|
|
634
648
|
{{ t('settings.workspaceSettings.runCredential.body') }}
|
|
635
649
|
</p>
|
|
636
650
|
<label class="flex items-center gap-2">
|
|
@@ -643,14 +657,14 @@ async function save() {
|
|
|
643
657
|
t('settings.workspaceSettings.runCredential.toggle')
|
|
644
658
|
}}</span>
|
|
645
659
|
</label>
|
|
646
|
-
<p v-if="!draft.allowInitiatorPat" class="text-
|
|
660
|
+
<p v-if="!draft.allowInitiatorPat" class="text-2xs text-app-warning-300">
|
|
647
661
|
{{ t('settings.workspaceSettings.runCredential.offHint') }}
|
|
648
662
|
</p>
|
|
649
663
|
<!-- Stated rather than read: the account floor lives behind an ACCOUNT-admin
|
|
650
664
|
endpoint, which a workspace admin may not hold, so probing it here would 403
|
|
651
665
|
for exactly the people this note is for. A static line sets the expectation
|
|
652
666
|
without pretending to report a value we cannot see. -->
|
|
653
|
-
<p v-if="draft.allowInitiatorPat" class="text-
|
|
667
|
+
<p v-if="draft.allowInitiatorPat" class="text-2xs text-dimmed">
|
|
654
668
|
{{ t('settings.workspaceSettings.runCredential.accountFloorNote') }}
|
|
655
669
|
</p>
|
|
656
670
|
</section>
|
|
@@ -662,7 +676,7 @@ async function save() {
|
|
|
662
676
|
<h3 class="text-sm font-semibold text-default">
|
|
663
677
|
{{ t('settings.workspaceSettings.bugFishing.heading') }}
|
|
664
678
|
</h3>
|
|
665
|
-
<p class="text-
|
|
679
|
+
<p class="text-2xs text-muted">
|
|
666
680
|
{{ t('settings.workspaceSettings.bugFishing.body') }}
|
|
667
681
|
</p>
|
|
668
682
|
<USelectMenu
|
|
@@ -680,7 +694,7 @@ async function save() {
|
|
|
680
694
|
<h3 class="text-sm font-semibold text-default">
|
|
681
695
|
{{ t('settings.workspaceSettings.kaizen.heading') }}
|
|
682
696
|
</h3>
|
|
683
|
-
<p class="text-
|
|
697
|
+
<p class="text-2xs text-muted">
|
|
684
698
|
{{ t('settings.workspaceSettings.kaizen.body') }}
|
|
685
699
|
</p>
|
|
686
700
|
<label class="flex items-center gap-2">
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { computed, ref } from 'vue'
|
|
18
18
|
import { MAX_REVIEW_SKILLS } from '@cat-factory/contracts'
|
|
19
19
|
import { useSkillsStore } from '~/stores/skills'
|
|
20
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
20
21
|
|
|
21
22
|
const props = defineProps<{
|
|
22
23
|
/** The queued skill ids, in the order the reviewer applies them (`v-model`). */
|
|
@@ -63,9 +64,9 @@ function toggle(id: string) {
|
|
|
63
64
|
<template>
|
|
64
65
|
<div>
|
|
65
66
|
<div class="mb-1 flex items-center justify-between gap-2">
|
|
66
|
-
<
|
|
67
|
+
<SectionLabel as="span">
|
|
67
68
|
{{ t('skills.reviewQueue.label') }}
|
|
68
|
-
</
|
|
69
|
+
</SectionLabel>
|
|
69
70
|
<UPopover v-model:open="open" :content="{ align: 'end' }">
|
|
70
71
|
<UButton
|
|
71
72
|
size="xs"
|
|
@@ -83,11 +84,12 @@ function toggle(id: string) {
|
|
|
83
84
|
>
|
|
84
85
|
<div class="min-h-0 flex-1 overflow-y-auto p-1">
|
|
85
86
|
<template v-if="offered.length">
|
|
86
|
-
<
|
|
87
|
+
<UButton
|
|
88
|
+
color="neutral"
|
|
89
|
+
variant="ghost"
|
|
87
90
|
v-for="s in offered"
|
|
88
91
|
:key="s.id"
|
|
89
|
-
|
|
90
|
-
class="flex w-full items-start gap-2 rounded px-2 py-1.5 text-start text-sm hover:bg-elevated/60 disabled:cursor-not-allowed disabled:opacity-40"
|
|
92
|
+
class="flex w-full items-start gap-2 rounded-sm px-2 py-1.5 text-start text-sm hover:bg-elevated/60 disabled:cursor-not-allowed disabled:opacity-40"
|
|
91
93
|
:class="selectedSet.has(s.id) ? 'text-app-100' : 'text-toned'"
|
|
92
94
|
:disabled="atCap && !selectedSet.has(s.id)"
|
|
93
95
|
:aria-pressed="selectedSet.has(s.id)"
|
|
@@ -101,20 +103,20 @@ function toggle(id: string) {
|
|
|
101
103
|
/>
|
|
102
104
|
<span class="min-w-0 flex-1">
|
|
103
105
|
<span class="block truncate">{{ s.name }}</span>
|
|
104
|
-
<span class="block truncate text-
|
|
106
|
+
<span class="block truncate text-2xs text-dimmed">
|
|
105
107
|
{{ s.description }}
|
|
106
108
|
</span>
|
|
107
109
|
</span>
|
|
108
|
-
</
|
|
110
|
+
</UButton>
|
|
109
111
|
</template>
|
|
110
|
-
<p v-else class="px-2 py-3 text-
|
|
112
|
+
<p v-else class="px-2 py-3 text-xs text-dimmed">
|
|
111
113
|
{{ t('skills.reviewQueue.pickerEmpty') }}
|
|
112
114
|
</p>
|
|
113
115
|
</div>
|
|
114
116
|
|
|
115
117
|
<p
|
|
116
118
|
v-if="atCap"
|
|
117
|
-
class="border-t border-default px-2 py-1.5 text-
|
|
119
|
+
class="border-t border-default px-2 py-1.5 text-2xs text-app-warning-400"
|
|
118
120
|
>
|
|
119
121
|
{{ t('skills.reviewQueue.capped', { max: MAX_REVIEW_SKILLS }) }}
|
|
120
122
|
</p>
|
|
@@ -149,7 +151,7 @@ function toggle(id: string) {
|
|
|
149
151
|
{{ s.name }}<UIcon name="i-lucide-x" class="ms-0.5 h-3 w-3" />
|
|
150
152
|
</UBadge>
|
|
151
153
|
</div>
|
|
152
|
-
<p v-else class="text-
|
|
154
|
+
<p v-else class="text-2xs text-dimmed">
|
|
153
155
|
{{ t('skills.reviewQueue.hint') }}
|
|
154
156
|
</p>
|
|
155
157
|
</div>
|
|
@@ -12,6 +12,7 @@ import { useSkillLibrary } from '~/stores/skillLibrary'
|
|
|
12
12
|
import { SKILL_GROUP_LABEL_KEYS } from '~/utils/skills'
|
|
13
13
|
import GitHubRepoSearchSelect from '~/components/github/GitHubRepoSearchSelect.vue'
|
|
14
14
|
import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
|
|
15
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
15
16
|
|
|
16
17
|
const props = defineProps<{ accountId: string }>()
|
|
17
18
|
|
|
@@ -181,10 +182,10 @@ async function unlinkSource(id: string) {
|
|
|
181
182
|
<!-- The manifest declared a group this build does not know (a typo, or a member
|
|
182
183
|
retired since the sync). It is filed under Other, and saying which value was
|
|
183
184
|
declared is what lets the author fix their frontmatter. -->
|
|
184
|
-
<p v-if="s.declaredGroup" class="mt-1 text-
|
|
185
|
+
<p v-if="s.declaredGroup" class="mt-1 text-2xs text-app-warning-400">
|
|
185
186
|
{{ t('skills.catalog.groupUnknown', { group: s.declaredGroup }) }}
|
|
186
187
|
</p>
|
|
187
|
-
<p class="mt-1 flex flex-wrap gap-x-3 text-
|
|
188
|
+
<p class="mt-1 flex flex-wrap gap-x-3 text-2xs text-dimmed">
|
|
188
189
|
<span v-if="s.resources.length">
|
|
189
190
|
{{ t('skills.catalog.resources', { count: s.resources.length }) }}
|
|
190
191
|
</span>
|
|
@@ -234,29 +235,29 @@ async function unlinkSource(id: string) {
|
|
|
234
235
|
{{ t('skills.sources.changes') }}
|
|
235
236
|
</UBadge>
|
|
236
237
|
<div class="ms-auto flex gap-1">
|
|
237
|
-
<
|
|
238
|
+
<IconButton
|
|
238
239
|
icon="i-lucide-search-check"
|
|
239
240
|
size="xs"
|
|
240
241
|
variant="ghost"
|
|
241
242
|
:loading="rowBusy(`check:${s.id}`)"
|
|
242
|
-
:
|
|
243
|
+
:label="t('skills.sources.check')"
|
|
243
244
|
@click="checkSource(s.id)"
|
|
244
245
|
/>
|
|
245
|
-
<
|
|
246
|
+
<IconButton
|
|
246
247
|
icon="i-lucide-refresh-cw"
|
|
247
248
|
size="xs"
|
|
248
249
|
variant="ghost"
|
|
249
250
|
:loading="rowBusy(`sync:${s.id}`)"
|
|
250
|
-
:
|
|
251
|
+
:label="t('skills.sources.sync')"
|
|
251
252
|
@click="syncSource(s.id)"
|
|
252
253
|
/>
|
|
253
|
-
<
|
|
254
|
+
<IconButton
|
|
254
255
|
icon="i-lucide-unplug"
|
|
255
256
|
size="xs"
|
|
256
257
|
color="error"
|
|
257
258
|
variant="ghost"
|
|
258
259
|
:loading="rowBusy(`unlink:${s.id}`)"
|
|
259
|
-
:
|
|
260
|
+
:label="t('skills.sources.unlink')"
|
|
260
261
|
@click="unlinkSource(s.id)"
|
|
261
262
|
/>
|
|
262
263
|
</div>
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '~/utils/slackMemberMapping'
|
|
17
17
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
18
18
|
import SecretInput from '~/components/common/SecretInput.vue'
|
|
19
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
19
20
|
|
|
20
21
|
const ui = useUiStore()
|
|
21
22
|
const slack = useSlackStore()
|
|
@@ -55,6 +56,8 @@ const ROLE_OPTIONS = computed<{ label: string; value: SlackMemberRole }[]>(() =>
|
|
|
55
56
|
])
|
|
56
57
|
|
|
57
58
|
// Local editable copies, synced from the store on load.
|
|
59
|
+
const channelSuggestions = computed(() => slack.channels.map((ch) => `#${ch.name}`))
|
|
60
|
+
|
|
58
61
|
const routes = reactive<Record<NotificationType, SlackRoute>>({
|
|
59
62
|
merge_review: { enabled: false, channel: '' },
|
|
60
63
|
pipeline_complete: { enabled: false, channel: '' },
|
|
@@ -224,9 +227,9 @@ async function saveMapping() {
|
|
|
224
227
|
{{ t('slack.connect.addToSlack') }}
|
|
225
228
|
</UButton>
|
|
226
229
|
<div class="space-y-1">
|
|
227
|
-
<span class="block
|
|
230
|
+
<SectionLabel as="span" class="block">
|
|
228
231
|
{{ t('slack.connect.orPasteToken') }}
|
|
229
|
-
</
|
|
232
|
+
</SectionLabel>
|
|
230
233
|
<div class="flex gap-2">
|
|
231
234
|
<SecretInput v-model="tokenInput" size="sm" class="flex-1" placeholder="xoxb-…" />
|
|
232
235
|
<UButton
|
|
@@ -267,9 +270,9 @@ async function saveMapping() {
|
|
|
267
270
|
|
|
268
271
|
<!-- routing -->
|
|
269
272
|
<div class="space-y-3">
|
|
270
|
-
<
|
|
273
|
+
<SectionLabel as="p">
|
|
271
274
|
{{ t('slack.routing.heading') }}
|
|
272
|
-
</
|
|
275
|
+
</SectionLabel>
|
|
273
276
|
<div
|
|
274
277
|
v-for="row in ROUTABLE"
|
|
275
278
|
:key="row.type"
|
|
@@ -277,18 +280,20 @@ async function saveMapping() {
|
|
|
277
280
|
>
|
|
278
281
|
<USwitch v-model="routes[row.type]!.enabled" size="sm" />
|
|
279
282
|
<span class="w-32 text-sm text-toned">{{ row.label }}</span>
|
|
280
|
-
|
|
283
|
+
<!-- The workspace's channels are suggestions, not a closed list: a route may name
|
|
284
|
+
a channel the bot cannot enumerate yet. `mode="autocomplete"` is what makes the
|
|
285
|
+
typed name the value: the DEFAULT combobox mode writes its model only when
|
|
286
|
+
something is SELECTED, so a channel typed and then saved would be dropped. -->
|
|
287
|
+
<UInputMenu
|
|
281
288
|
v-model="routes[row.type]!.channel"
|
|
289
|
+
mode="autocomplete"
|
|
290
|
+
:items="channelSuggestions"
|
|
282
291
|
size="sm"
|
|
283
292
|
class="flex-1"
|
|
284
293
|
:placeholder="t('slack.routing.channelPlaceholder')"
|
|
285
294
|
:disabled="!routes[row.type]!.enabled"
|
|
286
|
-
list="slack-channels"
|
|
287
295
|
/>
|
|
288
296
|
</div>
|
|
289
|
-
<datalist id="slack-channels">
|
|
290
|
-
<option v-for="ch in slack.channels" :key="ch.id" :value="`#${ch.name}`" />
|
|
291
|
-
</datalist>
|
|
292
297
|
|
|
293
298
|
<label class="flex items-center gap-2">
|
|
294
299
|
<USwitch v-model="mentionsEnabled" size="sm" />
|
|
@@ -311,10 +316,10 @@ async function saveMapping() {
|
|
|
311
316
|
|
|
312
317
|
<!-- member mapping -->
|
|
313
318
|
<div v-if="mentionsEnabled" class="space-y-2">
|
|
314
|
-
<
|
|
319
|
+
<SectionLabel as="p">
|
|
315
320
|
{{ t('slack.members.heading') }}
|
|
316
|
-
</
|
|
317
|
-
<p class="text-
|
|
321
|
+
</SectionLabel>
|
|
322
|
+
<p class="text-2xs leading-snug text-dimmed">
|
|
318
323
|
<i18n-t keypath="slack.members.hint" tag="span">
|
|
319
324
|
<template #product>
|
|
320
325
|
<span class="font-medium text-muted">{{ t('slack.members.productLabel') }}</span>
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type RequirementStateFilter,
|
|
23
23
|
} from './ServiceSpecWindow.logic'
|
|
24
24
|
import type { BadgeColor } from '~/utils/badge'
|
|
25
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
25
26
|
|
|
26
27
|
const { t } = useI18n()
|
|
27
28
|
const board = useBoardStore()
|
|
@@ -285,14 +286,15 @@ function kindLabel(item: RequirementItem): string {
|
|
|
285
286
|
{{ t('spec.overview') }}
|
|
286
287
|
</UButton>
|
|
287
288
|
<div v-for="(mod, mi) in modules" :key="mi" class="mb-3">
|
|
288
|
-
<
|
|
289
|
+
<SectionLabel class="px-2 pb-1">
|
|
289
290
|
{{ mod.name }}
|
|
290
|
-
</
|
|
291
|
+
</SectionLabel>
|
|
291
292
|
<ul class="space-y-0.5">
|
|
292
293
|
<li v-for="(group, gi) in mod.groups ?? []" :key="gi">
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
<UButton
|
|
295
|
+
color="neutral"
|
|
296
|
+
variant="ghost"
|
|
297
|
+
class="flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-start text-sm transition"
|
|
296
298
|
:class="
|
|
297
299
|
selected?.m === mi && selected?.g === gi
|
|
298
300
|
? 'bg-primary/15 text-primary'
|
|
@@ -301,12 +303,12 @@ function kindLabel(item: RequirementItem): string {
|
|
|
301
303
|
@click="selectGroup(mi, gi)"
|
|
302
304
|
>
|
|
303
305
|
<span class="truncate">{{ group.name }}</span>
|
|
304
|
-
<span class="shrink-0 text-
|
|
305
|
-
</
|
|
306
|
+
<span class="shrink-0 text-3xs text-dimmed">{{ reqCount(group) }}</span>
|
|
307
|
+
</UButton>
|
|
306
308
|
</li>
|
|
307
309
|
<li
|
|
308
310
|
v-if="(mod.groups?.length ?? 0) === 0"
|
|
309
|
-
class="px-2 py-1 text-
|
|
311
|
+
class="px-2 py-1 text-2xs italic text-app-600"
|
|
310
312
|
>
|
|
311
313
|
{{ t('spec.noFeatureGroups') }}
|
|
312
314
|
</li>
|
|
@@ -352,9 +354,9 @@ function kindLabel(item: RequirementItem): string {
|
|
|
352
354
|
|
|
353
355
|
<!-- selected feature group -->
|
|
354
356
|
<template v-else-if="selectedGroup">
|
|
355
|
-
<
|
|
357
|
+
<SectionLabel class="mb-1">
|
|
356
358
|
{{ selectedModule?.name }}
|
|
357
|
-
</
|
|
359
|
+
</SectionLabel>
|
|
358
360
|
<h2 class="text-lg font-semibold text-highlighted">{{ selectedGroup.name }}</h2>
|
|
359
361
|
<p v-if="selectedGroup.summary" class="mt-1 max-w-3xl text-sm text-muted">
|
|
360
362
|
{{ selectedGroup.summary }}
|
|
@@ -364,7 +366,7 @@ function kindLabel(item: RequirementItem): string {
|
|
|
364
366
|
<template v-if="mode === 'gherkin'">
|
|
365
367
|
<pre
|
|
366
368
|
v-if="selectedFeature"
|
|
367
|
-
class="mt-4 overflow-x-auto rounded-lg border border-default bg-app-950/60 p-4 text-
|
|
369
|
+
class="mt-4 overflow-x-auto rounded-lg border border-default bg-app-950/60 p-4 text-xs leading-relaxed text-default"
|
|
368
370
|
><code>{{ selectedFeature.content }}</code></pre>
|
|
369
371
|
<div
|
|
370
372
|
v-else
|
|
@@ -385,7 +387,7 @@ function kindLabel(item: RequirementItem): string {
|
|
|
385
387
|
class="mt-4 flex flex-wrap items-center justify-between gap-2"
|
|
386
388
|
data-testid="spec-state-filter"
|
|
387
389
|
>
|
|
388
|
-
<div class="flex items-center gap-1.5 text-
|
|
390
|
+
<div class="flex items-center gap-1.5 text-2xs text-dimmed">
|
|
389
391
|
<UIcon
|
|
390
392
|
:name="STATE_META.established.icon"
|
|
391
393
|
class="h-3.5 w-3.5 text-app-success-400"
|
|
@@ -466,7 +468,7 @@ function kindLabel(item: RequirementItem): string {
|
|
|
466
468
|
<UBadge color="neutral" variant="subtle" size="sm">{{ kindLabel(req) }}</UBadge>
|
|
467
469
|
</div>
|
|
468
470
|
</div>
|
|
469
|
-
<p class="mt-1.5 whitespace-pre-line text-
|
|
471
|
+
<p class="mt-1.5 whitespace-pre-line text-sm leading-relaxed text-toned">
|
|
470
472
|
{{ req.statement }}
|
|
471
473
|
</p>
|
|
472
474
|
<!-- acceptance criteria (Given/When/Then) -->
|
|
@@ -474,7 +476,7 @@ function kindLabel(item: RequirementItem): string {
|
|
|
474
476
|
<div
|
|
475
477
|
v-for="ac in req.acceptance ?? []"
|
|
476
478
|
:key="ac.id"
|
|
477
|
-
class="rounded-md border border-default bg-app-950/50 px-3 py-2 text-
|
|
479
|
+
class="rounded-md border border-default bg-app-950/50 px-3 py-2 text-xs leading-relaxed"
|
|
478
480
|
>
|
|
479
481
|
<p class="text-toned">
|
|
480
482
|
<span class="font-semibold text-app-success-400">{{
|
|
@@ -501,17 +503,15 @@ function kindLabel(item: RequirementItem): string {
|
|
|
501
503
|
|
|
502
504
|
<!-- domain rules / invariants scoped to this group -->
|
|
503
505
|
<div v-if="(selectedGroup.rules?.length ?? 0) > 0" class="mt-6">
|
|
504
|
-
<
|
|
505
|
-
class="mb-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted"
|
|
506
|
-
>
|
|
506
|
+
<SectionLabel class="mb-2 flex items-center gap-1.5">
|
|
507
507
|
<UIcon name="i-lucide-shield-check" class="h-3.5 w-3.5" />
|
|
508
508
|
{{ t('spec.domainRules') }}
|
|
509
|
-
</
|
|
509
|
+
</SectionLabel>
|
|
510
510
|
<ul class="max-w-3xl space-y-1.5">
|
|
511
511
|
<li
|
|
512
512
|
v-for="rule in selectedGroup.rules ?? []"
|
|
513
513
|
:key="rule.id"
|
|
514
|
-
class="rounded-md border border-default bg-default/60 px-3 py-2 text-
|
|
514
|
+
class="rounded-md border border-default bg-default/60 px-3 py-2 text-sm text-toned"
|
|
515
515
|
>
|
|
516
516
|
{{ rule.rule }}
|
|
517
517
|
<span v-if="rule.rationale" class="text-dimmed">{{
|